Continuing with the large refactoring of EventHandler:

- all keyboard-related stuff moved into PhysicalKeyboardHandler class
- all snapshot-related stuff moved directly into PNGLibrary class
- EventHandler class is now ~1300 LOC, which while still large, is much better than 2500 LOC
This commit is contained in:
Stephen Anthony 2018-03-24 12:36:00 -02:30
parent 08ac6b0ff9
commit 0908a92da1
13 changed files with 984 additions and 779 deletions

View File

@ -44,13 +44,6 @@ class EventHandlerSDL2 : public EventHandler
*/
void enableTextEvents(bool enable) override;
/**
Returns the human-readable name for a StellaKey.
*/
const char* const nameForKey(StellaKey key) const override {
return SDL_GetScancodeName(SDL_Scancode(key));
}
/**
Collects and dispatches any pending SDL2 events.
*/

View File

@ -609,7 +609,7 @@ void PhysicalJoystickHandler::handleBtnEvent(int stick, int button, uInt8 state)
{
case PhysicalJoystick::JT_REGULAR:
// Handle buttons which switch eventhandler state
if(state && myHandler.eventStateChange(j->btnTable[button][kEmulationMode]))
if(state && myHandler.changeStateByEvent(j->btnTable[button][kEmulationMode]))
return;
// Determine which mode we're in, then send the event to the appropriate place

View File

@ -0,0 +1,613 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "OSystem.hxx"
#include "Console.hxx"
#include "Settings.hxx"
#include "EventHandler.hxx"
#include "Event.hxx"
#include "Sound.hxx"
#include "StateManager.hxx"
#include "StellaKeys.hxx"
#include "TIASurface.hxx"
#include "PNGLibrary.hxx"
#include "PKeyboardHandler.hxx"
#ifdef DEBUGGER_SUPPORT
#include "Debugger.hxx"
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalKeyboardHandler::PhysicalKeyboardHandler(
OSystem& system, EventHandler& handler, Event& event)
: myOSystem(system),
myHandler(handler),
myEvent(event),
myAltKeyCounter(0),
myUseCtrlKeyFlag(myOSystem.settings().getBool("ctrlcombo"))
{
// Since istringstream swallows whitespace, we have to make the
// delimiters be spaces
string list = myOSystem.settings().getString("keymap");
replace(list.begin(), list.end(), ':', ' ');
istringstream buf(list);
IntArray map;
int value;
Event::Type e;
// Get event count, which should be the first int in the list
buf >> value;
e = Event::Type(value);
if(e == Event::LastType)
while(buf >> value)
map.push_back(value);
// Only fill the key mapping array if the data is valid
if(e == Event::LastType && map.size() == KBDK_LAST * kNumModes)
{
// Fill the keymap table with events
auto ev = map.cbegin();
for(int mode = 0; mode < kNumModes; ++mode)
for(int i = 0; i < KBDK_LAST; ++i)
myKeyTable[i][mode] = Event::Type(*ev++);
}
else
{
setDefaultMapping(Event::NoType, kEmulationMode);
setDefaultMapping(Event::NoType, kMenuMode);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalKeyboardHandler::setDefaultMapping(Event::Type event, EventMode mode)
{
// If event is 'NoType', erase and reset all mappings
// Otherwise, only reset the given event
bool eraseAll = (event == Event::NoType);
if(eraseAll)
{
// Erase all mappings
for(int i = 0; i < KBDK_LAST; ++i)
myKeyTable[i][mode] = Event::NoType;
}
auto setDefaultKey = [&](StellaKey key, Event::Type k_event)
{
if(eraseAll || k_event == event)
myKeyTable[key][mode] = k_event;
};
switch(mode)
{
case kEmulationMode:
setDefaultKey( KBDK_1, Event::KeyboardZero1 );
setDefaultKey( KBDK_2, Event::KeyboardZero2 );
setDefaultKey( KBDK_3, Event::KeyboardZero3 );
setDefaultKey( KBDK_Q, Event::KeyboardZero4 );
setDefaultKey( KBDK_W, Event::KeyboardZero5 );
setDefaultKey( KBDK_E, Event::KeyboardZero6 );
setDefaultKey( KBDK_A, Event::KeyboardZero7 );
setDefaultKey( KBDK_S, Event::KeyboardZero8 );
setDefaultKey( KBDK_D, Event::KeyboardZero9 );
setDefaultKey( KBDK_Z, Event::KeyboardZeroStar );
setDefaultKey( KBDK_X, Event::KeyboardZero0 );
setDefaultKey( KBDK_C, Event::KeyboardZeroPound );
setDefaultKey( KBDK_8, Event::KeyboardOne1 );
setDefaultKey( KBDK_9, Event::KeyboardOne2 );
setDefaultKey( KBDK_0, Event::KeyboardOne3 );
setDefaultKey( KBDK_I, Event::KeyboardOne4 );
setDefaultKey( KBDK_O, Event::KeyboardOne5 );
setDefaultKey( KBDK_P, Event::KeyboardOne6 );
setDefaultKey( KBDK_K, Event::KeyboardOne7 );
setDefaultKey( KBDK_L, Event::KeyboardOne8 );
setDefaultKey( KBDK_SEMICOLON, Event::KeyboardOne9 );
setDefaultKey( KBDK_COMMA, Event::KeyboardOneStar );
setDefaultKey( KBDK_PERIOD, Event::KeyboardOne0 );
setDefaultKey( KBDK_SLASH, Event::KeyboardOnePound );
setDefaultKey( KBDK_UP, Event::JoystickZeroUp );
setDefaultKey( KBDK_DOWN, Event::JoystickZeroDown );
setDefaultKey( KBDK_LEFT, Event::JoystickZeroLeft );
setDefaultKey( KBDK_RIGHT, Event::JoystickZeroRight );
setDefaultKey( KBDK_SPACE, Event::JoystickZeroFire );
setDefaultKey( KBDK_LCTRL, Event::JoystickZeroFire );
setDefaultKey( KBDK_4, Event::JoystickZeroFire5 );
setDefaultKey( KBDK_5, Event::JoystickZeroFire9 );
setDefaultKey( KBDK_Y, Event::JoystickOneUp );
setDefaultKey( KBDK_H, Event::JoystickOneDown );
setDefaultKey( KBDK_G, Event::JoystickOneLeft );
setDefaultKey( KBDK_J, Event::JoystickOneRight );
setDefaultKey( KBDK_F, Event::JoystickOneFire );
setDefaultKey( KBDK_6, Event::JoystickOneFire5 );
setDefaultKey( KBDK_7, Event::JoystickOneFire9 );
setDefaultKey( KBDK_F1, Event::ConsoleSelect );
setDefaultKey( KBDK_F2, Event::ConsoleReset );
setDefaultKey( KBDK_F3, Event::ConsoleColor );
setDefaultKey( KBDK_F4, Event::ConsoleBlackWhite );
setDefaultKey( KBDK_F5, Event::ConsoleLeftDiffA );
setDefaultKey( KBDK_F6, Event::ConsoleLeftDiffB );
setDefaultKey( KBDK_F7, Event::ConsoleRightDiffA );
setDefaultKey( KBDK_F8, Event::ConsoleRightDiffB );
setDefaultKey( KBDK_F9, Event::SaveState );
setDefaultKey( KBDK_F10, Event::ChangeState );
setDefaultKey( KBDK_F11, Event::LoadState );
setDefaultKey( KBDK_F12, Event::TakeSnapshot );
setDefaultKey( KBDK_BACKSPACE, Event::Fry );
setDefaultKey( KBDK_PAUSE, Event::PauseMode );
setDefaultKey( KBDK_TAB, Event::OptionsMenuMode );
setDefaultKey( KBDK_BACKSLASH, Event::CmdMenuMode );
setDefaultKey( KBDK_T, Event::TimeMachineMode );
setDefaultKey( KBDK_GRAVE, Event::DebuggerMode );
setDefaultKey( KBDK_ESCAPE, Event::LauncherMode );
break;
case kMenuMode:
setDefaultKey( KBDK_UP, Event::UIUp );
setDefaultKey( KBDK_DOWN, Event::UIDown );
setDefaultKey( KBDK_LEFT, Event::UILeft );
setDefaultKey( KBDK_RIGHT, Event::UIRight );
setDefaultKey( KBDK_HOME, Event::UIHome );
setDefaultKey( KBDK_END, Event::UIEnd );
setDefaultKey( KBDK_PAGEUP, Event::UIPgUp );
setDefaultKey( KBDK_PAGEDOWN, Event::UIPgDown );
setDefaultKey( KBDK_RETURN, Event::UISelect );
setDefaultKey( KBDK_ESCAPE, Event::UICancel );
setDefaultKey( KBDK_BACKSPACE, Event::UIPrevDir );
break;
default:
return;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalKeyboardHandler::eraseMapping(Event::Type event, EventMode mode)
{
for(int i = 0; i < KBDK_LAST; ++i)
if(myKeyTable[i][mode] == event && i != KBDK_TAB)
myKeyTable[i][mode] = Event::NoType;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalKeyboardHandler::saveMapping()
{
// Iterate through the keymap table and create a colon-separated list
// Prepend the event count, so we can check it on next load
ostringstream keybuf;
keybuf << Event::LastType;
for(int mode = 0; mode < kNumModes; ++mode)
for(int i = 0; i < KBDK_LAST; ++i)
keybuf << ":" << myKeyTable[i][mode];
myOSystem.settings().setValue("keymap", keybuf.str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string PhysicalKeyboardHandler::getMappingDesc(Event::Type event, EventMode mode) const
{
ostringstream buf;
for(int k = 0; k < KBDK_LAST; ++k)
{
if(myKeyTable[k][mode] == event)
{
if(buf.str() != "")
buf << ", ";
buf << StellaKeyName::forKey(StellaKey(k));
}
}
return buf.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalKeyboardHandler::addMapping(Event::Type event, EventMode mode,
StellaKey key)
{
// These keys cannot be remapped
if(key == KBDK_TAB || Event::isAnalog(event))
return false;
else
myKeyTable[key][mode] = event;
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalKeyboardHandler::handleEvent(StellaKey key, StellaMod mod, bool state)
{
// Swallow KBDK_TAB under certain conditions
// See commments on 'myAltKeyCounter' for more information
#ifdef BSPF_UNIX
if(myAltKeyCounter > 1 && key == KBDK_TAB)
{
myAltKeyCounter = 0;
return;
}
#endif
bool handled = true;
EventHandlerState estate = myHandler.state();
// Immediately store the key state
myEvent.setKey(key, state);
// An attempt to speed up event processing; we quickly check for
// Control or Alt/Cmd combos first
if(StellaModTest::isAlt(mod) && state)
{
#ifdef BSPF_MAC_OSX
// These keys work in all states
if(key == KBDK_Q)
{
myHandler.handleEvent(Event::Quit, 1);
}
else
#endif
if(key == KBDK_TAB)
{
// Swallow Alt-Tab, but remember that it happened
myAltKeyCounter = 1;
return;
}
else if(key == KBDK_RETURN)
{
myOSystem.frameBuffer().toggleFullscreen();
}
// State rewinding must work in pause mode too
else if(estate == EventHandlerState::EMULATION || estate == EventHandlerState::PAUSE)
{
switch(key)
{
case KBDK_LEFT: // Alt-left(-shift) rewinds 1(10) states
myHandler.enterTimeMachineMenuMode((StellaModTest::isShift(mod) && state) ? 10 : 1, false);
break;
case KBDK_RIGHT: // Alt-right(-shift) unwinds 1(10) states
myHandler.enterTimeMachineMenuMode((StellaModTest::isShift(mod) && state) ? 10 : 1, true);
break;
case KBDK_DOWN: // Alt-down rewinds to start of list
myHandler.enterTimeMachineMenuMode(1000, false);
break;
case KBDK_UP: // Alt-up rewinds to end of list
myHandler.enterTimeMachineMenuMode(1000, true);
break;
// These can work in pause mode too
case KBDK_EQUALS:
myOSystem.frameBuffer().changeWindowedVidMode(+1);
break;
case KBDK_MINUS:
myOSystem.frameBuffer().changeWindowedVidMode(-1);
break;
case KBDK_LEFTBRACKET:
myOSystem.sound().adjustVolume(-1);
break;
case KBDK_RIGHTBRACKET:
myOSystem.sound().adjustVolume(+1);
break;
case KBDK_PAGEUP: // Alt-PageUp increases YStart
myOSystem.console().changeYStart(+1);
break;
case KBDK_PAGEDOWN: // Alt-PageDown decreases YStart
myOSystem.console().changeYStart(-1);
break;
case KBDK_1: // Alt-1 turns off NTSC filtering
myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_OFF);
break;
case KBDK_2: // Alt-2 turns on 'composite' NTSC filtering
myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_COMPOSITE);
break;
case KBDK_3: // Alt-3 turns on 'svideo' NTSC filtering
myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_SVIDEO);
break;
case KBDK_4: // Alt-4 turns on 'rgb' NTSC filtering
myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_RGB);
break;
case KBDK_5: // Alt-5 turns on 'bad' NTSC filtering
myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_BAD);
break;
case KBDK_6: // Alt-6 turns on 'custom' NTSC filtering
myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_CUSTOM);
break;
case KBDK_7: // Alt-7 changes scanline intensity for NTSC filtering
if(StellaModTest::isShift(mod))
myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-5);
else
myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+5);
break;
case KBDK_8: // Alt-8 turns toggles scanline interpolation
myOSystem.frameBuffer().tiaSurface().toggleScanlineInterpolation();
break;
case KBDK_9: // Alt-9 selects various custom adjustables for NTSC filtering
if(myOSystem.frameBuffer().tiaSurface().ntscEnabled())
{
if(StellaModTest::isShift(mod))
myOSystem.frameBuffer().showMessage(
myOSystem.frameBuffer().tiaSurface().ntsc().setPreviousAdjustable());
else
myOSystem.frameBuffer().showMessage(
myOSystem.frameBuffer().tiaSurface().ntsc().setNextAdjustable());
}
break;
case KBDK_0: // Alt-0 changes custom adjustables for NTSC filtering
if(myOSystem.frameBuffer().tiaSurface().ntscEnabled())
{
if(StellaModTest::isShift(mod))
myOSystem.frameBuffer().showMessage(
myOSystem.frameBuffer().tiaSurface().ntsc().decreaseAdjustable());
else
myOSystem.frameBuffer().showMessage(
myOSystem.frameBuffer().tiaSurface().ntsc().increaseAdjustable());
}
break;
case KBDK_Z:
if(StellaModTest::isShift(mod))
myOSystem.console().toggleP0Collision();
else
myOSystem.console().toggleP0Bit();
break;
case KBDK_X:
if(StellaModTest::isShift(mod))
myOSystem.console().toggleP1Collision();
else
myOSystem.console().toggleP1Bit();
break;
case KBDK_C:
if(StellaModTest::isShift(mod))
myOSystem.console().toggleM0Collision();
else
myOSystem.console().toggleM0Bit();
break;
case KBDK_V:
if(StellaModTest::isShift(mod))
myOSystem.console().toggleM1Collision();
else
myOSystem.console().toggleM1Bit();
break;
case KBDK_B:
if(StellaModTest::isShift(mod))
myOSystem.console().toggleBLCollision();
else
myOSystem.console().toggleBLBit();
break;
case KBDK_N:
if(StellaModTest::isShift(mod))
myOSystem.console().togglePFCollision();
else
myOSystem.console().togglePFBit();
break;
case KBDK_COMMA:
myOSystem.console().toggleFixedColors();
break;
case KBDK_PERIOD:
if(StellaModTest::isShift(mod))
myOSystem.console().toggleCollisions();
else
myOSystem.console().toggleBits();
break;
case KBDK_I: // Alt-i decreases phosphor blend
myOSystem.console().changePhosphor(-1);
break;
case KBDK_O: // Alt-o increases phosphor blend
myOSystem.console().changePhosphor(+1);
break;
case KBDK_P: // Alt-p toggles phosphor effect
myOSystem.console().togglePhosphor();
break;
case KBDK_J: // Alt-j toggles scanline jitter
myOSystem.console().toggleJitter();
break;
case KBDK_L:
myOSystem.frameBuffer().toggleFrameStats();
break;
case KBDK_T: // Alt-t toggles Time Machine
myOSystem.state().toggleTimeMachine();
break;
case KBDK_S:
myOSystem.png().toggleContinuousSnapshots(StellaModTest::isShift(mod));
break;
default:
handled = false;
break;
}
}
else
handled = false;
}
else if(StellaModTest::isControl(mod) && state && myUseCtrlKeyFlag)
{
// These keys work in all states
if(key == KBDK_Q)
{
myHandler.handleEvent(Event::Quit, 1);
}
// These only work when in emulation mode
else if(estate == EventHandlerState::EMULATION || estate == EventHandlerState::PAUSE)
{
switch(key)
{
case KBDK_0: // Ctrl-0 switches between mouse control modes
myHandler.handleMouseControl();
break;
case KBDK_1: // Ctrl-1 swaps Stelladaptor/2600-daptor ports
myHandler.toggleSAPortOrder();
break;
case KBDK_F: // (Shift) Ctrl-f toggles NTSC/PAL/SECAM mode
myOSystem.console().toggleFormat(StellaModTest::isShift(mod) ? -1 : 1);
break;
case KBDK_G: // Ctrl-g (un)grabs mouse
if(!myOSystem.frameBuffer().fullScreen())
{
myOSystem.frameBuffer().toggleGrabMouse();
myOSystem.frameBuffer().showMessage(myOSystem.frameBuffer().grabMouseEnabled()
? "Grab mouse enabled" : "Grab mouse disabled");
}
break;
case KBDK_L: // Ctrl-l toggles PAL color-loss effect
myOSystem.console().toggleColorLoss();
break;
case KBDK_P: // Ctrl-p toggles different palettes
myOSystem.console().togglePalette();
break;
case KBDK_R: // Ctrl-r reloads the currently loaded ROM
myOSystem.reloadConsole();
break;
case KBDK_PAGEUP: // Ctrl-PageUp increases Height
myOSystem.console().changeHeight(+1);
break;
case KBDK_PAGEDOWN: // Ctrl-PageDown decreases Height
myOSystem.console().changeHeight(-1);
break;
case KBDK_S: // Ctrl-s saves properties to a file
{
string filename = myOSystem.baseDir() +
myOSystem.console().properties().get(Cartridge_Name) + ".pro";
ofstream out(filename);
if(out)
{
out << myOSystem.console().properties();
myOSystem.frameBuffer().showMessage("Properties saved");
}
else
myOSystem.frameBuffer().showMessage("Error saving properties");
break;
}
default:
handled = false;
break;
}
}
else
handled = false;
}
else
handled = false;
// Don't pass the key on if we've already taken care of it
if(handled) return;
// Arrange the logic to take advantage of short-circuit evaluation
if(!(StellaModTest::isControl(mod) || StellaModTest::isShift(mod) || StellaModTest::isAlt(mod)))
{
// Special handling for Escape key
// Basically, exit whichever mode we're currently in
if(state && key == KBDK_ESCAPE)
{
switch(estate)
{
case EventHandlerState::PAUSE:
myHandler.changeStateByEvent(Event::PauseMode);
return;
case EventHandlerState::CMDMENU:
myHandler.changeStateByEvent(Event::CmdMenuMode);
return;
case EventHandlerState::TIMEMACHINE:
myHandler.changeStateByEvent(Event::TimeMachineMode);
return;
#if 0 // FIXME - exits ROM too, when it should just go back to ROM
case EventHandlerState::DEBUGGER:
myHandler.changeStateByEvent(Event::DebuggerMode);
return;
#endif
default:
break;
}
}
// Handle keys which switch eventhandler state
if(!state && myHandler.changeStateByEvent(myKeyTable[key][kEmulationMode]))
return;
}
// Otherwise, let the event handler deal with it
switch(estate)
{
case EventHandlerState::EMULATION:
myHandler.handleEvent(myKeyTable[key][kEmulationMode], state);
break;
case EventHandlerState::PAUSE:
switch(myKeyTable[key][kEmulationMode])
{
case Event::TakeSnapshot:
case Event::DebuggerMode:
myHandler.handleEvent(myKeyTable[key][kEmulationMode], state);
break;
default:
break;
}
break;
default:
if(myHandler.hasOverlay())
myHandler.overlay().handleKeyEvent(key, mod, state);
break;
}
}

View File

@ -0,0 +1,95 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef PHYSICAL_KEYBOARD_HANDLER_HXX
#define PHYSICAL_KEYBOARD_HANDLER_HXX
#include <map>
class OSystem;
class EventHandler;
class Event;
#include "bspf.hxx"
#include "EventHandlerConstants.hxx"
/**
This class handles all physical keyboard-related operations in Stella.
It is responsible for getting/setting events associated with keyboard
actions.
Essentially, this class is an extension of the EventHandler class, but
handling only keyboard-specific functionality.
@author Stephen Anthony
*/
class PhysicalKeyboardHandler
{
public:
PhysicalKeyboardHandler(OSystem& system, EventHandler& handler, Event& event);
void setDefaultMapping(Event::Type type, EventMode mode);
void eraseMapping(Event::Type event, EventMode mode);
void saveMapping();
string getMappingDesc(Event::Type, EventMode mode) const;
/** Bind a physical keyboard event to a virtual event/action. */
bool addMapping(Event::Type event, EventMode mode, StellaKey key);
/** Handle a physical keyboard event. */
void handleEvent(StellaKey key, StellaMod mod, bool state);
Event::Type eventForKey(StellaKey key, EventMode mode) const {
return myKeyTable[key][mode];
}
/** See comments on 'myAltKeyCounter' for more information. */
uInt8& altKeyCount() { return myAltKeyCounter; }
/** See comments on 'myUseCtrlKeyFlag' for more information. */
bool& useCtrlKey() { return myUseCtrlKeyFlag; }
private:
OSystem& myOSystem;
EventHandler& myHandler;
Event& myEvent;
// Array of key events, indexed by StellaKey
Event::Type myKeyTable[KBDK_LAST][kNumModes];
// Sometimes key combos with the Alt key become 'stuck' after the
// window changes state, and we want to ignore that event
// For example, press Alt-Tab and then upon re-entering the window,
// the app receives 'tab'; obviously the 'tab' shouldn't be happening
// So we keep track of the cases that matter (for now, Alt-Tab)
// and swallow the event afterwards
// Basically, the initial event sets the variable to 1, and upon
// returning to the app (ie, receiving EVENT_WINDOW_FOCUS_GAINED),
// the count is updated to 2, but only if it was already updated to 1
// TODO - This may be a bug in SDL, and might be removed in the future
// It only seems to be an issue in Linux
uInt8 myAltKeyCounter;
// Indicates whether the key-combos tied to the Control key are
// being used or not (since Ctrl by default is the fire button,
// pressing it with a movement key could inadvertantly activate
// a Ctrl combo when it isn't wanted)
bool myUseCtrlKeyFlag;
};
#endif

View File

@ -18,14 +18,21 @@
#include <cmath>
#include "bspf.hxx"
#include "OSystem.hxx"
#include "Console.hxx"
#include "FrameBuffer.hxx"
#include "FBSurface.hxx"
#include "Props.hxx"
#include "Settings.hxx"
#include "TIASurface.hxx"
#include "Version.hxx"
#include "PNGLibrary.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PNGLibrary::PNGLibrary(const FrameBuffer& fb)
: myFB(fb)
PNGLibrary::PNGLibrary(OSystem& osystem)
: myOSystem(osystem),
mySnapInterval(0),
mySnapCounter(0)
{
}
@ -121,12 +128,13 @@ void PNGLibrary::saveImage(const string& filename, const VariantList& comments)
if(!out.is_open())
throw runtime_error("ERROR: Couldn't create snapshot file");
const GUI::Rect& rect = myFB.imageRect();
const FrameBuffer& fb = myOSystem.frameBuffer();
const GUI::Rect& rect = fb.imageRect();
png_uint_32 width = rect.width(), height = rect.height();
// Get framebuffer pixel data (we get ABGR format)
unique_ptr<png_byte[]> buffer = make_unique<png_byte[]>(width * height * 4);
myFB.readPixels(buffer.get(), width*4, rect);
fb.readPixels(buffer.get(), width*4, rect);
// Set up pointers into "buffer" byte array
unique_ptr<png_bytep[]> rows = make_unique<png_bytep[]>(height);
@ -227,6 +235,146 @@ done:
throw runtime_error(err_message);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::updateTime(uInt64 time)
{
if(++mySnapCounter % mySnapInterval == 0)
takeSnapshot(uInt32(time) >> 10); // not quite milliseconds, but close enough
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::toggleContinuousSnapshots(bool perFrame)
{
if(mySnapInterval == 0)
{
ostringstream buf;
uInt32 interval = myOSystem.settings().getInt("ssinterval");
if(perFrame)
{
buf << "Enabling snapshots every frame";
interval = 1;
}
else
{
buf << "Enabling snapshots in " << interval << " second intervals";
interval *= uInt32(myOSystem.frameRate());
}
myOSystem.frameBuffer().showMessage(buf.str());
setContinuousSnapInterval(interval);
}
else
{
ostringstream buf;
buf << "Disabling snapshots, generated "
<< (mySnapCounter / mySnapInterval)
<< " files";
myOSystem.frameBuffer().showMessage(buf.str());
setContinuousSnapInterval(0);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::setContinuousSnapInterval(uInt32 interval)
{
mySnapInterval = interval;
mySnapCounter = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::takeSnapshot(uInt32 number)
{
if(!myOSystem.hasConsole())
return;
// Figure out the correct snapshot name
string filename;
bool showmessage = number == 0;
string sspath = myOSystem.snapshotSaveDir() +
(myOSystem.settings().getString("snapname") != "int" ?
myOSystem.romFile().getNameWithExt("")
: myOSystem.console().properties().get(Cartridge_Name));
// Check whether we want multiple snapshots created
if(number > 0)
{
ostringstream buf;
buf << sspath << "_" << std::hex << std::setw(8) << std::setfill('0')
<< number << ".png";
filename = buf.str();
}
else if(!myOSystem.settings().getBool("sssingle"))
{
// Determine if the file already exists, checking each successive filename
// until one doesn't exist
filename = sspath + ".png";
FilesystemNode node(filename);
if(node.exists())
{
ostringstream buf;
for(uInt32 i = 1; ;++i)
{
buf.str("");
buf << sspath << "_" << i << ".png";
FilesystemNode next(buf.str());
if(!next.exists())
break;
}
filename = buf.str();
}
}
else
filename = sspath + ".png";
// Some text fields to add to the PNG snapshot
VariantList comments;
ostringstream version;
version << "Stella " << STELLA_VERSION << " (Build " << STELLA_BUILD << ") ["
<< BSPF::ARCH << "]";
VarList::push_back(comments, "Software", version.str());
VarList::push_back(comments, "ROM Name", myOSystem.console().properties().get(Cartridge_Name));
VarList::push_back(comments, "ROM MD5", myOSystem.console().properties().get(Cartridge_MD5));
VarList::push_back(comments, "TV Effects", myOSystem.frameBuffer().tiaSurface().effectsInfo());
// Now create a PNG snapshot
if(myOSystem.settings().getBool("ss1x"))
{
string message = "Snapshot saved";
try
{
GUI::Rect rect;
const FBSurface& surface = myOSystem.frameBuffer().tiaSurface().baseSurface(rect);
myOSystem.png().saveImage(filename, surface, rect, comments);
}
catch(const runtime_error& e)
{
message = e.what();
}
if(showmessage)
myOSystem.frameBuffer().showMessage(message);
}
else
{
// Make sure we have a 'clean' image, with no onscreen messages
myOSystem.frameBuffer().enableMessages(false);
myOSystem.frameBuffer().tiaSurface().reRender();
string message = "Snapshot saved";
try
{
myOSystem.png().saveImage(filename, comments);
}
catch(const runtime_error& e)
{
message = e.what();
}
// Re-enable old messages
myOSystem.frameBuffer().enableMessages(true);
if(showmessage)
myOSystem.frameBuffer().showMessage(message);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PNGLibrary::allocateStorage(png_uint_32 w, png_uint_32 h)
{
@ -276,12 +424,13 @@ void PNGLibrary::loadImagetoSurface(FBSurface& surface)
uInt8* i_buf = ReadInfo.buffer.get();
uInt32 i_pitch = ReadInfo.pitch;
const FrameBuffer& fb = myOSystem.frameBuffer();
for(uInt32 irow = 0; irow < ih; ++irow, i_buf += i_pitch, s_buf += s_pitch)
{
uInt8* i_ptr = i_buf;
uInt32* s_ptr = s_buf;
for(uInt32 icol = 0; icol < ReadInfo.width; ++icol, i_ptr += 3)
*s_ptr++ = myFB.mapRGB(*i_ptr, *(i_ptr+1), *(i_ptr+2));
*s_ptr++ = fb.mapRGB(*i_ptr, *(i_ptr+1), *(i_ptr+2));
}
}

View File

@ -20,6 +20,7 @@
#include <png.h>
class OSystem;
class FrameBuffer;
class FBSurface;
class Properties;
@ -36,7 +37,7 @@ class Properties;
class PNGLibrary
{
public:
PNGLibrary(const FrameBuffer& fb);
PNGLibrary(OSystem& osystem);
/**
Read a PNG image from the specified file into a FBSurface structure,
@ -82,8 +83,51 @@ class PNGLibrary
const GUI::Rect& rect = GUI::EmptyRect,
const VariantList& comments = EmptyVarList);
/**
Called at regular intervals, and used to determine whether a
continuous snapshot is due to be taken.
@param time The current time in microseconds
*/
void updateTime(uInt64 time);
/**
Answer whether continuous snapshot mode is enabled.
*/
bool continuousSnapEnabled() const { return mySnapInterval > 0; }
/**
Enable/disable continuous snapshot mode.
@param perFrame Toggle snapshots every frame, or that specified by
'ssinterval' setting.
*/
void toggleContinuousSnapshots(bool perFrame);
/**
Set the number of seconds between taking a snapshot in
continuous snapshot mode. Setting an interval of 0 disables
continuous snapshots.
@param interval Interval in seconds between snapshots
*/
void setContinuousSnapInterval(uInt32 interval);
/**
Create a new snapshot based on the name of the ROM, and also
optionally using the number given as a parameter.
@param number Optional number to append to the snapshot name
*/
void takeSnapshot(uInt32 number = 0);
private:
const FrameBuffer& myFB;
// Global OSystem object
OSystem& myOSystem;
// Used for continuous snapshot mode
uInt32 mySnapInterval;
uInt32 mySnapCounter;
// The following data remains between invocations of allocateStorage,
// and is only changed when absolutely necessary.

View File

@ -15,8 +15,8 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef STELLA_JOYSTICK_HXX
#define STELLA_JOYSTICK_HXX
#ifndef PHYSICAL_JOYSTICK_HXX
#define PHYSICAL_JOYSTICK_HXX
#include "Event.hxx"
#include "EventHandlerConstants.hxx"

View File

@ -435,4 +435,12 @@ namespace StellaModTest
}
};
namespace StellaKeyName
{
inline const char* const forKey(StellaKey key)
{
return SDL_GetScancodeName(SDL_Scancode(key));
}
};
#endif /* StellaKeys */

View File

@ -28,6 +28,7 @@
#include "Settings.hxx"
#include "FSNode.hxx"
#include "OSystem.hxx"
#include "PNGLibrary.hxx"
#include "System.hxx"
#ifdef DEBUGGER_SUPPORT
@ -132,7 +133,7 @@ int main(int argc, char* argv[])
{
theOSystem->logMessage("Taking snapshots with 'takesnapshot' ...", 2);
for(int i = 0; i < 30; ++i) theOSystem->frameBuffer().update();
theOSystem->eventHandler().takeSnapshot();
theOSystem->png().takeSnapshot();
return Cleanup();
}

View File

@ -10,6 +10,7 @@ MODULE_OBJS := \
src/common/MouseControl.o \
src/common/PhysicalJoystick.o \
src/common/PJoystickHandler.o \
src/common/PKeyboardHandler.o \
src/common/PNGLibrary.o \
src/common/RewindManager.o \
src/common/SoundSDL2.o \

View File

@ -26,7 +26,6 @@
#include "DialogContainer.hxx"
#include "Event.hxx"
#include "FrameBuffer.hxx"
#include "TIASurface.hxx"
#include "FSNode.hxx"
#include "Launcher.hxx"
#include "TimeMachine.hxx"
@ -46,7 +45,6 @@
#include "M6532.hxx"
#include "MouseControl.hxx"
#include "PNGLibrary.hxx"
#include "Version.hxx"
#include "EventHandler.hxx"
@ -65,25 +63,19 @@ EventHandler::EventHandler(OSystem& osystem)
myState(EventHandlerState::NONE),
myAllowAllDirectionsFlag(false),
myFryingFlag(false),
myUseCtrlKeyFlag(true),
mySkipMouseMotion(true),
myIs7800(false),
myAltKeyCounter(0),
myContSnapshotInterval(0),
myContSnapshotCounter(0)
myIs7800(false)
{
// Erase the key mapping array
for(int i = 0; i < KBDK_LAST; ++i)
for(int m = 0; m < kNumModes; ++m)
myKeyTable[i][m] = Event::NoType;
// Create keyboard handler (to handle all physical keyboard functionality)
myPKeyHandler = make_unique<PhysicalKeyboardHandler>(osystem, *this, myEvent);
// Create joystick handler (to handle all physical joystick functionality)
myPJoyHandler = make_unique<PhysicalJoystickHandler>(osystem, *this, myEvent);
// Erase the 'combo' array
for(int i = 0; i < kComboSize; ++i)
for(int j = 0; j < kEventsPerCombo; ++j)
myComboTable[i][j] = Event::NoType;
// Create joystick handler (to handle all physical joystick functionality)
myPJoyHandler = make_unique<PhysicalJoystickHandler>(osystem, *this, myEvent);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -96,13 +88,10 @@ void EventHandler::initialize()
{
// Make sure the event/action mappings are correctly set,
// and fill the ActionList structure with valid values
setKeymap();
setComboMap();
setActionMappings(kEmulationMode);
setActionMappings(kMenuMode);
myUseCtrlKeyFlag = myOSystem.settings().getBool("ctrlcombo");
Joystick::setDeadZone(myOSystem.settings().getInt("joydeadzone"));
Paddles::setDigitalSensitivity(myOSystem.settings().getInt("dsense"));
Paddles::setMouseSensitivity(myOSystem.settings().getInt("msense"));
@ -128,10 +117,9 @@ void EventHandler::initialize()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::reset(EventHandlerState state)
{
setEventState(state);
setState(state);
myOSystem.state().reset();
setContinuousSnapshots(0);
myOSystem.png().setContinuousSnapInterval(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -195,6 +183,13 @@ void EventHandler::set7800Mode()
myIs7800 = false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::handleMouseControl()
{
if(myMouseControl)
myOSystem.frameBuffer().showMessage(myMouseControl->next());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::poll(uInt64 time)
{
@ -218,9 +213,8 @@ void EventHandler::poll(uInt64 time)
#endif
// Handle continuous snapshots
if(myContSnapshotInterval > 0 &&
(++myContSnapshotCounter % myContSnapshotInterval == 0))
takeSnapshot(uInt32(time) >> 10); // not quite milliseconds, but close enough
if(myOSystem.png().continuousSnapEnabled())
myOSystem.png().updateTime(time);
}
else if(myOverlay)
{
@ -243,404 +237,6 @@ void EventHandler::handleTextEvent(char text)
myOverlay->handleTextEvent(text);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state)
{
// Swallow KBDK_TAB under certain conditions
// See commments on 'myAltKeyCounter' for more information
#ifdef BSPF_UNIX
if(myAltKeyCounter > 1 && key == KBDK_TAB)
{
myAltKeyCounter = false;
return;
}
#endif
bool handled = true;
// Immediately store the key state
myEvent.setKey(key, state);
// An attempt to speed up event processing; we quickly check for
// Control or Alt/Cmd combos first
if(StellaModTest::isAlt(mod) && state)
{
#ifdef BSPF_MAC_OSX
// These keys work in all states
if(key == KBDK_Q)
{
handleEvent(Event::Quit, 1);
}
else
#endif
if(key == KBDK_TAB)
{
// Swallow Alt-Tab, but remember that it happened
myAltKeyCounter = 1;
return;
}
else if(key == KBDK_RETURN)
{
myOSystem.frameBuffer().toggleFullscreen();
}
// State rewinding must work in pause mode too
else if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE)
{
switch(key)
{
case KBDK_LEFT: // Alt-left(-shift) rewinds 1(10) states
enterTimeMachineMenuMode((StellaModTest::isShift(mod) && state) ? 10 : 1, false);
break;
case KBDK_RIGHT: // Alt-right(-shift) unwinds 1(10) states
enterTimeMachineMenuMode((StellaModTest::isShift(mod) && state) ? 10 : 1, true);
break;
case KBDK_DOWN: // Alt-down rewinds to start of list
enterTimeMachineMenuMode(1000, false);
break;
case KBDK_UP: // Alt-up rewinds to end of list
enterTimeMachineMenuMode(1000, true);
break;
// These can work in pause mode too
case KBDK_EQUALS:
myOSystem.frameBuffer().changeWindowedVidMode(+1);
break;
case KBDK_MINUS:
myOSystem.frameBuffer().changeWindowedVidMode(-1);
break;
case KBDK_LEFTBRACKET:
myOSystem.sound().adjustVolume(-1);
break;
case KBDK_RIGHTBRACKET:
myOSystem.sound().adjustVolume(+1);
break;
case KBDK_PAGEUP: // Alt-PageUp increases YStart
myOSystem.console().changeYStart(+1);
break;
case KBDK_PAGEDOWN: // Alt-PageDown decreases YStart
myOSystem.console().changeYStart(-1);
break;
case KBDK_1: // Alt-1 turns off NTSC filtering
myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_OFF);
break;
case KBDK_2: // Alt-2 turns on 'composite' NTSC filtering
myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_COMPOSITE);
break;
case KBDK_3: // Alt-3 turns on 'svideo' NTSC filtering
myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_SVIDEO);
break;
case KBDK_4: // Alt-4 turns on 'rgb' NTSC filtering
myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_RGB);
break;
case KBDK_5: // Alt-5 turns on 'bad' NTSC filtering
myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_BAD);
break;
case KBDK_6: // Alt-6 turns on 'custom' NTSC filtering
myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_CUSTOM);
break;
case KBDK_7: // Alt-7 changes scanline intensity for NTSC filtering
if(mod & KBDM_SHIFT)
myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-5);
else
myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+5);
break;
case KBDK_8: // Alt-8 turns toggles scanline interpolation
myOSystem.frameBuffer().tiaSurface().toggleScanlineInterpolation();
break;
case KBDK_9: // Alt-9 selects various custom adjustables for NTSC filtering
if(myOSystem.frameBuffer().tiaSurface().ntscEnabled())
{
if(mod & KBDM_SHIFT)
myOSystem.frameBuffer().showMessage(
myOSystem.frameBuffer().tiaSurface().ntsc().setPreviousAdjustable());
else
myOSystem.frameBuffer().showMessage(
myOSystem.frameBuffer().tiaSurface().ntsc().setNextAdjustable());
}
break;
case KBDK_0: // Alt-0 changes custom adjustables for NTSC filtering
if(myOSystem.frameBuffer().tiaSurface().ntscEnabled())
{
if(mod & KBDM_SHIFT)
myOSystem.frameBuffer().showMessage(
myOSystem.frameBuffer().tiaSurface().ntsc().decreaseAdjustable());
else
myOSystem.frameBuffer().showMessage(
myOSystem.frameBuffer().tiaSurface().ntsc().increaseAdjustable());
}
break;
case KBDK_Z:
if(mod & KBDM_SHIFT)
myOSystem.console().toggleP0Collision();
else
myOSystem.console().toggleP0Bit();
break;
case KBDK_X:
if(mod & KBDM_SHIFT)
myOSystem.console().toggleP1Collision();
else
myOSystem.console().toggleP1Bit();
break;
case KBDK_C:
if(mod & KBDM_SHIFT)
myOSystem.console().toggleM0Collision();
else
myOSystem.console().toggleM0Bit();
break;
case KBDK_V:
if(mod & KBDM_SHIFT)
myOSystem.console().toggleM1Collision();
else
myOSystem.console().toggleM1Bit();
break;
case KBDK_B:
if(mod & KBDM_SHIFT)
myOSystem.console().toggleBLCollision();
else
myOSystem.console().toggleBLBit();
break;
case KBDK_N:
if(mod & KBDM_SHIFT)
myOSystem.console().togglePFCollision();
else
myOSystem.console().togglePFBit();
break;
case KBDK_COMMA:
myOSystem.console().toggleFixedColors();
break;
case KBDK_PERIOD:
if(mod & KBDM_SHIFT)
myOSystem.console().toggleCollisions();
else
myOSystem.console().toggleBits();
break;
case KBDK_I: // Alt-i decreases phosphor blend
myOSystem.console().changePhosphor(-1);
break;
case KBDK_O: // Alt-o increases phosphor blend
myOSystem.console().changePhosphor(+1);
break;
case KBDK_P: // Alt-p toggles phosphor effect
myOSystem.console().togglePhosphor();
break;
case KBDK_J: // Alt-j toggles scanline jitter
myOSystem.console().toggleJitter();
break;
case KBDK_L:
myOSystem.frameBuffer().toggleFrameStats();
break;
case KBDK_T: // Alt-t toggles Time Machine
myOSystem.state().toggleTimeMachine();
break;
case KBDK_S:
if(myContSnapshotInterval == 0)
{
ostringstream buf;
uInt32 interval = myOSystem.settings().getInt("ssinterval");
if(mod & KBDM_SHIFT)
{
buf << "Enabling snapshots every frame";
interval = 1;
}
else
{
buf << "Enabling snapshots in " << interval << " second intervals";
interval *= uInt32(myOSystem.frameRate());
}
myOSystem.frameBuffer().showMessage(buf.str());
setContinuousSnapshots(interval);
}
else
{
ostringstream buf;
buf << "Disabling snapshots, generated "
<< (myContSnapshotCounter / myContSnapshotInterval)
<< " files";
myOSystem.frameBuffer().showMessage(buf.str());
setContinuousSnapshots(0);
}
break;
default:
handled = false;
break;
}
}
else
handled = false;
}
else if(StellaModTest::isControl(mod) && state && myUseCtrlKeyFlag)
{
// These keys work in all states
if(key == KBDK_Q)
{
handleEvent(Event::Quit, 1);
}
// These only work when in emulation mode
else if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE)
{
switch(key)
{
case KBDK_0: // Ctrl-0 switches between mouse control modes
if(myMouseControl)
myOSystem.frameBuffer().showMessage(myMouseControl->next());
break;
case KBDK_1: // Ctrl-1 swaps Stelladaptor/2600-daptor ports
toggleSAPortOrder();
break;
case KBDK_F: // (Shift) Ctrl-f toggles NTSC/PAL/SECAM mode
myOSystem.console().toggleFormat(mod & KBDM_SHIFT ? -1 : 1);
break;
case KBDK_G: // Ctrl-g (un)grabs mouse
if(!myOSystem.frameBuffer().fullScreen())
{
myOSystem.frameBuffer().toggleGrabMouse();
myOSystem.frameBuffer().showMessage(myOSystem.frameBuffer().grabMouseEnabled()
? "Grab mouse enabled" : "Grab mouse disabled");
}
break;
case KBDK_L: // Ctrl-l toggles PAL color-loss effect
myOSystem.console().toggleColorLoss();
break;
case KBDK_P: // Ctrl-p toggles different palettes
myOSystem.console().togglePalette();
break;
case KBDK_R: // Ctrl-r reloads the currently loaded ROM
myOSystem.reloadConsole();
break;
case KBDK_PAGEUP: // Ctrl-PageUp increases Height
myOSystem.console().changeHeight(+1);
break;
case KBDK_PAGEDOWN: // Ctrl-PageDown decreases Height
myOSystem.console().changeHeight(-1);
break;
case KBDK_S: // Ctrl-s saves properties to a file
{
string filename = myOSystem.baseDir() +
myOSystem.console().properties().get(Cartridge_Name) + ".pro";
ofstream out(filename);
if(out)
{
out << myOSystem.console().properties();
myOSystem.frameBuffer().showMessage("Properties saved");
}
else
myOSystem.frameBuffer().showMessage("Error saving properties");
break;
}
default:
handled = false;
break;
}
}
else
handled = false;
}
else
handled = false;
// Don't pass the key on if we've already taken care of it
if(handled) return;
// Arrange the logic to take advantage of short-circuit evaluation
if(!(StellaModTest::isControl(mod) || StellaModTest::isShift(mod) || StellaModTest::isAlt(mod)))
{
// special handling for Escape key
if(state && key == KBDK_ESCAPE)
{
if(myState == EventHandlerState::PAUSE)
{
setEventState(EventHandlerState::EMULATION);
return;
}
else if(myState == EventHandlerState::CMDMENU ||
myState == EventHandlerState::TIMEMACHINE)
{
leaveMenuMode();
return;
}
else if(myState == EventHandlerState::DEBUGGER && myOSystem.debugger().canExit())
{
leaveDebugMode();
return;
}
}
// Handle keys which switch eventhandler state
if(!state && eventStateChange(myKeyTable[key][kEmulationMode]))
return;
}
// Otherwise, let the event handler deal with it
switch(myState)
{
case EventHandlerState::EMULATION:
handleEvent(myKeyTable[key][kEmulationMode], state);
break;
case EventHandlerState::PAUSE:
switch(myKeyTable[key][kEmulationMode])
{
case Event::TakeSnapshot:
case Event::DebuggerMode:
handleEvent(myKeyTable[key][kEmulationMode], state);
break;
default:
break;
}
break;
default:
if(myOverlay)
myOverlay->handleKeyEvent(key, mod, state);
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::handleMouseMotionEvent(int x, int y, int xrel, int yrel)
{
@ -693,8 +289,8 @@ void EventHandler::handleSystemEvent(SystemEvent e, int, int)
case SystemEvent::WINDOW_FOCUS_GAINED:
// Used to handle Alt-x key combos; sometimes the key associated with
// Alt gets 'stuck' and is passed to the core for processing
if(myAltKeyCounter > 0)
myAltKeyCounter = 2;
if(myPKeyHandler->altKeyCount() > 0)
myPKeyHandler->altKeyCount() = 2;
break;
#if 0
case SystemEvent::WINDOW_MINIMIZED:
@ -758,7 +354,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 state)
////////////////////////////////////////////////////////////////////////
case Event::Fry:
if(myUseCtrlKeyFlag) myFryingFlag = bool(state);
if(myPKeyHandler->useCtrlKey()) myFryingFlag = bool(state);
return;
case Event::VolumeDecrease:
@ -782,7 +378,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 state)
return;
case Event::TakeSnapshot:
if(state) takeSnapshot();
if(state) myOSystem.png().takeSnapshot();
return;
case Event::LauncherMode:
@ -996,7 +592,7 @@ void EventHandler::handleConsoleStartupEvents()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool EventHandler::eventStateChange(Event::Type type)
bool EventHandler::changeStateByEvent(Event::Type type)
{
bool handled = true;
@ -1004,9 +600,9 @@ bool EventHandler::eventStateChange(Event::Type type)
{
case Event::PauseMode:
if(myState == EventHandlerState::EMULATION)
setEventState(EventHandlerState::PAUSE);
setState(EventHandlerState::PAUSE);
else if(myState == EventHandlerState::PAUSE)
setEventState(EventHandlerState::EMULATION);
setState(EventHandlerState::EMULATION);
else
handled = false;
break;
@ -1078,17 +674,7 @@ void EventHandler::setActionMappings(EventMode mode)
{
Event::Type event = list[i].event;
list[i].key = "None";
string key = "";
for(int j = 0; j < KBDK_LAST; ++j) // key mapping
{
if(myKeyTable[j][mode] == event)
{
if(key == "")
key = key + nameForKey(StellaKey(j));
else
key = key + ", " + nameForKey(StellaKey(j));
}
}
string key = myPKeyHandler->getMappingDesc(event, mode);
#ifdef JOYSTICK_SUPPORT
string joydesc = myPJoyHandler->getMappingDesc(event, mode);
@ -1124,42 +710,6 @@ void EventHandler::setActionMappings(EventMode mode)
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::setKeymap()
{
// Since istringstream swallows whitespace, we have to make the
// delimiters be spaces
string list = myOSystem.settings().getString("keymap");
replace(list.begin(), list.end(), ':', ' ');
istringstream buf(list);
IntArray map;
int value;
Event::Type event;
// Get event count, which should be the first int in the list
buf >> value;
event = Event::Type(value);
if(event == Event::LastType)
while(buf >> value)
map.push_back(value);
// Only fill the key mapping array if the data is valid
if(event == Event::LastType && map.size() == KBDK_LAST * kNumModes)
{
// Fill the keymap table with events
auto e = map.cbegin();
for(int mode = 0; mode < kNumModes; ++mode)
for(int i = 0; i < KBDK_LAST; ++i)
myKeyTable[i][mode] = Event::Type(*e++);
}
else
{
setDefaultKeymap(Event::NoType, kEmulationMode);
setDefaultKeymap(Event::NoType, kMenuMode);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::setComboMap()
{
@ -1214,16 +764,11 @@ void EventHandler::removePhysicalJoystickFromDatabase(const string& name)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool EventHandler::addKeyMapping(Event::Type event, EventMode mode, StellaKey key)
{
// These keys cannot be remapped
if(key == KBDK_TAB || Event::isAnalog(event))
return false;
else
{
myKeyTable[key][mode] = event;
bool mapped = myPKeyHandler->addMapping(event, mode, key);
if(mapped)
setActionMappings(mode);
return true;
}
return mapped;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1277,10 +822,8 @@ bool EventHandler::addJoyHatMapping(Event::Type event, EventMode mode,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::eraseMapping(Event::Type event, EventMode mode)
{
// Erase the KeyEvent arrays
for(int i = 0; i < KBDK_LAST; ++i)
if(myKeyTable[i][mode] == event && i != KBDK_TAB)
myKeyTable[i][mode] = Event::NoType;
// Erase the KeyEvent array
myPKeyHandler->eraseMapping(event, mode);
#ifdef JOYSTICK_SUPPORT
// Erase the joystick mapping arrays
@ -1300,110 +843,7 @@ void EventHandler::setDefaultMapping(Event::Type event, EventMode mode)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::setDefaultKeymap(Event::Type event, EventMode mode)
{
// If event is 'NoType', erase and reset all mappings
// Otherwise, only reset the given event
bool eraseAll = (event == Event::NoType);
if(eraseAll)
{
// Erase all mappings
for(int i = 0; i < KBDK_LAST; ++i)
myKeyTable[i][mode] = Event::NoType;
}
auto setDefaultKey = [&](StellaKey key, Event::Type k_event)
{
if(eraseAll || k_event == event)
myKeyTable[key][mode] = k_event;
};
switch(mode)
{
case kEmulationMode:
setDefaultKey( KBDK_1, Event::KeyboardZero1 );
setDefaultKey( KBDK_2, Event::KeyboardZero2 );
setDefaultKey( KBDK_3, Event::KeyboardZero3 );
setDefaultKey( KBDK_Q, Event::KeyboardZero4 );
setDefaultKey( KBDK_W, Event::KeyboardZero5 );
setDefaultKey( KBDK_E, Event::KeyboardZero6 );
setDefaultKey( KBDK_A, Event::KeyboardZero7 );
setDefaultKey( KBDK_S, Event::KeyboardZero8 );
setDefaultKey( KBDK_D, Event::KeyboardZero9 );
setDefaultKey( KBDK_Z, Event::KeyboardZeroStar );
setDefaultKey( KBDK_X, Event::KeyboardZero0 );
setDefaultKey( KBDK_C, Event::KeyboardZeroPound );
setDefaultKey( KBDK_8, Event::KeyboardOne1 );
setDefaultKey( KBDK_9, Event::KeyboardOne2 );
setDefaultKey( KBDK_0, Event::KeyboardOne3 );
setDefaultKey( KBDK_I, Event::KeyboardOne4 );
setDefaultKey( KBDK_O, Event::KeyboardOne5 );
setDefaultKey( KBDK_P, Event::KeyboardOne6 );
setDefaultKey( KBDK_K, Event::KeyboardOne7 );
setDefaultKey( KBDK_L, Event::KeyboardOne8 );
setDefaultKey( KBDK_SEMICOLON, Event::KeyboardOne9 );
setDefaultKey( KBDK_COMMA, Event::KeyboardOneStar );
setDefaultKey( KBDK_PERIOD, Event::KeyboardOne0 );
setDefaultKey( KBDK_SLASH, Event::KeyboardOnePound );
setDefaultKey( KBDK_UP, Event::JoystickZeroUp );
setDefaultKey( KBDK_DOWN, Event::JoystickZeroDown );
setDefaultKey( KBDK_LEFT, Event::JoystickZeroLeft );
setDefaultKey( KBDK_RIGHT, Event::JoystickZeroRight );
setDefaultKey( KBDK_SPACE, Event::JoystickZeroFire );
setDefaultKey( KBDK_LCTRL, Event::JoystickZeroFire );
setDefaultKey( KBDK_4, Event::JoystickZeroFire5 );
setDefaultKey( KBDK_5, Event::JoystickZeroFire9 );
setDefaultKey( KBDK_Y, Event::JoystickOneUp );
setDefaultKey( KBDK_H, Event::JoystickOneDown );
setDefaultKey( KBDK_G, Event::JoystickOneLeft );
setDefaultKey( KBDK_J, Event::JoystickOneRight );
setDefaultKey( KBDK_F, Event::JoystickOneFire );
setDefaultKey( KBDK_6, Event::JoystickOneFire5 );
setDefaultKey( KBDK_7, Event::JoystickOneFire9 );
setDefaultKey( KBDK_F1, Event::ConsoleSelect );
setDefaultKey( KBDK_F2, Event::ConsoleReset );
setDefaultKey( KBDK_F3, Event::ConsoleColor );
setDefaultKey( KBDK_F4, Event::ConsoleBlackWhite );
setDefaultKey( KBDK_F5, Event::ConsoleLeftDiffA );
setDefaultKey( KBDK_F6, Event::ConsoleLeftDiffB );
setDefaultKey( KBDK_F7, Event::ConsoleRightDiffA );
setDefaultKey( KBDK_F8, Event::ConsoleRightDiffB );
setDefaultKey( KBDK_F9, Event::SaveState );
setDefaultKey( KBDK_F10, Event::ChangeState );
setDefaultKey( KBDK_F11, Event::LoadState );
setDefaultKey( KBDK_F12, Event::TakeSnapshot );
setDefaultKey( KBDK_BACKSPACE, Event::Fry );
setDefaultKey( KBDK_PAUSE, Event::PauseMode );
setDefaultKey( KBDK_TAB, Event::OptionsMenuMode );
setDefaultKey( KBDK_BACKSLASH, Event::CmdMenuMode );
setDefaultKey( KBDK_T, Event::TimeMachineMode );
setDefaultKey( KBDK_GRAVE, Event::DebuggerMode );
setDefaultKey( KBDK_ESCAPE, Event::LauncherMode );
break;
case kMenuMode:
setDefaultKey( KBDK_UP, Event::UIUp );
setDefaultKey( KBDK_DOWN, Event::UIDown );
setDefaultKey( KBDK_LEFT, Event::UILeft );
setDefaultKey( KBDK_RIGHT, Event::UIRight );
setDefaultKey( KBDK_HOME, Event::UIHome );
setDefaultKey( KBDK_END, Event::UIEnd );
setDefaultKey( KBDK_PAGEUP, Event::UIPgUp );
setDefaultKey( KBDK_PAGEDOWN, Event::UIPgDown );
setDefaultKey( KBDK_RETURN, Event::UISelect );
setDefaultKey( KBDK_ESCAPE, Event::UICancel );
setDefaultKey( KBDK_BACKSPACE, Event::UIPrevDir );
break;
default:
return;
}
myPKeyHandler->setDefaultMapping(event, mode);
setActionMappings(mode);
}
@ -1419,15 +859,7 @@ void EventHandler::setDefaultJoymap(Event::Type event, EventMode mode)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::saveKeyMapping()
{
// Iterate through the keymap table and create a colon-separated list
// Prepend the event count, so we can check it on next load
ostringstream keybuf;
keybuf << Event::LastType;
for(int mode = 0; mode < kNumModes; ++mode)
for(int i = 0; i < KBDK_LAST; ++i)
keybuf << ":" << myKeyTable[i][mode];
myOSystem.settings().setValue("keymap", keybuf.str());
myPKeyHandler->saveMapping();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1603,98 +1035,6 @@ string EventHandler::keyAtIndex(int idx, EventMode mode) const
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::takeSnapshot(uInt32 number)
{
// Figure out the correct snapshot name
string filename;
bool showmessage = number == 0;
string sspath = myOSystem.snapshotSaveDir() +
(myOSystem.settings().getString("snapname") != "int" ?
myOSystem.romFile().getNameWithExt("")
: myOSystem.console().properties().get(Cartridge_Name));
// Check whether we want multiple snapshots created
if(number > 0)
{
ostringstream buf;
buf << sspath << "_" << std::hex << std::setw(8) << std::setfill('0')
<< number << ".png";
filename = buf.str();
}
else if(!myOSystem.settings().getBool("sssingle"))
{
// Determine if the file already exists, checking each successive filename
// until one doesn't exist
filename = sspath + ".png";
FilesystemNode node(filename);
if(node.exists())
{
ostringstream buf;
for(uInt32 i = 1; ;++i)
{
buf.str("");
buf << sspath << "_" << i << ".png";
FilesystemNode next(buf.str());
if(!next.exists())
break;
}
filename = buf.str();
}
}
else
filename = sspath + ".png";
// Some text fields to add to the PNG snapshot
VariantList comments;
ostringstream version;
version << "Stella " << STELLA_VERSION << " (Build " << STELLA_BUILD << ") ["
<< BSPF::ARCH << "]";
VarList::push_back(comments, "Software", version.str());
VarList::push_back(comments, "ROM Name", myOSystem.console().properties().get(Cartridge_Name));
VarList::push_back(comments, "ROM MD5", myOSystem.console().properties().get(Cartridge_MD5));
VarList::push_back(comments, "TV Effects", myOSystem.frameBuffer().tiaSurface().effectsInfo());
// Now create a PNG snapshot
if(myOSystem.settings().getBool("ss1x"))
{
string message = "Snapshot saved";
try
{
GUI::Rect rect;
const FBSurface& surface = myOSystem.frameBuffer().tiaSurface().baseSurface(rect);
myOSystem.png().saveImage(filename, surface, rect, comments);
}
catch(const runtime_error& e)
{
message = e.what();
}
if(showmessage)
myOSystem.frameBuffer().showMessage(message);
}
else
{
// Make sure we have a 'clean' image, with no onscreen messages
myOSystem.frameBuffer().enableMessages(false);
myOSystem.frameBuffer().tiaSurface().reRender();
string message = "Snapshot saved";
try
{
myOSystem.png().saveImage(filename, comments);
}
catch(const runtime_error& e)
{
message = e.what();
}
// Re-enable old messages
myOSystem.frameBuffer().enableMessages(true);
if(showmessage)
myOSystem.frameBuffer().showMessage(message);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::setMouseControllerMode(const string& enable)
{
@ -1719,17 +1059,10 @@ void EventHandler::setMouseControllerMode(const string& enable)
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::setContinuousSnapshots(uInt32 interval)
{
myContSnapshotInterval = interval;
myContSnapshotCounter = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::enterMenuMode(EventHandlerState state)
{
setEventState(state);
setState(state);
myOverlay->reStack();
myOSystem.sound().mute(true);
}
@ -1737,7 +1070,7 @@ void EventHandler::enterMenuMode(EventHandlerState state)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::leaveMenuMode()
{
setEventState(EventHandlerState::EMULATION);
setState(EventHandlerState::EMULATION);
myOSystem.sound().mute(false);
}
@ -1753,13 +1086,13 @@ bool EventHandler::enterDebugMode()
// mode, since it takes care of locking the debugger state, which will
// probably be modified below
myOSystem.debugger().setStartState();
setEventState(EventHandlerState::DEBUGGER);
setState(EventHandlerState::DEBUGGER);
FBInitStatus fbstatus = myOSystem.createFrameBuffer();
if(fbstatus != FBInitStatus::Success)
{
myOSystem.debugger().setQuitState();
setEventState(EventHandlerState::EMULATION);
setState(EventHandlerState::EMULATION);
if(fbstatus == FBInitStatus::FailTooLarge)
myOSystem.frameBuffer().showMessage("Debugger window too large for screen",
MessagePosition::BottomCenter, true);
@ -1786,7 +1119,7 @@ void EventHandler::leaveDebugMode()
// Make sure debugger quits in a consistent state
myOSystem.debugger().setQuitState();
setEventState(EventHandlerState::EMULATION);
setState(EventHandlerState::EMULATION);
myOSystem.createFrameBuffer();
myOSystem.sound().mute(false);
#endif
@ -1807,13 +1140,13 @@ void EventHandler::enterTimeMachineMenuMode(uInt32 numWinds, bool unwind)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::setEventState(EventHandlerState state)
void EventHandler::setState(EventHandlerState state)
{
myState = state;
// Normally, the usage of Control key is determined by 'ctrlcombo'
// For certain ROMs it may be forced off, whatever the setting
myUseCtrlKeyFlag = myOSystem.settings().getBool("ctrlcombo");
myPKeyHandler->useCtrlKey() = myOSystem.settings().getBool("ctrlcombo");
// Only enable text input in GUI modes, since in emulation mode the
// keyboard acts as one large joystick with many (single) buttons
@ -1824,7 +1157,7 @@ void EventHandler::setEventState(EventHandlerState state)
myOSystem.sound().mute(false);
enableTextEvents(false);
if(myOSystem.console().leftController().type() == Controller::CompuMate)
myUseCtrlKeyFlag = false;
myPKeyHandler->useCtrlKey() = false;
break;
case EventHandlerState::PAUSE:

View File

@ -30,6 +30,7 @@ class PhysicalJoystick;
#include "EventHandlerConstants.hxx"
#include "Control.hxx"
#include "StellaKeys.hxx"
#include "PKeyboardHandler.hxx"
#include "PJoystickHandler.hxx"
#include "Variant.hxx"
#include "bspf.hxx"
@ -97,11 +98,12 @@ class EventHandler
void poll(uInt64 time);
/**
Returns the current state of the EventHandler
Get/set the current state of the EventHandler
@return The EventHandlerState type
*/
EventHandlerState state() const { return myState; }
void setState(EventHandlerState state);
/**
Resets the state machine of the EventHandler to the defaults
@ -125,21 +127,11 @@ class EventHandler
*/
void setMouseControllerMode(const string& enable);
/**
Set the number of seconds between taking a snapshot in
continuous snapshot mode. Setting an interval of 0 disables
continuous snapshots.
@param interval Interval in seconds between snapshots
*/
void setContinuousSnapshots(uInt32 interval);
void enterMenuMode(EventHandlerState state);
void leaveMenuMode();
bool enterDebugMode();
void leaveDebugMode();
void enterTimeMachineMenuMode(uInt32 numWinds, bool unwind);
void takeSnapshot(uInt32 number = 0);
/**
Send an event directly to the event handler.
@ -166,8 +158,9 @@ class EventHandler
void setComboListForEvent(Event::Type event, const StringList& events);
/** Convert keys and physical joystick events into Stella events. */
Event::Type eventForKey(StellaKey key, EventMode mode) const
{ return myKeyTable[key][mode]; }
Event::Type eventForKey(StellaKey key, EventMode mode) const {
return myPKeyHandler->eventForKey(key, mode);
}
Event::Type eventForJoyAxis(int stick, int axis, int value, EventMode mode) const {
return myPJoyHandler->eventForAxis(stick, axis, value, mode);
}
@ -270,12 +263,12 @@ class EventHandler
void allowAllDirections(bool allow) { myAllowAllDirectionsFlag = allow; }
/**
Detects and changes the eventhandler state.
Changes to a new state based on the current state and the given event.
@param type The event
@return True if the state changed, else false
*/
bool eventStateChange(Event::Type type);
bool changeStateByEvent(Event::Type type);
/**
Get the current overlay in use. The overlay won't always exist,
@ -305,6 +298,11 @@ class EventHandler
*/
virtual void enableTextEvents(bool enable) = 0;
/**
Handle changing mouse modes.
*/
void handleMouseControl();
protected:
// Global OSystem object
OSystem& myOSystem;
@ -314,9 +312,11 @@ class EventHandler
of input.
*/
void handleTextEvent(char text);
void handleKeyEvent(StellaKey key, StellaMod mod, bool state);
void handleMouseMotionEvent(int x, int y, int xrel, int yrel);
void handleMouseButtonEvent(MouseButton b, bool pressed, int x, int y);
void handleKeyEvent(StellaKey key, StellaMod mod, bool state) {
myPKeyHandler->handleEvent(key, mod, state);
}
void handleJoyBtnEvent(int stick, int button, uInt8 state) {
myPJoyHandler->handleBtnEvent(stick, button, state);
}
@ -327,12 +327,6 @@ class EventHandler
myPJoyHandler->handleHatEvent(stick, hat, value);
}
/**
Returns the human-readable name for a StellaKey.
*/
virtual const char* const nameForKey(StellaKey key) const
{ return EmptyString.c_str(); }
/**
Collects and dispatches any pending events.
*/
@ -377,15 +371,12 @@ class EventHandler
The following methods take care of assigning action mappings.
*/
void setActionMappings(EventMode mode);
void setKeymap();
void setDefaultKeymap(Event::Type, EventMode mode);
void setDefaultJoymap(Event::Type, EventMode mode);
void saveKeyMapping();
void saveJoyMapping();
void saveComboMapping();
void setEventState(EventHandlerState state);
private:
// Structure used for action menu items
struct ActionList {
@ -401,15 +392,15 @@ class EventHandler
// Indicates current overlay object
DialogContainer* myOverlay;
// MouseControl object, which takes care of switching the mouse between
// all possible controller modes
unique_ptr<MouseControl> myMouseControl;
// Handler for all keyboard-related events
unique_ptr<PhysicalKeyboardHandler> myPKeyHandler;
// Handler for all joystick addition/removal/mapping
unique_ptr<PhysicalJoystickHandler> myPJoyHandler;
// Array of key events, indexed by StellaKey
Event::Type myKeyTable[KBDK_LAST][kNumModes];
// MouseControl object, which takes care of switching the mouse between
// all possible controller modes
unique_ptr<MouseControl> myMouseControl;
// The event(s) assigned to each combination event
Event::Type myComboTable[kComboSize][kEventsPerCombo];
@ -423,12 +414,6 @@ class EventHandler
// Indicates whether or not we're in frying mode
bool myFryingFlag;
// Indicates whether the key-combos tied to the Control key are
// being used or not (since Ctrl by default is the fire button,
// pressing it with a movement key could inadvertantly activate
// a Ctrl combo when it isn't wanted)
bool myUseCtrlKeyFlag;
// Sometimes an extraneous mouse motion event occurs after a video
// state change; we detect when this happens and discard the event
bool mySkipMouseMotion;
@ -437,23 +422,6 @@ class EventHandler
// of the 7800 (for now, only the switches are notified)
bool myIs7800;
// Sometimes key combos with the Alt key become 'stuck' after the
// window changes state, and we want to ignore that event
// For example, press Alt-Tab and then upon re-entering the window,
// the app receives 'tab'; obviously the 'tab' shouldn't be happening
// So we keep track of the cases that matter (for now, Alt-Tab)
// and swallow the event afterwards
// Basically, the initial event sets the variable to 1, and upon
// returning to the app (ie, receiving EVENT_WINDOW_FOCUS_GAINED),
// the count is updated to 2, but only if it was already updated to 1
// TODO - This may be a bug in SDL, and might be removed in the future
// It only seems to be an issue in Linux
uInt8 myAltKeyCounter;
// Used for continuous snapshot mode
uInt32 myContSnapshotInterval;
uInt32 myContSnapshotCounter;
// Holds static strings for the remap menu (emulation and menu events)
static ActionList ourEmulActionList[kEmulActionListSize];
static ActionList ourMenuActionList[kMenuActionListSize];

View File

@ -158,7 +158,7 @@ bool OSystem::create()
myRandom->initSeed();
// Create PNG handler
myPNGLib = make_unique<PNGLibrary>(*myFrameBuffer);
myPNGLib = make_unique<PNGLibrary>(*this);
return true;
}