mirror of https://github.com/stella-emu/stella.git
Merge branch 'master' into feature/precise-audio
This commit is contained in:
commit
c905b01fca
33
Changes.txt
33
Changes.txt
|
@ -1,4 +1,18 @@
|
|||
5.1 to 5.2: (MMM d, 2018)
|
||||
===========================================================================
|
||||
|
||||
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
|
||||
|
||||
===========================================================================
|
||||
Release History
|
||||
===========================================================================
|
||||
|
||||
5.1.1 to 5.2: (MMM d, 2018)
|
||||
|
||||
* Extra functionality for Time Machine dialog (start/stop recording;
|
||||
minor fixes; TODO button and initial key repeats...)
|
||||
|
@ -7,6 +21,21 @@
|
|||
|
||||
* UI modernization (new widget look, dialog titles added, dialogs refactored)
|
||||
|
||||
* Fixed bug in UI navigation with joystick hat movement.
|
||||
|
||||
* The Linux builds now use the system-installed PNG and ZLIB libraries
|
||||
by default.
|
||||
|
||||
* Updated version of SDL included with the Windows build to 2.0.8.
|
||||
|
||||
-Have fun!
|
||||
|
||||
|
||||
5.1 to 5.1.1: (February 21, 2018)
|
||||
|
||||
* Fixed bug in Stargunner ROM starting with a blank screen.
|
||||
|
||||
|
||||
5.0.2 to 5.1: (February 4, 2018)
|
||||
|
||||
* Added "Time Machine" mode, which automatically creates save states
|
||||
|
@ -141,8 +170,6 @@
|
|||
|
||||
* Updated included PNG library to latest stable version.
|
||||
|
||||
-Have fun!
|
||||
|
||||
|
||||
5.0.1 to 5.0.2: (August 20, 2017)
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
5
|
||||
9
|
||||
|
|
|
@ -3,7 +3,7 @@ Section: games
|
|||
Priority: optional
|
||||
Maintainer: Stephen Anthony <sa666666@gmail.com>
|
||||
Standards-Version: 3.7.2
|
||||
Build-Depends: debhelper (>= 5.0.0), libsdl2-dev
|
||||
Build-Depends: debhelper (>= 5.0.0), libsdl2-dev, libpng-dev
|
||||
|
||||
Package: stella
|
||||
Architecture: any
|
||||
|
|
|
@ -20,7 +20,7 @@ endif
|
|||
|
||||
config.status: configure
|
||||
dh_testdir
|
||||
CXXFLAGS="$(CXXFLAGS)" ./configure --prefix=/usr --force-builtin-libpng
|
||||
CXXFLAGS="$(CXXFLAGS)" ./configure --prefix=/usr
|
||||
|
||||
build: build-stamp
|
||||
|
||||
|
|
|
@ -96,8 +96,8 @@ void EventHandlerSDL2::pollEvent()
|
|||
case SDL_JOYBUTTONUP:
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
{
|
||||
handleJoyEvent(myEvent.jbutton.which, myEvent.jbutton.button,
|
||||
myEvent.jbutton.state == SDL_PRESSED ? 1 : 0);
|
||||
handleJoyBtnEvent(myEvent.jbutton.which, myEvent.jbutton.button,
|
||||
myEvent.jbutton.state == SDL_PRESSED ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ void EventHandlerSDL2::pollEvent()
|
|||
case SDL_JOYHATMOTION:
|
||||
{
|
||||
int v = myEvent.jhat.value, value = 0;
|
||||
if(v & SDL_HAT_CENTERED)
|
||||
if(v == SDL_HAT_CENTERED)
|
||||
value = EVENT_HATCENTER_M;
|
||||
else
|
||||
{
|
||||
|
@ -127,12 +127,12 @@ void EventHandlerSDL2::pollEvent()
|
|||
|
||||
case SDL_JOYDEVICEADDED:
|
||||
{
|
||||
addJoystick(new JoystickSDL2(myEvent.jdevice.which));
|
||||
addPhysicalJoystick(make_shared<JoystickSDL2>(myEvent.jdevice.which));
|
||||
break; // SDL_JOYDEVICEADDED
|
||||
}
|
||||
case SDL_JOYDEVICEREMOVED:
|
||||
{
|
||||
removeJoystick(myEvent.jdevice.which);
|
||||
removePhysicalJoystick(myEvent.jdevice.which);
|
||||
break; // SDL_JOYDEVICEREMOVED
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "SDL_lib.hxx"
|
||||
#include "EventHandler.hxx"
|
||||
#include "PhysicalJoystick.hxx"
|
||||
|
||||
/**
|
||||
This class handles event collection from the point of view of the specific
|
||||
|
@ -43,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.
|
||||
*/
|
||||
|
@ -58,9 +52,9 @@ class EventHandlerSDL2 : public EventHandler
|
|||
private:
|
||||
SDL_Event myEvent;
|
||||
|
||||
// A thin wrapper around a basic StellaJoystick, holding the pointer to
|
||||
// the underlying SDL stick.
|
||||
class JoystickSDL2 : public StellaJoystick
|
||||
// A thin wrapper around a basic PhysicalJoystick, holding the pointer to
|
||||
// the underlying SDL joystick device.
|
||||
class JoystickSDL2 : public PhysicalJoystick
|
||||
{
|
||||
public:
|
||||
JoystickSDL2(int idx);
|
||||
|
|
|
@ -0,0 +1,749 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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 "Joystick.hxx"
|
||||
#include "Settings.hxx"
|
||||
#include "EventHandler.hxx"
|
||||
#include "DialogContainer.hxx"
|
||||
#include "PJoystickHandler.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PhysicalJoystickHandler::PhysicalJoystickHandler(
|
||||
OSystem& system, EventHandler& handler, Event& event)
|
||||
: myOSystem(system),
|
||||
myHandler(handler),
|
||||
myEvent(event)
|
||||
{
|
||||
// Load previously saved joystick mapping (if any) from settings
|
||||
istringstream buf(myOSystem.settings().getString("joymap"));
|
||||
string joymap, joyname;
|
||||
|
||||
// First check the event type, and disregard the entire mapping if it's invalid
|
||||
getline(buf, joymap, '^');
|
||||
if(atoi(joymap.c_str()) == Event::LastType)
|
||||
{
|
||||
// Otherwise, put each joystick mapping entry into the database
|
||||
while(getline(buf, joymap, '^'))
|
||||
{
|
||||
istringstream namebuf(joymap);
|
||||
getline(namebuf, joyname, '|');
|
||||
if(joyname.length() != 0)
|
||||
myDatabase.emplace(joyname, StickInfo(joymap));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int PhysicalJoystickHandler::add(PhysicalJoystickPtr stick)
|
||||
{
|
||||
// Skip if we couldn't open it for any reason
|
||||
if(stick->ID < 0)
|
||||
return -1;
|
||||
|
||||
// Figure out what type of joystick this is
|
||||
bool specialAdaptor = false;
|
||||
|
||||
if(BSPF::containsIgnoreCase(stick->name, "2600-daptor"))
|
||||
{
|
||||
specialAdaptor = true;
|
||||
if(stick->numAxes == 4)
|
||||
{
|
||||
// TODO - detect controller type based on z-axis
|
||||
stick->name = "2600-daptor D9";
|
||||
}
|
||||
else if(stick->numAxes == 3)
|
||||
{
|
||||
stick->name = "2600-daptor II";
|
||||
}
|
||||
else
|
||||
stick->name = "2600-daptor";
|
||||
}
|
||||
else if(BSPF::containsIgnoreCase(stick->name, "Stelladaptor"))
|
||||
{
|
||||
stick->name = "Stelladaptor";
|
||||
specialAdaptor = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need unique names for mappable devices
|
||||
// For non-unique names that already have a database entry,
|
||||
// we append ' #x', where 'x' increases consecutively
|
||||
int count = 0;
|
||||
for(const auto& i: myDatabase)
|
||||
if(BSPF::startsWithIgnoreCase(i.first, stick->name) && i.second.joy)
|
||||
++count;
|
||||
|
||||
if(count > 0)
|
||||
{
|
||||
ostringstream name;
|
||||
name << stick->name << " #" << count+1;
|
||||
stick->name = name.str();
|
||||
}
|
||||
stick->type = PhysicalJoystick::JT_REGULAR;
|
||||
}
|
||||
// The stick *must* be inserted here, since it may be used below
|
||||
mySticks[stick->ID] = stick;
|
||||
|
||||
// Map the stelladaptors we've found according to the specified ports
|
||||
if(specialAdaptor)
|
||||
mapStelladaptors(myOSystem.settings().getString("saport"));
|
||||
|
||||
// Add stick to database
|
||||
auto it = myDatabase.find(stick->name);
|
||||
if(it != myDatabase.end()) // already present
|
||||
{
|
||||
it->second.joy = stick;
|
||||
stick->setMap(it->second.mapping);
|
||||
}
|
||||
else // adding for the first time
|
||||
{
|
||||
StickInfo info("", stick);
|
||||
myDatabase.emplace(stick->name, info);
|
||||
setStickDefaultMapping(stick->ID, Event::NoType, kEmulationMode);
|
||||
setStickDefaultMapping(stick->ID, Event::NoType, kMenuMode);
|
||||
}
|
||||
|
||||
// We're potentially swapping out an input device behind the back of
|
||||
// the Event system, so we make sure all Stelladaptor-generated events
|
||||
// are reset
|
||||
for(int i = 0; i < 2; ++i)
|
||||
{
|
||||
for(int j = 0; j < 2; ++j)
|
||||
myEvent.set(SA_Axis[i][j], 0);
|
||||
for(int j = 0; j < 4; ++j)
|
||||
myEvent.set(SA_Button[i][j], 0);
|
||||
for(int j = 0; j < 12; ++j)
|
||||
myEvent.set(SA_Key[i][j], 0);
|
||||
}
|
||||
|
||||
return stick->ID;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::remove(int id)
|
||||
{
|
||||
// When a joystick is removed, we delete the actual joystick object but
|
||||
// remember its mapping, since it will eventually be saved to settings
|
||||
|
||||
// Sticks that are removed must have initially been added
|
||||
// So we use the 'active' joystick list to access them
|
||||
try
|
||||
{
|
||||
PhysicalJoystickPtr stick = mySticks.at(id);
|
||||
|
||||
auto it = myDatabase.find(stick->name);
|
||||
if(it != myDatabase.end() && it->second.joy == stick)
|
||||
{
|
||||
ostringstream buf;
|
||||
buf << "Removed joystick " << mySticks[id]->ID << ":" << endl
|
||||
<< " " << mySticks[id]->about() << endl;
|
||||
myOSystem.logMessage(buf.str(), 1);
|
||||
|
||||
// Remove joystick, but remember mapping
|
||||
it->second.mapping = stick->getMap();
|
||||
it->second.joy = nullptr;
|
||||
mySticks.erase(id);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch(const std::out_of_range&)
|
||||
{
|
||||
// fall through to indicate remove failed
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::remove(const string& name)
|
||||
{
|
||||
auto it = myDatabase.find(name);
|
||||
if(it != myDatabase.end() && it->second.joy == nullptr)
|
||||
{
|
||||
myDatabase.erase(it);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::mapStelladaptors(const string& saport)
|
||||
{
|
||||
// saport will have two values:
|
||||
// 'lr' means treat first valid adaptor as left port, second as right port
|
||||
// 'rl' means treat first valid adaptor as right port, second as left port
|
||||
// We know there will be only two such devices (at most), since the logic
|
||||
// in setupJoysticks take care of that
|
||||
int saCount = 0;
|
||||
int saOrder[2] = { 1, 2 };
|
||||
if(BSPF::equalsIgnoreCase(saport, "rl"))
|
||||
{
|
||||
saOrder[0] = 2; saOrder[1] = 1;
|
||||
}
|
||||
|
||||
for(auto& stick: mySticks)
|
||||
{
|
||||
if(BSPF::startsWithIgnoreCase(stick.second->name, "Stelladaptor"))
|
||||
{
|
||||
if(saOrder[saCount] == 1)
|
||||
{
|
||||
stick.second->name += " (emulates left joystick port)";
|
||||
stick.second->type = PhysicalJoystick::JT_STELLADAPTOR_LEFT;
|
||||
}
|
||||
else if(saOrder[saCount] == 2)
|
||||
{
|
||||
stick.second->name += " (emulates right joystick port)";
|
||||
stick.second->type = PhysicalJoystick::JT_STELLADAPTOR_RIGHT;
|
||||
}
|
||||
saCount++;
|
||||
}
|
||||
else if(BSPF::startsWithIgnoreCase(stick.second->name, "2600-daptor"))
|
||||
{
|
||||
if(saOrder[saCount] == 1)
|
||||
{
|
||||
stick.second->name += " (emulates left joystick port)";
|
||||
stick.second->type = PhysicalJoystick::JT_2600DAPTOR_LEFT;
|
||||
}
|
||||
else if(saOrder[saCount] == 2)
|
||||
{
|
||||
stick.second->name += " (emulates right joystick port)";
|
||||
stick.second->type = PhysicalJoystick::JT_2600DAPTOR_RIGHT;
|
||||
}
|
||||
saCount++;
|
||||
}
|
||||
}
|
||||
myOSystem.settings().setValue("saport", saport);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::setDefaultMapping(Event::Type event, EventMode mode)
|
||||
{
|
||||
eraseMapping(event, mode);
|
||||
for(auto& i: mySticks)
|
||||
setStickDefaultMapping(i.first, event, mode);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::setStickDefaultMapping(int stick,
|
||||
Event::Type event, EventMode mode)
|
||||
{
|
||||
bool eraseAll = (event == Event::NoType);
|
||||
|
||||
auto setDefaultAxis = [&](int a_stick, int a_axis, int a_value, Event::Type a_event)
|
||||
{
|
||||
if(eraseAll || a_event == event)
|
||||
myHandler.addJoyAxisMapping(a_event, mode, a_stick, a_axis, a_value, false);
|
||||
};
|
||||
auto setDefaultBtn = [&](int b_stick, int b_button, Event::Type b_event)
|
||||
{
|
||||
if(eraseAll || b_event == event)
|
||||
myHandler.addJoyButtonMapping(b_event, mode, b_stick, b_button, false);
|
||||
};
|
||||
auto setDefaultHat = [&](int h_stick, int h_hat, JoyHat h_dir, Event::Type h_event)
|
||||
{
|
||||
if(eraseAll || h_event == event)
|
||||
myHandler.addJoyHatMapping(h_event, mode, h_stick, h_hat, h_dir, false);
|
||||
};
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case kEmulationMode: // Default emulation events
|
||||
if(stick == 0)
|
||||
{
|
||||
// Left joystick left/right directions (assume joystick zero)
|
||||
setDefaultAxis( 0, 0, 0, Event::JoystickZeroLeft );
|
||||
setDefaultAxis( 0, 0, 1, Event::JoystickZeroRight );
|
||||
// Left joystick up/down directions (assume joystick zero)
|
||||
setDefaultAxis( 0, 1, 0, Event::JoystickZeroUp );
|
||||
setDefaultAxis( 0, 1, 1, Event::JoystickZeroDown );
|
||||
// Left joystick (assume joystick zero, button zero)
|
||||
setDefaultBtn( 0, 0, Event::JoystickZeroFire );
|
||||
// Left joystick left/right directions (assume joystick zero and hat 0)
|
||||
setDefaultHat( 0, 0, JoyHat::LEFT, Event::JoystickZeroLeft );
|
||||
setDefaultHat( 0, 0, JoyHat::RIGHT, Event::JoystickZeroRight );
|
||||
// Left joystick up/down directions (assume joystick zero and hat 0)
|
||||
setDefaultHat( 0, 0, JoyHat::UP, Event::JoystickZeroUp );
|
||||
setDefaultHat( 0, 0, JoyHat::DOWN, Event::JoystickZeroDown );
|
||||
}
|
||||
else if(stick == 1)
|
||||
{
|
||||
// Right joystick left/right directions (assume joystick one)
|
||||
setDefaultAxis( 1, 0, 0, Event::JoystickOneLeft );
|
||||
setDefaultAxis( 1, 0, 1, Event::JoystickOneRight );
|
||||
// Right joystick left/right directions (assume joystick one)
|
||||
setDefaultAxis( 1, 1, 0, Event::JoystickOneUp );
|
||||
setDefaultAxis( 1, 1, 1, Event::JoystickOneDown );
|
||||
// Right joystick (assume joystick one, button zero)
|
||||
setDefaultBtn( 1, 0, Event::JoystickOneFire );
|
||||
// Right joystick left/right directions (assume joystick one and hat 0)
|
||||
setDefaultHat( 1, 0, JoyHat::LEFT, Event::JoystickOneLeft );
|
||||
setDefaultHat( 1, 0, JoyHat::RIGHT, Event::JoystickOneRight );
|
||||
// Right joystick up/down directions (assume joystick one and hat 0)
|
||||
setDefaultHat( 1, 0, JoyHat::UP, Event::JoystickOneUp );
|
||||
setDefaultHat( 1, 0, JoyHat::DOWN, Event::JoystickOneDown );
|
||||
}
|
||||
break;
|
||||
|
||||
case kMenuMode: // Default menu/UI events
|
||||
if(stick == 0)
|
||||
{
|
||||
setDefaultAxis( 0, 0, 0, Event::UILeft );
|
||||
setDefaultAxis( 0, 0, 1, Event::UIRight );
|
||||
setDefaultAxis( 0, 1, 0, Event::UIUp );
|
||||
setDefaultAxis( 0, 1, 1, Event::UIDown );
|
||||
|
||||
// Left joystick (assume joystick zero, button zero)
|
||||
setDefaultBtn( 0, 0, Event::UISelect );
|
||||
|
||||
setDefaultHat( 0, 0, JoyHat::LEFT, Event::UILeft );
|
||||
setDefaultHat( 0, 0, JoyHat::RIGHT, Event::UIRight );
|
||||
setDefaultHat( 0, 0, JoyHat::UP, Event::UIUp );
|
||||
setDefaultHat( 0, 0, JoyHat::DOWN, Event::UIDown );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::eraseMapping(Event::Type event, EventMode mode)
|
||||
{
|
||||
// If event is 'NoType', erase and reset all mappings
|
||||
// Otherwise, only reset the given event
|
||||
if(event == Event::NoType)
|
||||
{
|
||||
for(auto& stick: mySticks)
|
||||
stick.second->eraseMap(mode); // erase all events
|
||||
}
|
||||
else
|
||||
{
|
||||
for(auto& stick: mySticks)
|
||||
stick.second->eraseEvent(event, mode); // only reset the specific event
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::saveMapping()
|
||||
{
|
||||
// Save the joystick mapping hash table, making sure to update it with
|
||||
// any changes that have been made during the program run
|
||||
ostringstream joybuf;
|
||||
joybuf << Event::LastType;
|
||||
|
||||
for(const auto& i: myDatabase)
|
||||
{
|
||||
const string& map = i.second.joy ? i.second.joy->getMap() : i.second.mapping;
|
||||
if(map != "")
|
||||
joybuf << "^" << map;
|
||||
}
|
||||
myOSystem.settings().setValue("joymap", joybuf.str());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string PhysicalJoystickHandler::getMappingDesc(Event::Type event, EventMode mode) const
|
||||
{
|
||||
ostringstream buf;
|
||||
|
||||
for(const auto& s: mySticks)
|
||||
{
|
||||
uInt32 stick = s.first;
|
||||
const PhysicalJoystickPtr j = s.second;
|
||||
if(!j) continue;
|
||||
|
||||
// Joystick button mapping/labeling
|
||||
for(int button = 0; button < j->numButtons; ++button)
|
||||
{
|
||||
if(j->btnTable[button][mode] == event)
|
||||
{
|
||||
if(buf.str() != "")
|
||||
buf << ", ";
|
||||
buf << "J" << stick << "/B" << button;
|
||||
}
|
||||
}
|
||||
|
||||
// Joystick axis mapping/labeling
|
||||
for(int axis = 0; axis < j->numAxes; ++axis)
|
||||
{
|
||||
for(int dir = 0; dir < 2; ++dir)
|
||||
{
|
||||
if(j->axisTable[axis][dir][mode] == event)
|
||||
{
|
||||
if(buf.str() != "")
|
||||
buf << ", ";
|
||||
buf << "J" << stick << "/A" << axis;
|
||||
if(Event::isAnalog(event))
|
||||
{
|
||||
dir = 2; // Immediately exit the inner loop after this iteration
|
||||
buf << "/+|-";
|
||||
}
|
||||
else if(dir == 0)
|
||||
buf << "/-";
|
||||
else
|
||||
buf << "/+";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Joystick hat mapping/labeling
|
||||
for(int hat = 0; hat < j->numHats; ++hat)
|
||||
{
|
||||
for(int dir = 0; dir < 4; ++dir)
|
||||
{
|
||||
if(j->hatTable[hat][dir][mode] == event)
|
||||
{
|
||||
if(buf.str() != "")
|
||||
buf << ", ";
|
||||
buf << "J" << stick << "/H" << hat;
|
||||
switch(JoyHat(dir))
|
||||
{
|
||||
case JoyHat::UP: buf << "/up"; break;
|
||||
case JoyHat::DOWN: buf << "/down"; break;
|
||||
case JoyHat::LEFT: buf << "/left"; break;
|
||||
case JoyHat::RIGHT: buf << "/right"; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::addAxisMapping(Event::Type event, EventMode mode,
|
||||
int stick, int axis, int value)
|
||||
{
|
||||
const PhysicalJoystickPtr j = joy(stick);
|
||||
if(j)
|
||||
{
|
||||
if(axis >= 0 && axis < j->numAxes && event < Event::LastType)
|
||||
{
|
||||
// This confusing code is because each axis has two associated values,
|
||||
// but analog events only affect one of the axis.
|
||||
if(Event::isAnalog(event))
|
||||
j->axisTable[axis][0][mode] = j->axisTable[axis][1][mode] = event;
|
||||
else
|
||||
{
|
||||
// Otherwise, turn off the analog event(s) for this axis
|
||||
if(Event::isAnalog(j->axisTable[axis][0][mode]))
|
||||
j->axisTable[axis][0][mode] = Event::NoType;
|
||||
if(Event::isAnalog(j->axisTable[axis][1][mode]))
|
||||
j->axisTable[axis][1][mode] = Event::NoType;
|
||||
|
||||
j->axisTable[axis][(value > 0)][mode] = event;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::addBtnMapping(Event::Type event, EventMode mode,
|
||||
int stick, int button)
|
||||
{
|
||||
const PhysicalJoystickPtr j = joy(stick);
|
||||
if(j)
|
||||
{
|
||||
if(button >= 0 && button < j->numButtons && event < Event::LastType)
|
||||
{
|
||||
j->btnTable[button][mode] = event;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::addHatMapping(Event::Type event, EventMode mode,
|
||||
int stick, int hat, JoyHat value)
|
||||
{
|
||||
const PhysicalJoystickPtr j = joy(stick);
|
||||
if(j)
|
||||
{
|
||||
if(hat >= 0 && hat < j->numHats && event < Event::LastType &&
|
||||
value != JoyHat::CENTER)
|
||||
{
|
||||
j->hatTable[hat][int(value)][mode] = event;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::handleAxisEvent(int stick, int axis, int value)
|
||||
{
|
||||
const PhysicalJoystickPtr j = joy(stick);
|
||||
if(!j) return;
|
||||
|
||||
// Stelladaptors handle axis differently than regular joysticks
|
||||
switch(j->type)
|
||||
{
|
||||
case PhysicalJoystick::JT_REGULAR:
|
||||
if(myHandler.state() == EventHandlerState::EMULATION)
|
||||
{
|
||||
// Every axis event has two associated values, negative and positive
|
||||
Event::Type eventAxisNeg = j->axisTable[axis][0][kEmulationMode];
|
||||
Event::Type eventAxisPos = j->axisTable[axis][1][kEmulationMode];
|
||||
|
||||
// Check for analog events, which are handled differently
|
||||
// We'll pass them off as Stelladaptor events, and let the controllers
|
||||
// handle it
|
||||
switch(int(eventAxisNeg))
|
||||
{
|
||||
case Event::PaddleZeroAnalog:
|
||||
myEvent.set(Event::SALeftAxis0Value, value);
|
||||
break;
|
||||
case Event::PaddleOneAnalog:
|
||||
myEvent.set(Event::SALeftAxis1Value, value);
|
||||
break;
|
||||
case Event::PaddleTwoAnalog:
|
||||
myEvent.set(Event::SARightAxis0Value, value);
|
||||
break;
|
||||
case Event::PaddleThreeAnalog:
|
||||
myEvent.set(Event::SARightAxis1Value, value);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
// Otherwise, we know the event is digital
|
||||
if(value > Joystick::deadzone())
|
||||
myHandler.handleEvent(eventAxisPos, 1);
|
||||
else if(value < -Joystick::deadzone())
|
||||
myHandler.handleEvent(eventAxisNeg, 1);
|
||||
else
|
||||
{
|
||||
// Treat any deadzone value as zero
|
||||
value = 0;
|
||||
|
||||
// Now filter out consecutive, similar values
|
||||
// (only pass on the event if the state has changed)
|
||||
if(j->axisLastValue[axis] != value)
|
||||
{
|
||||
// Turn off both events, since we don't know exactly which one
|
||||
// was previously activated.
|
||||
myHandler.handleEvent(eventAxisNeg, 0);
|
||||
myHandler.handleEvent(eventAxisPos, 0);
|
||||
}
|
||||
}
|
||||
j->axisLastValue[axis] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(myHandler.hasOverlay())
|
||||
{
|
||||
// First, clamp the values to simulate digital input
|
||||
// (the only thing that the underlying code understands)
|
||||
if(value > Joystick::deadzone())
|
||||
value = 32000;
|
||||
else if(value < -Joystick::deadzone())
|
||||
value = -32000;
|
||||
else
|
||||
value = 0;
|
||||
|
||||
// Now filter out consecutive, similar values
|
||||
// (only pass on the event if the state has changed)
|
||||
if(value != j->axisLastValue[axis])
|
||||
{
|
||||
myHandler.overlay().handleJoyAxisEvent(stick, axis, value);
|
||||
j->axisLastValue[axis] = value;
|
||||
}
|
||||
}
|
||||
break; // Regular joystick axis
|
||||
|
||||
// Since the various controller classes deal with Stelladaptor
|
||||
// devices differently, we send the raw X and Y axis data directly,
|
||||
// and let the controller handle it
|
||||
// These events don't have to pass through handleEvent, since
|
||||
// they can never be remapped
|
||||
case PhysicalJoystick::JT_STELLADAPTOR_LEFT:
|
||||
case PhysicalJoystick::JT_2600DAPTOR_LEFT:
|
||||
if(axis < 2)
|
||||
myEvent.set(SA_Axis[0][axis], value);
|
||||
break; // axis on left controller (0)
|
||||
case PhysicalJoystick::JT_STELLADAPTOR_RIGHT:
|
||||
case PhysicalJoystick::JT_2600DAPTOR_RIGHT:
|
||||
if(axis < 2)
|
||||
myEvent.set(SA_Axis[1][axis], value);
|
||||
break; // axis on right controller (1)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::handleBtnEvent(int stick, int button, uInt8 state)
|
||||
{
|
||||
const PhysicalJoystickPtr j = joy(stick);
|
||||
if(!j) return;
|
||||
|
||||
// Stelladaptors handle buttons differently than regular joysticks
|
||||
switch(j->type)
|
||||
{
|
||||
case PhysicalJoystick::JT_REGULAR:
|
||||
// Handle buttons which switch eventhandler state
|
||||
if(state && myHandler.changeStateByEvent(j->btnTable[button][kEmulationMode]))
|
||||
return;
|
||||
|
||||
// Determine which mode we're in, then send the event to the appropriate place
|
||||
if(myHandler.state() == EventHandlerState::EMULATION)
|
||||
myHandler.handleEvent(j->btnTable[button][kEmulationMode], state);
|
||||
else if(myHandler.hasOverlay())
|
||||
myHandler.overlay().handleJoyBtnEvent(stick, button, state);
|
||||
break; // Regular button
|
||||
|
||||
// These events don't have to pass through handleEvent, since
|
||||
// they can never be remapped
|
||||
case PhysicalJoystick::JT_STELLADAPTOR_LEFT:
|
||||
case PhysicalJoystick::JT_STELLADAPTOR_RIGHT:
|
||||
// The 'type-2' here refers to the fact that 'PhysicalJoystick::JT_STELLADAPTOR_LEFT'
|
||||
// and 'PhysicalJoystick::JT_STELLADAPTOR_RIGHT' are at index 2 and 3 in the JoyType
|
||||
// enum; subtracting two gives us Controller 0 and 1
|
||||
if(button < 2) myEvent.set(SA_Button[j->type-2][button], state);
|
||||
break; // Stelladaptor button
|
||||
case PhysicalJoystick::JT_2600DAPTOR_LEFT:
|
||||
case PhysicalJoystick::JT_2600DAPTOR_RIGHT:
|
||||
// The 'type-4' here refers to the fact that 'PhysicalJoystick::JT_2600DAPTOR_LEFT'
|
||||
// and 'PhysicalJoystick::JT_2600DAPTOR_RIGHT' are at index 4 and 5 in the JoyType
|
||||
// enum; subtracting four gives us Controller 0 and 1
|
||||
if(myHandler.state() == EventHandlerState::EMULATION)
|
||||
{
|
||||
switch(myOSystem.console().leftController().type())
|
||||
{
|
||||
case Controller::Keyboard:
|
||||
if(button < 12) myEvent.set(SA_Key[j->type-4][button], state);
|
||||
break;
|
||||
default:
|
||||
if(button < 4) myEvent.set(SA_Button[j->type-4][button], state);
|
||||
}
|
||||
switch(myOSystem.console().rightController().type())
|
||||
{
|
||||
case Controller::Keyboard:
|
||||
if(button < 12) myEvent.set(SA_Key[j->type-4][button], state);
|
||||
break;
|
||||
default:
|
||||
if(button < 4) myEvent.set(SA_Button[j->type-4][button], state);
|
||||
}
|
||||
}
|
||||
break; // 2600DAPTOR button
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::handleHatEvent(int stick, int hat, int value)
|
||||
{
|
||||
// Preprocess all hat events, converting to Stella JoyHat type
|
||||
// Generate multiple equivalent hat events representing combined direction
|
||||
// when we get a diagonal hat event
|
||||
if(myHandler.state() == EventHandlerState::EMULATION)
|
||||
{
|
||||
const PhysicalJoystickPtr j = joy(stick);
|
||||
if(!j) return;
|
||||
|
||||
myHandler.handleEvent(j->hatTable[hat][int(JoyHat::UP)][kEmulationMode],
|
||||
value & EVENT_HATUP_M);
|
||||
myHandler.handleEvent(j->hatTable[hat][int(JoyHat::RIGHT)][kEmulationMode],
|
||||
value & EVENT_HATRIGHT_M);
|
||||
myHandler.handleEvent(j->hatTable[hat][int(JoyHat::DOWN)][kEmulationMode],
|
||||
value & EVENT_HATDOWN_M);
|
||||
myHandler.handleEvent(j->hatTable[hat][int(JoyHat::LEFT)][kEmulationMode],
|
||||
value & EVENT_HATLEFT_M);
|
||||
}
|
||||
else if(myHandler.hasOverlay())
|
||||
{
|
||||
if(value == EVENT_HATCENTER_M)
|
||||
myHandler.overlay().handleJoyHatEvent(stick, hat, JoyHat::CENTER);
|
||||
else
|
||||
{
|
||||
if(value & EVENT_HATUP_M)
|
||||
myHandler.overlay().handleJoyHatEvent(stick, hat, JoyHat::UP);
|
||||
if(value & EVENT_HATRIGHT_M)
|
||||
myHandler.overlay().handleJoyHatEvent(stick, hat, JoyHat::RIGHT);
|
||||
if(value & EVENT_HATDOWN_M)
|
||||
myHandler.overlay().handleJoyHatEvent(stick, hat, JoyHat::DOWN);
|
||||
if(value & EVENT_HATLEFT_M)
|
||||
myHandler.overlay().handleJoyHatEvent(stick, hat, JoyHat::LEFT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
VariantList PhysicalJoystickHandler::database() const
|
||||
{
|
||||
VariantList db;
|
||||
for(const auto& i: myDatabase)
|
||||
VarList::push_back(db, i.first, i.second.joy ? i.second.joy->ID : -1);
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ostream& operator<<(ostream& os, const PhysicalJoystickHandler& jh)
|
||||
{
|
||||
os << "---------------------------------------------------------" << endl
|
||||
<< "joy database:" << endl;
|
||||
for(const auto& i: jh.myDatabase)
|
||||
os << i.first << endl << i.second << endl << endl;
|
||||
|
||||
os << "---------------------" << endl
|
||||
<< "joy active:" << endl;
|
||||
for(const auto& i: jh.mySticks)
|
||||
os << i.first << ": " << *i.second << endl;
|
||||
os << "---------------------------------------------------------"
|
||||
<< endl << endl << endl;
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Used by the Stelladaptor to send absolute axis values
|
||||
const Event::Type PhysicalJoystickHandler::SA_Axis[2][2] = {
|
||||
{ Event::SALeftAxis0Value, Event::SALeftAxis1Value },
|
||||
{ Event::SARightAxis0Value, Event::SARightAxis1Value }
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Used by the Stelladaptor to map button presses to joystick or paddles
|
||||
// (driving controllers and boostergrip are considered the same as joysticks)
|
||||
const Event::Type PhysicalJoystickHandler::SA_Button[2][4] = {
|
||||
{ Event::JoystickZeroFire, Event::JoystickZeroFire9,
|
||||
Event::JoystickZeroFire5, Event::JoystickZeroFire9 },
|
||||
{ Event::JoystickOneFire, Event::JoystickOneFire9,
|
||||
Event::JoystickOneFire5, Event::JoystickOneFire9 }
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Used by the 2600-daptor to map button presses to keypad keys
|
||||
const Event::Type PhysicalJoystickHandler::SA_Key[2][12] = {
|
||||
{ Event::KeyboardZero1, Event::KeyboardZero2, Event::KeyboardZero3,
|
||||
Event::KeyboardZero4, Event::KeyboardZero5, Event::KeyboardZero6,
|
||||
Event::KeyboardZero7, Event::KeyboardZero8, Event::KeyboardZero9,
|
||||
Event::KeyboardZeroStar, Event::KeyboardZero0, Event::KeyboardZeroPound },
|
||||
{ Event::KeyboardOne1, Event::KeyboardOne2, Event::KeyboardOne3,
|
||||
Event::KeyboardOne4, Event::KeyboardOne5, Event::KeyboardOne6,
|
||||
Event::KeyboardOne7, Event::KeyboardOne8, Event::KeyboardOne9,
|
||||
Event::KeyboardOneStar, Event::KeyboardOne0, Event::KeyboardOnePound }
|
||||
};
|
|
@ -0,0 +1,134 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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_JOYSTICK_HANDLER_HXX
|
||||
#define PHYSICAL_JOYSTICK_HANDLER_HXX
|
||||
|
||||
#include <map>
|
||||
|
||||
class OSystem;
|
||||
class EventHandler;
|
||||
class Event;
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "EventHandlerConstants.hxx"
|
||||
#include "PhysicalJoystick.hxx"
|
||||
#include "Variant.hxx"
|
||||
|
||||
using PhysicalJoystickPtr = shared_ptr<PhysicalJoystick>;
|
||||
|
||||
/**
|
||||
This class handles all physical joystick-related operations in Stella.
|
||||
|
||||
It is responsible for adding/accessing/removing PhysicalJoystick objects,
|
||||
and getting/setting events associated with joystick actions (button presses,
|
||||
axis/hat actions, etc).
|
||||
|
||||
Essentially, this class is an extension of the EventHandler class, but
|
||||
handling only joystick-specific functionality.
|
||||
|
||||
@author Stephen Anthony
|
||||
*/
|
||||
class PhysicalJoystickHandler
|
||||
{
|
||||
private:
|
||||
struct StickInfo
|
||||
{
|
||||
StickInfo(const string& map = EmptyString, PhysicalJoystickPtr stick = nullptr)
|
||||
: mapping(map), joy(stick) {}
|
||||
|
||||
string mapping;
|
||||
PhysicalJoystickPtr joy;
|
||||
|
||||
friend ostream& operator<<(ostream& os, const StickInfo& si) {
|
||||
os << " joy: " << si.joy << endl << " map: " << si.mapping;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
PhysicalJoystickHandler(OSystem& system, EventHandler& handler, Event& event);
|
||||
|
||||
/** Return stick ID on success, -1 on failure. */
|
||||
int add(PhysicalJoystickPtr stick);
|
||||
bool remove(int id);
|
||||
bool remove(const string& name);
|
||||
void mapStelladaptors(const string& saport);
|
||||
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 joystick event to a virtual event/action. */
|
||||
bool addAxisMapping(Event::Type event, EventMode mode, int stick, int axis, int value);
|
||||
bool addBtnMapping(Event::Type event, EventMode mode, int stick, int button);
|
||||
bool addHatMapping(Event::Type event, EventMode mode, int stick, int hat, JoyHat value);
|
||||
|
||||
/** Handle a physical joystick event. */
|
||||
void handleAxisEvent(int stick, int axis, int value);
|
||||
void handleBtnEvent(int stick, int button, uInt8 state);
|
||||
void handleHatEvent(int stick, int hat, int value);
|
||||
|
||||
Event::Type eventForAxis(int stick, int axis, int value, EventMode mode) const {
|
||||
const PhysicalJoystickPtr j = joy(stick);
|
||||
return j ? j->axisTable[axis][(value > 0)][mode] : Event::NoType;
|
||||
}
|
||||
Event::Type eventForButton(int stick, int button, EventMode mode) const {
|
||||
const PhysicalJoystickPtr j = joy(stick);
|
||||
return j ? j->btnTable[button][mode] : Event::NoType;
|
||||
}
|
||||
Event::Type eventForHat(int stick, int hat, JoyHat value, EventMode mode) const {
|
||||
const PhysicalJoystickPtr j = joy(stick);
|
||||
return j ? j->hatTable[hat][int(value)][mode] : Event::NoType;
|
||||
}
|
||||
|
||||
/** Returns a list of pairs consisting of joystick name and associated ID. */
|
||||
VariantList database() const;
|
||||
|
||||
private:
|
||||
using StickDatabase = std::map<string,StickInfo>;
|
||||
using StickList = std::map<int, PhysicalJoystickPtr>;
|
||||
|
||||
OSystem& myOSystem;
|
||||
EventHandler& myHandler;
|
||||
Event& myEvent;
|
||||
|
||||
// Contains all joysticks that Stella knows about, indexed by name
|
||||
StickDatabase myDatabase;
|
||||
|
||||
// Contains only joysticks that are currently available, indexed by id
|
||||
StickList mySticks;
|
||||
|
||||
// Get joystick corresponding to given id (or nullptr if it doesn't exist)
|
||||
// Make this inline so it's as fast as possible
|
||||
const PhysicalJoystickPtr joy(int id) const {
|
||||
const auto& i = mySticks.find(id);
|
||||
return i != mySticks.cend() ? i->second : nullptr;
|
||||
}
|
||||
|
||||
// Set default mapping for given joystick when no mappings already exist
|
||||
void setStickDefaultMapping(int stick, Event::Type type, EventMode mode);
|
||||
|
||||
friend ostream& operator<<(ostream& os, const PhysicalJoystickHandler& jh);
|
||||
|
||||
// Static lookup tables for Stelladaptor/2600-daptor axis/button support
|
||||
static const Event::Type SA_Axis[2][2];
|
||||
static const Event::Type SA_Button[2][4];
|
||||
static const Event::Type SA_Key[2][12];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,614 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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 "DialogContainer.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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -0,0 +1,229 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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 <map>
|
||||
|
||||
#include "OSystem.hxx"
|
||||
#include "Settings.hxx"
|
||||
#include "Vec.hxx"
|
||||
#include "bspf.hxx"
|
||||
#include "PhysicalJoystick.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PhysicalJoystick::PhysicalJoystick()
|
||||
: type(JT_NONE),
|
||||
ID(-1),
|
||||
name("None"),
|
||||
numAxes(0),
|
||||
numButtons(0),
|
||||
numHats(0),
|
||||
axisTable(nullptr),
|
||||
btnTable(nullptr),
|
||||
hatTable(nullptr),
|
||||
axisLastValue(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PhysicalJoystick::~PhysicalJoystick()
|
||||
{
|
||||
delete[] axisTable;
|
||||
delete[] btnTable;
|
||||
delete[] hatTable;
|
||||
delete[] axisLastValue;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystick::initialize(int index, const string& desc,
|
||||
int axes, int buttons, int hats, int /*balls*/)
|
||||
{
|
||||
ID = index;
|
||||
name = desc;
|
||||
|
||||
// Dynamically create the various mapping arrays for this joystick,
|
||||
// based on its specific attributes
|
||||
numAxes = axes;
|
||||
numButtons = buttons;
|
||||
numHats = hats;
|
||||
if(numAxes)
|
||||
axisTable = new Event::Type[numAxes][2][kNumModes];
|
||||
if(numButtons)
|
||||
btnTable = new Event::Type[numButtons][kNumModes];
|
||||
if(numHats)
|
||||
hatTable = new Event::Type[numHats][4][kNumModes];
|
||||
axisLastValue = new int[numAxes];
|
||||
|
||||
// Erase the joystick axis mapping array and last axis value
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
{
|
||||
axisLastValue[a] = 0;
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
axisTable[a][0][m] = axisTable[a][1][m] = Event::NoType;
|
||||
}
|
||||
|
||||
// Erase the joystick button mapping array
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
btnTable[b][m] = Event::NoType;
|
||||
|
||||
// Erase the joystick hat mapping array
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
hatTable[h][0][m] = hatTable[h][1][m] =
|
||||
hatTable[h][2][m] = hatTable[h][3][m] = Event::NoType;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string PhysicalJoystick::getMap() const
|
||||
{
|
||||
// The mapping structure (for remappable devices) is defined as follows:
|
||||
// NAME | AXIS # + values | BUTTON # + values | HAT # + values,
|
||||
// where each subsection of values is separated by ':'
|
||||
if(type == JT_REGULAR)
|
||||
{
|
||||
ostringstream joybuf;
|
||||
joybuf << name << "|" << numAxes;
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
for(int k = 0; k < 2; ++k)
|
||||
joybuf << " " << axisTable[a][k][m];
|
||||
joybuf << "|" << numButtons;
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
joybuf << " " << btnTable[b][m];
|
||||
joybuf << "|" << numHats;
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
for(int k = 0; k < 4; ++k)
|
||||
joybuf << " " << hatTable[h][k][m];
|
||||
|
||||
return joybuf.str();
|
||||
}
|
||||
return EmptyString;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystick::setMap(const string& mapString)
|
||||
{
|
||||
istringstream buf(mapString);
|
||||
StringList items;
|
||||
string item;
|
||||
while(getline(buf, item, '|'))
|
||||
items.push_back(item);
|
||||
|
||||
// Error checking
|
||||
if(items.size() != 4)
|
||||
return false;
|
||||
|
||||
IntArray map;
|
||||
|
||||
// Parse axis/button/hat values
|
||||
getValues(items[1], map);
|
||||
if(int(map.size()) == numAxes * 2 * kNumModes)
|
||||
{
|
||||
// Fill the axes table with events
|
||||
auto event = map.cbegin();
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
for(int k = 0; k < 2; ++k)
|
||||
axisTable[a][k][m] = Event::Type(*event++);
|
||||
}
|
||||
getValues(items[2], map);
|
||||
if(int(map.size()) == numButtons * kNumModes)
|
||||
{
|
||||
auto event = map.cbegin();
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
btnTable[b][m] = Event::Type(*event++);
|
||||
}
|
||||
getValues(items[3], map);
|
||||
if(int(map.size()) == numHats * 4 * kNumModes)
|
||||
{
|
||||
auto event = map.cbegin();
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
for(int k = 0; k < 4; ++k)
|
||||
hatTable[h][k][m] = Event::Type(*event++);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystick::eraseMap(EventMode mode)
|
||||
{
|
||||
// Erase axis mappings
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
axisTable[a][0][mode] = axisTable[a][1][mode] = Event::NoType;
|
||||
|
||||
// Erase button mappings
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
btnTable[b][mode] = Event::NoType;
|
||||
|
||||
// Erase hat mappings
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
hatTable[h][0][mode] = hatTable[h][1][mode] =
|
||||
hatTable[h][2][mode] = hatTable[h][3][mode] = Event::NoType;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystick::eraseEvent(Event::Type event, EventMode mode)
|
||||
{
|
||||
// Erase axis mappings
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
{
|
||||
if(axisTable[a][0][mode] == event) axisTable[a][0][mode] = Event::NoType;
|
||||
if(axisTable[a][1][mode] == event) axisTable[a][1][mode] = Event::NoType;
|
||||
}
|
||||
|
||||
// Erase button mappings
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
if(btnTable[b][mode] == event) btnTable[b][mode] = Event::NoType;
|
||||
|
||||
// Erase hat mappings
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
{
|
||||
if(hatTable[h][0][mode] == event) hatTable[h][0][mode] = Event::NoType;
|
||||
if(hatTable[h][1][mode] == event) hatTable[h][1][mode] = Event::NoType;
|
||||
if(hatTable[h][2][mode] == event) hatTable[h][2][mode] = Event::NoType;
|
||||
if(hatTable[h][3][mode] == event) hatTable[h][3][mode] = Event::NoType;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystick::getValues(const string& list, IntArray& map) const
|
||||
{
|
||||
map.clear();
|
||||
istringstream buf(list);
|
||||
|
||||
int value;
|
||||
buf >> value; // we don't need to know the # of items at this point
|
||||
while(buf >> value)
|
||||
map.push_back(value);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string PhysicalJoystick::about() const
|
||||
{
|
||||
ostringstream buf;
|
||||
buf << name;
|
||||
if(type == JT_REGULAR)
|
||||
buf << " with: " << numAxes << " axes, " << numButtons << " buttons, "
|
||||
<< numHats << " hats";
|
||||
|
||||
return buf.str();
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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_JOYSTICK_HXX
|
||||
#define PHYSICAL_JOYSTICK_HXX
|
||||
|
||||
#include "Event.hxx"
|
||||
#include "EventHandlerConstants.hxx"
|
||||
|
||||
/**
|
||||
An abstraction of a physical (real) joystick in Stella.
|
||||
|
||||
A PhysicalJoystick holds its own event mapping information, space for
|
||||
which is dynamically allocated based on the actual number of buttons,
|
||||
axes, etc that the device contains.
|
||||
|
||||
Specific backend class(es) will inherit from this class, and implement
|
||||
functionality specific to the device.
|
||||
|
||||
@author Stephen Anthony
|
||||
*/
|
||||
class PhysicalJoystick
|
||||
{
|
||||
friend class PhysicalJoystickHandler;
|
||||
|
||||
public:
|
||||
PhysicalJoystick();
|
||||
virtual ~PhysicalJoystick();
|
||||
|
||||
string getMap() const;
|
||||
bool setMap(const string& map);
|
||||
void eraseMap(EventMode mode);
|
||||
void eraseEvent(Event::Type event, EventMode mode);
|
||||
string about() const;
|
||||
|
||||
protected:
|
||||
void initialize(int index, const string& desc,
|
||||
int axes, int buttons, int hats, int balls);
|
||||
|
||||
private:
|
||||
enum JoyType {
|
||||
JT_NONE = 0,
|
||||
JT_REGULAR = 1,
|
||||
JT_STELLADAPTOR_LEFT = 2,
|
||||
JT_STELLADAPTOR_RIGHT = 3,
|
||||
JT_2600DAPTOR_LEFT = 4,
|
||||
JT_2600DAPTOR_RIGHT = 5
|
||||
};
|
||||
|
||||
JoyType type;
|
||||
int ID;
|
||||
string name;
|
||||
int numAxes, numButtons, numHats;
|
||||
Event::Type (*axisTable)[2][kNumModes];
|
||||
Event::Type (*btnTable)[kNumModes];
|
||||
Event::Type (*hatTable)[4][kNumModes];
|
||||
int* axisLastValue;
|
||||
|
||||
private:
|
||||
void getValues(const string& list, IntArray& map) const;
|
||||
|
||||
friend ostream& operator<<(ostream& os, const PhysicalJoystick& s) {
|
||||
os << " ID: " << s.ID << ", name: " << s.name << ", numaxis: " << s.numAxes
|
||||
<< ", numbtns: " << s.numButtons << ", numhats: " << s.numHats;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -177,8 +177,8 @@ class RewindManager
|
|||
|
||||
// We do nothing on object instantiation or copy
|
||||
// The goal of LinkedObjectPool is to not do any allocations at all
|
||||
RewindState() { }
|
||||
RewindState(const RewindState&) { }
|
||||
RewindState() : cycles(0) { }
|
||||
RewindState(const RewindState& rs) : cycles(rs.cycles) { }
|
||||
|
||||
// Output object info; used for debugging only
|
||||
friend ostream& operator<<(ostream& os, const RewindState& s) {
|
||||
|
|
|
@ -49,6 +49,13 @@ SoundSDL2::SoundSDL2(OSystem& osystem)
|
|||
{
|
||||
myOSystem.logMessage("SoundSDL2::SoundSDL2 started ...", 2);
|
||||
|
||||
#ifdef BSPF_WINDOWS
|
||||
// TODO - remove the following code once we convert to the new sound
|
||||
// core, and use 32-bit floating point samples and do
|
||||
// our own resampling
|
||||
SDL_setenv("SDL_AUDIODRIVER", "directsound", true);
|
||||
#endif
|
||||
|
||||
// The sound system is opened only once per program run, to eliminate
|
||||
// issues with opening and closing it multiple times
|
||||
// This fixes a bug most prevalent with ATI video cards in Windows,
|
||||
|
|
|
@ -435,4 +435,12 @@ namespace StellaModTest
|
|||
}
|
||||
};
|
||||
|
||||
namespace StellaKeyName
|
||||
{
|
||||
inline const char* const forKey(StellaKey key)
|
||||
{
|
||||
return SDL_GetScancodeName(SDL_Scancode(key));
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* StellaKeys */
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "Settings.hxx"
|
||||
#include "FSNode.hxx"
|
||||
#include "OSystem.hxx"
|
||||
#include "PNGLibrary.hxx"
|
||||
#include "System.hxx"
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
|
@ -124,15 +125,22 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
else
|
||||
{
|
||||
const string& result = theOSystem->createConsole(romnode);
|
||||
if(result != EmptyString)
|
||||
return Cleanup();
|
||||
|
||||
if(theOSystem->settings().getBool("takesnapshot"))
|
||||
try
|
||||
{
|
||||
theOSystem->logMessage("Taking snapshots with 'takesnapshot' ...", 2);
|
||||
for(int i = 0; i < 30; ++i) theOSystem->frameBuffer().update();
|
||||
theOSystem->eventHandler().takeSnapshot();
|
||||
const string& result = theOSystem->createConsole(romnode);
|
||||
if(result != EmptyString)
|
||||
return Cleanup();
|
||||
|
||||
if(theOSystem->settings().getBool("takesnapshot"))
|
||||
{
|
||||
for(int i = 0; i < 30; ++i) theOSystem->frameBuffer().update();
|
||||
theOSystem->png().takeSnapshot();
|
||||
return Cleanup();
|
||||
}
|
||||
}
|
||||
catch(const runtime_error& e)
|
||||
{
|
||||
theOSystem->logMessage(e.what(), 0);
|
||||
return Cleanup();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
MODULE := src/common
|
||||
|
||||
MODULE_OBJS := \
|
||||
src/common/main.o \
|
||||
src/common/Base.o \
|
||||
src/common/EventHandlerSDL2.o \
|
||||
src/common/FrameBufferSDL2.o \
|
||||
src/common/FBSurfaceSDL2.o \
|
||||
src/common/SoundSDL2.o \
|
||||
src/common/FrameBufferSDL2.o \
|
||||
src/common/FSNodeZIP.o \
|
||||
src/common/PNGLibrary.o \
|
||||
src/common/main.o \
|
||||
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 \
|
||||
src/common/StateManager.o \
|
||||
src/common/ZipHandler.o \
|
||||
src/common/AudioQueue.o
|
||||
|
|
|
@ -184,6 +184,8 @@ class AtariNTSC
|
|||
float artifacts;
|
||||
float fringing;
|
||||
float kernel [rescale_out * kernel_size * 2];
|
||||
|
||||
init_t() : contrast(0.0), brightness(0.0), artifacts(0.0), fringing(0.0) { }
|
||||
};
|
||||
init_t myImpl;
|
||||
|
||||
|
|
|
@ -735,7 +735,7 @@ string CartDebug::loadListFile()
|
|||
|
||||
getline(in, line);
|
||||
|
||||
if(line.length() == 0 || line[0] == '-')
|
||||
if(!in.good() || line == "" || line[0] == '-')
|
||||
continue;
|
||||
else // Search for constants
|
||||
{
|
||||
|
@ -798,6 +798,7 @@ string CartDebug::loadSymbolFile()
|
|||
int value = -1;
|
||||
|
||||
getline(in, label);
|
||||
if(!in.good()) continue;
|
||||
stringstream buf(label);
|
||||
buf >> label >> hex >> value;
|
||||
|
||||
|
|
|
@ -226,9 +226,9 @@ const string Debugger::invIfChanged(int reg, int oldReg)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::reset()
|
||||
{
|
||||
unlockBankswitchState();
|
||||
unlockSystem();
|
||||
mySystem.reset();
|
||||
lockBankswitchState();
|
||||
lockSystem();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -253,21 +253,21 @@ string Debugger::setRAM(IntArray& args)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::saveState(int state)
|
||||
{
|
||||
mySystem.clearDirtyPages();
|
||||
|
||||
unlockBankswitchState();
|
||||
// Saving a state is implicitly a read-only operation, so we keep the
|
||||
// system locked, so no changes can occur
|
||||
myOSystem.state().saveState(state);
|
||||
lockBankswitchState();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::loadState(int state)
|
||||
{
|
||||
// We're loading a new state, so we start with a clean slate
|
||||
mySystem.clearDirtyPages();
|
||||
|
||||
unlockBankswitchState();
|
||||
// State loading could initiate a bankswitch, so we allow it temporarily
|
||||
unlockSystem();
|
||||
myOSystem.state().loadState(state);
|
||||
lockBankswitchState();
|
||||
lockSystem();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -277,9 +277,9 @@ int Debugger::step()
|
|||
|
||||
uInt64 startCycle = mySystem.cycles();
|
||||
|
||||
unlockBankswitchState();
|
||||
unlockSystem();
|
||||
myOSystem.console().tia().updateScanlineByStep().flushLineCache();
|
||||
lockBankswitchState();
|
||||
lockSystem();
|
||||
|
||||
addState("step");
|
||||
return int(mySystem.cycles() - startCycle);
|
||||
|
@ -305,9 +305,9 @@ int Debugger::trace()
|
|||
uInt64 startCycle = mySystem.cycles();
|
||||
int targetPC = myCpuDebug->pc() + 3; // return address
|
||||
|
||||
unlockBankswitchState();
|
||||
unlockSystem();
|
||||
myOSystem.console().tia().updateScanlineByTrace(targetPC).flushLineCache();
|
||||
lockBankswitchState();
|
||||
lockSystem();
|
||||
|
||||
addState("trace");
|
||||
return int(mySystem.cycles() - startCycle);
|
||||
|
@ -490,13 +490,13 @@ void Debugger::nextScanline(int lines)
|
|||
|
||||
saveOldState();
|
||||
|
||||
unlockBankswitchState();
|
||||
unlockSystem();
|
||||
while(lines)
|
||||
{
|
||||
myOSystem.console().tia().updateScanline();
|
||||
--lines;
|
||||
}
|
||||
lockBankswitchState();
|
||||
lockSystem();
|
||||
|
||||
addState(buf.str());
|
||||
myOSystem.console().tia().flushLineCache();
|
||||
|
@ -510,13 +510,13 @@ void Debugger::nextFrame(int frames)
|
|||
|
||||
saveOldState();
|
||||
|
||||
unlockBankswitchState();
|
||||
unlockSystem();
|
||||
while(frames)
|
||||
{
|
||||
myOSystem.console().tia().update();
|
||||
--frames;
|
||||
}
|
||||
lockBankswitchState();
|
||||
lockSystem();
|
||||
|
||||
addState(buf.str());
|
||||
}
|
||||
|
@ -535,13 +535,13 @@ uInt16 Debugger::windStates(uInt16 numStates, bool unwind, string& message)
|
|||
|
||||
saveOldState();
|
||||
|
||||
unlockBankswitchState();
|
||||
unlockSystem();
|
||||
|
||||
uInt64 startCycles = myOSystem.console().tia().cycles();
|
||||
uInt16 winds = r.windStates(numStates, unwind);
|
||||
message = r.getUnitString(myOSystem.console().tia().cycles() - startCycles);
|
||||
|
||||
lockBankswitchState();
|
||||
lockSystem();
|
||||
|
||||
updateRewindbuttons(r);
|
||||
return winds;
|
||||
|
@ -593,13 +593,15 @@ bool Debugger::patchROM(uInt16 addr, uInt8 value)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::saveOldState(bool clearDirtyPages)
|
||||
{
|
||||
if (clearDirtyPages)
|
||||
if(clearDirtyPages)
|
||||
mySystem.clearDirtyPages();
|
||||
|
||||
lockSystem();
|
||||
myCartDebug->saveOldState();
|
||||
myCpuDebug->saveOldState();
|
||||
myRiotDebug->saveOldState();
|
||||
myTiaDebug->saveOldState();
|
||||
unlockSystem();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -615,7 +617,7 @@ void Debugger::addState(string rewindMsg)
|
|||
void Debugger::setStartState()
|
||||
{
|
||||
// Lock the bus each time the debugger is entered, so we don't disturb anything
|
||||
lockBankswitchState();
|
||||
lockSystem();
|
||||
|
||||
// Save initial state and add it to the rewind list (except when in currently rewinding)
|
||||
RewindManager& r = myOSystem.state().rewindManager();
|
||||
|
@ -636,7 +638,7 @@ void Debugger::setQuitState()
|
|||
saveOldState();
|
||||
|
||||
// Bus must be unlocked for normal operation when leaving debugger mode
|
||||
unlockBankswitchState();
|
||||
unlockSystem();
|
||||
|
||||
// execute one instruction on quit. If we're
|
||||
// sitting at a breakpoint/trap, this will get us past it.
|
||||
|
@ -771,14 +773,14 @@ void Debugger::getCompletions(const char* in, StringList& list) const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::lockBankswitchState()
|
||||
void Debugger::lockSystem()
|
||||
{
|
||||
mySystem.lockDataBus();
|
||||
myConsole.cartridge().lockBank();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::unlockBankswitchState()
|
||||
void Debugger::unlockSystem()
|
||||
{
|
||||
mySystem.unlockDataBus();
|
||||
myConsole.cartridge().unlockBank();
|
||||
|
|
|
@ -231,14 +231,13 @@ class Debugger : public DialogContainer
|
|||
|
||||
/**
|
||||
Normally, accessing RAM or ROM during emulation can possibly trigger
|
||||
bankswitching. However, when we're in the debugger, we'd like to
|
||||
inspect values without actually triggering bankswitches. The
|
||||
bankswitching or other inadvertent changes. However, when we're in
|
||||
the debugger, we'd like to inspect values without restriction. The
|
||||
read/write state must therefore be locked before accessing values,
|
||||
and unlocked for normal emulation to occur.
|
||||
(takes mediasource into account)
|
||||
*/
|
||||
void lockBankswitchState();
|
||||
void unlockBankswitchState();
|
||||
void lockSystem();
|
||||
void unlockSystem();
|
||||
|
||||
/**
|
||||
Answers whether the debugger can be exited. Currently this only
|
||||
|
|
|
@ -58,6 +58,7 @@ using std::right;
|
|||
DebuggerParser::DebuggerParser(Debugger& d, Settings& s)
|
||||
: debugger(d),
|
||||
settings(s),
|
||||
myCommand(0),
|
||||
argCount(0),
|
||||
execDepth(0),
|
||||
execPrefix("")
|
||||
|
@ -1459,13 +1460,10 @@ void DebuggerParser::executeListfunctions()
|
|||
void DebuggerParser::executeListsavestateifs()
|
||||
{
|
||||
ostringstream buf;
|
||||
int count = 0;
|
||||
|
||||
StringList conds = debugger.m6502().getCondSaveStateNames();
|
||||
if(conds.size() > 0)
|
||||
{
|
||||
if(count)
|
||||
commandResult << endl;
|
||||
commandResult << "savestateif:" << endl;
|
||||
for(uInt32 i = 0; i < conds.size(); i++)
|
||||
{
|
||||
|
|
|
@ -26,8 +26,11 @@ CartridgeMNetworkWidget::CartridgeMNetworkWidget(
|
|||
int x, int y, int w, int h,
|
||||
CartridgeMNetwork& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
{}
|
||||
myCart(cart),
|
||||
myLower2K(nullptr),
|
||||
myUpper256B(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeMNetworkWidget::initialize(GuiObject* boss, CartridgeMNetwork& cart, ostringstream& info)
|
||||
|
|
|
@ -34,11 +34,11 @@ class CartridgeMNetworkWidget : public CartDebugWidget
|
|||
virtual ~CartridgeMNetworkWidget() = default;
|
||||
|
||||
protected:
|
||||
PopUpWidget *myLower2K, *myUpper256B;
|
||||
|
||||
//CartridgeE7& myCart;
|
||||
CartridgeMNetwork& myCart;
|
||||
|
||||
PopUpWidget *myLower2K, *myUpper256B;
|
||||
|
||||
struct CartState
|
||||
{
|
||||
ByteArray internalram;
|
||||
|
|
|
@ -64,11 +64,15 @@ void DrivingWidget::loadConfig()
|
|||
if(myController.read(Controller::Two)) gray += 2;
|
||||
|
||||
for(myGrayIndex = 0; myGrayIndex < 4; ++myGrayIndex)
|
||||
{
|
||||
if(ourGrayTable[myGrayIndex] == gray)
|
||||
{
|
||||
setValue(myGrayIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
myFire->setState(!myController.read(Controller::Six));
|
||||
setValue();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -81,13 +85,13 @@ void DrivingWidget::handleCommand(
|
|||
myGrayIndex = (myGrayIndex + 1) % 4;
|
||||
myController.set(Controller::One, (ourGrayTable[myGrayIndex] & 0x1) != 0);
|
||||
myController.set(Controller::Two, (ourGrayTable[myGrayIndex] & 0x2) != 0);
|
||||
setValue();
|
||||
setValue(myGrayIndex);
|
||||
break;
|
||||
case kGrayDownCmd:
|
||||
myGrayIndex = myGrayIndex == 0 ? 3 : myGrayIndex - 1;
|
||||
myController.set(Controller::One, (ourGrayTable[myGrayIndex] & 0x1) != 0);
|
||||
myController.set(Controller::Two, (ourGrayTable[myGrayIndex] & 0x2) != 0);
|
||||
setValue();
|
||||
setValue(myGrayIndex);
|
||||
break;
|
||||
case kFireCmd:
|
||||
myController.set(Controller::Six, !myFire->getState());
|
||||
|
@ -96,9 +100,9 @@ void DrivingWidget::handleCommand(
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DrivingWidget::setValue()
|
||||
void DrivingWidget::setValue(int idx)
|
||||
{
|
||||
int grayCode = ourGrayTable[myGrayIndex];
|
||||
int grayCode = ourGrayTable[idx];
|
||||
// FIXME * 8 = a nasty hack, because the DataGridWidget does not support 2 digit binary output
|
||||
myGrayValue->setList(0, (grayCode & 0b01) + (grayCode & 0b10) * 8);
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ class DrivingWidget : public ControllerWidget
|
|||
void loadConfig() override;
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
|
||||
void setValue();
|
||||
void setValue(int idx);
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
DrivingWidget() = delete;
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FlashWidget::FlashWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, Controller& controller)
|
||||
: ControllerWidget(boss, font, x, y, controller)
|
||||
: ControllerWidget(boss, font, x, y, controller),
|
||||
myEEPROMEraseCurrent(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -34,7 +35,7 @@ void FlashWidget::init(GuiObject* boss, const GUI::Font& font, int x, int y)
|
|||
int xpos = x, ypos = y;
|
||||
|
||||
new StaticTextWidget(boss, font, xpos, ypos + 2, getHeader());
|
||||
|
||||
|
||||
ypos += lineHeight + 6;
|
||||
|
||||
new StaticTextWidget(boss, ifont, xpos, ypos, "Pages/Ranges used:");
|
||||
|
|
|
@ -34,7 +34,9 @@ PromptWidget::PromptWidget(GuiObject* boss, const GUI::Font& font,
|
|||
int x, int y, int w, int h)
|
||||
: Widget(boss, font, x, y, w - kScrollBarWidth, h),
|
||||
CommandSender(boss),
|
||||
_historySize(0),
|
||||
_historyIndex(0),
|
||||
_historyLine(0),
|
||||
_makeDirty(false),
|
||||
_firstTime(true),
|
||||
_exitedEarly(false)
|
||||
|
|
|
@ -127,7 +127,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
|||
2*fontWidth, fontHeight,
|
||||
rowLabel[row], TextAlign::Left);
|
||||
|
||||
for(uInt32 col = 0; col < 5 - row; ++col)
|
||||
for(uInt32 col = 0; col < 5 - row; ++col, ++idx)
|
||||
{
|
||||
myCollision[idx] = new CheckboxWidget(boss, lfont, collX, collY, "", CheckboxWidget::kCheckActionCmd);
|
||||
myCollision[idx]->setTarget(this);
|
||||
|
@ -149,7 +149,6 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
|||
colLabel[col], TextAlign::Left);
|
||||
|
||||
collX += myCollision[idx]->getWidth() + 10;
|
||||
idx++;
|
||||
}
|
||||
collX = xpos + lwidth + 5;
|
||||
collY += lineHeight+3;
|
||||
|
|
|
@ -102,6 +102,11 @@ void CartridgeBUS::setInitialState()
|
|||
// Assuming mode starts out with Fast Fetch off and 3-Voice music,
|
||||
// need to confirm with Chris
|
||||
myMode = 0xFF;
|
||||
|
||||
myBankOffset = myBusOverdriveAddress =
|
||||
mySTYZeroPageAddress = myJMPoperandAddress = 0;
|
||||
|
||||
myFastJumpActive = 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -105,6 +105,7 @@ void CartridgeCDF::setInitialState()
|
|||
// need to confirm with Chris
|
||||
myMode = 0xFF;
|
||||
|
||||
myBankOffset = myLDAimmediateOperandAddress = myJMPoperandAddress = 0;
|
||||
myFastJumpActive = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -273,8 +273,6 @@ class CartridgeCDF : public Cartridge
|
|||
// *and* the next two bytes in ROM are 00 00
|
||||
uInt16 myJMPoperandAddress;
|
||||
|
||||
TIA* myTIA;
|
||||
|
||||
uInt8 myFastJumpActive;
|
||||
|
||||
// version of CDF
|
||||
|
|
|
@ -23,7 +23,8 @@ CartridgeMNetwork::CartridgeMNetwork(const BytePtr& image, uInt32 size,
|
|||
const Settings& settings)
|
||||
: Cartridge(settings),
|
||||
mySize(size),
|
||||
myCurrentRAM(0)
|
||||
myCurrentRAM(0),
|
||||
myRAMSlice(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -94,6 +94,9 @@ class Console : public Serializable
|
|||
*/
|
||||
Controller& leftController() const { return *myLeftControl; }
|
||||
Controller& rightController() const { return *myRightControl; }
|
||||
Controller& controller(Controller::Jack jack) const {
|
||||
return jack == Controller::Left ? leftController() : rightController();
|
||||
}
|
||||
|
||||
/**
|
||||
Get the TIA for this console
|
||||
|
|
|
@ -171,6 +171,12 @@ class Controller : public Serializable
|
|||
*/
|
||||
virtual void update() = 0;
|
||||
|
||||
/**
|
||||
Answers whether the controller is intrinsically an analog controller.
|
||||
Specific controllers should override and implement this method.
|
||||
*/
|
||||
virtual bool isAnalog() const { return false; }
|
||||
|
||||
/**
|
||||
Notification method invoked by the system after its reset method has
|
||||
been called. It may be necessary to override this method for
|
||||
|
|
|
@ -47,6 +47,11 @@ class Driving : public Controller
|
|||
*/
|
||||
void update() override;
|
||||
|
||||
/**
|
||||
Answers whether the controller is intrinsically an analog controller.
|
||||
*/
|
||||
bool isAnalog() const override { return true; }
|
||||
|
||||
/**
|
||||
Determines how this controller will treat values received from the
|
||||
X/Y axis and left/right buttons of the mouse. Since not all controllers
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "StellaKeys.hxx"
|
||||
|
||||
/**
|
||||
@author Bradford W. Mott
|
||||
@author Bradford W. Mott, Stephen Anthony
|
||||
*/
|
||||
class Event
|
||||
{
|
||||
|
@ -82,23 +82,23 @@ class Event
|
|||
|
||||
public:
|
||||
/**
|
||||
Create a new event object
|
||||
Create a new event object.
|
||||
*/
|
||||
Event() { clear(); }
|
||||
|
||||
public:
|
||||
/**
|
||||
Get the value associated with the event of the specified type
|
||||
Get the value associated with the event of the specified type.
|
||||
*/
|
||||
Int32 get(Type type) const { return myValues[type]; }
|
||||
|
||||
/**
|
||||
Set the value associated with the event of the specified type
|
||||
Set the value associated with the event of the specified type.
|
||||
*/
|
||||
void set(Type type, Int32 value) { myValues[type] = value; }
|
||||
|
||||
/**
|
||||
Clears the event array (resets to initial state)
|
||||
Clears the event array (resets to initial state).
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
|
@ -110,15 +110,32 @@ class Event
|
|||
}
|
||||
|
||||
/**
|
||||
Get the keytable associated with this event
|
||||
Get the keytable associated with this event.
|
||||
*/
|
||||
const bool* getKeys() const { return myKeyTable; }
|
||||
|
||||
/**
|
||||
Set the value associated with the event of the specified type
|
||||
Set the value associated with the event of the specified type.
|
||||
*/
|
||||
void setKey(StellaKey key, bool state) { myKeyTable[key] = state; }
|
||||
|
||||
/**
|
||||
Tests if a given event represents continuous or analog values.
|
||||
*/
|
||||
static bool isAnalog(Type type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case Event::PaddleZeroAnalog:
|
||||
case Event::PaddleOneAnalog:
|
||||
case Event::PaddleTwoAnalog:
|
||||
case Event::PaddleThreeAnalog:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Array of values associated with each event type
|
||||
Int32 myValues[LastType];
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -24,11 +24,14 @@ class Console;
|
|||
class OSystem;
|
||||
class MouseControl;
|
||||
class DialogContainer;
|
||||
class PhysicalJoystick;
|
||||
|
||||
#include "Event.hxx"
|
||||
#include "EventHandlerConstants.hxx"
|
||||
#include "Control.hxx"
|
||||
#include "StellaKeys.hxx"
|
||||
#include "PKeyboardHandler.hxx"
|
||||
#include "PJoystickHandler.hxx"
|
||||
#include "Variant.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
|
@ -95,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
|
||||
|
@ -123,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.
|
||||
|
@ -163,19 +157,18 @@ class EventHandler
|
|||
StringList getComboListForEvent(Event::Type event) const;
|
||||
void setComboListForEvent(Event::Type event, const StringList& events);
|
||||
|
||||
Event::Type eventForKey(StellaKey key, EventMode mode) const
|
||||
{ return myKeyTable[key][mode]; }
|
||||
/** Convert keys and physical joystick events into Stella events. */
|
||||
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 {
|
||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
||||
return joy ? joy->axisTable[axis][(value > 0)][mode] : Event::NoType;
|
||||
return myPJoyHandler->eventForAxis(stick, axis, value, mode);
|
||||
}
|
||||
Event::Type eventForJoyButton(int stick, int button, EventMode mode) const {
|
||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
||||
return joy ? joy->btnTable[button][mode] : Event::NoType;
|
||||
return myPJoyHandler->eventForButton(stick, button, mode);
|
||||
}
|
||||
Event::Type eventForJoyHat(int stick, int hat, JoyHat value, EventMode mode) const {
|
||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
||||
return joy ? joy->hatTable[hat][int(value)][mode] : Event::NoType;
|
||||
return myPJoyHandler->eventForHat(stick, hat, value, mode);
|
||||
}
|
||||
|
||||
Event::Type eventAtIndex(int idx, EventMode mode) const;
|
||||
|
@ -192,7 +185,7 @@ class EventHandler
|
|||
bool addKeyMapping(Event::Type event, EventMode mode, StellaKey key);
|
||||
|
||||
/**
|
||||
Bind a joystick axis direction to an event/action and regenerate
|
||||
Bind a physical joystick axis direction to an event/action and regenerate
|
||||
the mapping array(s).
|
||||
|
||||
@param event The event we are remapping
|
||||
|
@ -209,7 +202,7 @@ class EventHandler
|
|||
bool updateMenus = true);
|
||||
|
||||
/**
|
||||
Bind a joystick button to an event/action and regenerate the
|
||||
Bind a physical joystick button to an event/action and regenerate the
|
||||
mapping array(s).
|
||||
|
||||
@param event The event we are remapping
|
||||
|
@ -224,7 +217,7 @@ class EventHandler
|
|||
bool updateMenus = true);
|
||||
|
||||
/**
|
||||
Bind a joystick hat direction to an event/action and regenerate
|
||||
Bind a physical joystick hat direction to an event/action and regenerate
|
||||
the mapping array(s).
|
||||
|
||||
@param event The event we are remapping
|
||||
|
@ -270,30 +263,46 @@ class EventHandler
|
|||
void allowAllDirections(bool allow) { myAllowAllDirectionsFlag = allow; }
|
||||
|
||||
/**
|
||||
Determines whether the given controller must use the mouse (aka,
|
||||
whether the controller generates analog output).
|
||||
Changes to a new state based on the current state and the given event.
|
||||
|
||||
@param jack The controller to query
|
||||
@param type The event
|
||||
@return True if the state changed, else false
|
||||
*/
|
||||
bool controllerIsAnalog(Controller::Jack jack) const;
|
||||
bool changeStateByEvent(Event::Type type);
|
||||
|
||||
/**
|
||||
Return a list of all joysticks currently in the internal database
|
||||
Get the current overlay in use. The overlay won't always exist,
|
||||
so we should test if it's available.
|
||||
|
||||
@return The overlay object
|
||||
*/
|
||||
DialogContainer& overlay() const { return *myOverlay; }
|
||||
bool hasOverlay() const { return myOverlay != nullptr; }
|
||||
|
||||
/**
|
||||
Return a list of all physical joysticks currently in the internal database
|
||||
(first part of variant) and its internal ID (second part of variant).
|
||||
*/
|
||||
VariantList joystickDatabase() const;
|
||||
VariantList physicalJoystickDatabase() const {
|
||||
return myPJoyHandler->database();
|
||||
}
|
||||
|
||||
/**
|
||||
Remove the joystick identified by 'name' from the joystick database,
|
||||
only if it is not currently active.
|
||||
Remove the physical joystick identified by 'name' from the joystick
|
||||
database, only if it is not currently active.
|
||||
*/
|
||||
void removeJoystickFromDatabase(const string& name);
|
||||
void removePhysicalJoystickFromDatabase(const string& name);
|
||||
|
||||
/**
|
||||
Enable/disable text events (distinct from single-key events).
|
||||
*/
|
||||
virtual void enableTextEvents(bool enable) = 0;
|
||||
|
||||
/**
|
||||
Handle changing mouse modes.
|
||||
*/
|
||||
void handleMouseControl();
|
||||
|
||||
protected:
|
||||
// Global OSystem object
|
||||
OSystem& myOSystem;
|
||||
|
@ -303,18 +312,20 @@ 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 handleJoyEvent(int stick, int button, uInt8 state);
|
||||
void handleJoyAxisEvent(int stick, int axis, int value);
|
||||
void handleJoyHatEvent(int stick, int hat, int value);
|
||||
|
||||
/**
|
||||
Returns the human-readable name for a StellaKey.
|
||||
*/
|
||||
virtual const char* const nameForKey(StellaKey key) const
|
||||
{ return EmptyString.c_str(); }
|
||||
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);
|
||||
}
|
||||
void handleJoyAxisEvent(int stick, int axis, int value) {
|
||||
myPJoyHandler->handleAxisEvent(stick, axis, value);
|
||||
}
|
||||
void handleJoyHatEvent(int stick, int hat, int value) {
|
||||
myPJoyHandler->handleHatEvent(stick, hat, value);
|
||||
}
|
||||
|
||||
/**
|
||||
Collects and dispatches any pending events.
|
||||
|
@ -338,120 +349,15 @@ class EventHandler
|
|||
};
|
||||
void handleSystemEvent(SystemEvent e, int data1 = 0, int data2 = 0);
|
||||
|
||||
// An abstraction of a joystick in Stella.
|
||||
// A StellaJoystick holds its own event mapping information, space for
|
||||
// which is dynamically allocated based on the actual number of buttons,
|
||||
// axes, etc that the device contains.
|
||||
// Specific backend class(es) will inherit from this class, and implement
|
||||
// functionality specific to the device.
|
||||
class StellaJoystick
|
||||
{
|
||||
friend class EventHandler;
|
||||
|
||||
public:
|
||||
StellaJoystick();
|
||||
virtual ~StellaJoystick();
|
||||
|
||||
string getMap() const;
|
||||
bool setMap(const string& map);
|
||||
void eraseMap(EventMode mode);
|
||||
void eraseEvent(Event::Type event, EventMode mode);
|
||||
string about() const;
|
||||
|
||||
protected:
|
||||
void initialize(int index, const string& desc,
|
||||
int axes, int buttons, int hats, int balls);
|
||||
|
||||
private:
|
||||
enum JoyType {
|
||||
JT_NONE = 0,
|
||||
JT_REGULAR = 1,
|
||||
JT_STELLADAPTOR_LEFT = 2,
|
||||
JT_STELLADAPTOR_RIGHT = 3,
|
||||
JT_2600DAPTOR_LEFT = 4,
|
||||
JT_2600DAPTOR_RIGHT = 5
|
||||
};
|
||||
|
||||
JoyType type;
|
||||
int ID;
|
||||
string name;
|
||||
int numAxes, numButtons, numHats;
|
||||
Event::Type (*axisTable)[2][kNumModes];
|
||||
Event::Type (*btnTable)[kNumModes];
|
||||
Event::Type (*hatTable)[4][kNumModes];
|
||||
int* axisLastValue;
|
||||
|
||||
private:
|
||||
void getValues(const string& list, IntArray& map) const;
|
||||
|
||||
friend ostream& operator<<(ostream& os, const StellaJoystick& s) {
|
||||
os << " ID: " << s.ID << ", name: " << s.name << ", numaxis: " << s.numAxes
|
||||
<< ", numbtns: " << s.numButtons << ", numhats: " << s.numHats;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
class JoystickHandler
|
||||
{
|
||||
private:
|
||||
struct StickInfo
|
||||
{
|
||||
StickInfo(const string& map = EmptyString, StellaJoystick* stick = nullptr)
|
||||
: mapping(map), joy(stick) {}
|
||||
|
||||
string mapping;
|
||||
StellaJoystick* joy;
|
||||
|
||||
friend ostream& operator<<(ostream& os, const StickInfo& si) {
|
||||
os << " joy: " << si.joy << endl << " map: " << si.mapping;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
using StickDatabase = std::map<string,StickInfo>;
|
||||
using StickList = std::map<int, StellaJoystick*>;
|
||||
|
||||
JoystickHandler(OSystem& system);
|
||||
~JoystickHandler();
|
||||
|
||||
bool add(StellaJoystick* stick);
|
||||
bool remove(int id);
|
||||
bool remove(const string& name);
|
||||
void mapStelladaptors(const string& saport);
|
||||
void setDefaultMapping(Event::Type type, EventMode mode);
|
||||
void eraseMapping(Event::Type event, EventMode mode);
|
||||
void saveMapping();
|
||||
|
||||
const StellaJoystick* joy(int id) const {
|
||||
const auto& i = mySticks.find(id);
|
||||
return i != mySticks.cend() ? i->second : nullptr;
|
||||
}
|
||||
const StickDatabase& database() const { return myDatabase; }
|
||||
const StickList& sticks() const { return mySticks; }
|
||||
|
||||
private:
|
||||
OSystem& myOSystem;
|
||||
|
||||
// Contains all joysticks that Stella knows about, indexed by name
|
||||
StickDatabase myDatabase;
|
||||
|
||||
// Contains only joysticks that are currently available, indexed by id
|
||||
StickList mySticks;
|
||||
|
||||
void setStickDefaultMapping(int stick, Event::Type type, EventMode mode);
|
||||
void printDatabase() const;
|
||||
};
|
||||
/**
|
||||
Add the given joystick to the list of physical joysticks available to the handler.
|
||||
*/
|
||||
void addPhysicalJoystick(PhysicalJoystickPtr stick);
|
||||
|
||||
/**
|
||||
Add the given joystick to the list of sticks available to the handler.
|
||||
Remove physical joystick at the current index.
|
||||
*/
|
||||
void addJoystick(StellaJoystick* stick);
|
||||
|
||||
/**
|
||||
Remove joystick at the current index.
|
||||
*/
|
||||
void removeJoystick(int index);
|
||||
void removePhysicalJoystick(int index);
|
||||
|
||||
private:
|
||||
enum {
|
||||
|
@ -461,35 +367,16 @@ class EventHandler
|
|||
kMenuActionListSize = 14
|
||||
};
|
||||
|
||||
/**
|
||||
Detects and changes the eventhandler state
|
||||
|
||||
@param type The event
|
||||
@return True if the state changed, else false
|
||||
*/
|
||||
bool eventStateChange(Event::Type type);
|
||||
|
||||
/**
|
||||
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();
|
||||
|
||||
/**
|
||||
Tests if a given event should use continuous/analog values.
|
||||
|
||||
@param event The event to test for analog processing
|
||||
@return True if analog, else false
|
||||
*/
|
||||
bool eventIsAnalog(Event::Type event) const;
|
||||
|
||||
void setEventState(EventHandlerState state);
|
||||
|
||||
private:
|
||||
// Structure used for action menu items
|
||||
struct ActionList {
|
||||
|
@ -505,31 +392,28 @@ class EventHandler
|
|||
// Indicates current overlay object
|
||||
DialogContainer* myOverlay;
|
||||
|
||||
// Handler for all keyboard-related events
|
||||
unique_ptr<PhysicalKeyboardHandler> myPKeyHandler;
|
||||
|
||||
// Handler for all joystick addition/removal/mapping
|
||||
unique_ptr<PhysicalJoystickHandler> myPJoyHandler;
|
||||
|
||||
// MouseControl object, which takes care of switching the mouse between
|
||||
// all possible controller modes
|
||||
unique_ptr<MouseControl> myMouseControl;
|
||||
|
||||
// Array of key events, indexed by StellaKey
|
||||
Event::Type myKeyTable[KBDK_LAST][kNumModes];
|
||||
|
||||
// The event(s) assigned to each combination event
|
||||
Event::Type myComboTable[kComboSize][kEventsPerCombo];
|
||||
|
||||
// Indicates the current state of the system (ie, which mode is current)
|
||||
EventHandlerState myState;
|
||||
|
||||
// Indicates whether the joystick emulates 'impossible' directions
|
||||
// Indicates whether the virtual joystick emulates 'impossible' directions
|
||||
bool myAllowAllDirectionsFlag;
|
||||
|
||||
// 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;
|
||||
|
@ -538,35 +422,10 @@ 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];
|
||||
|
||||
// Static lookup tables for Stelladaptor/2600-daptor axis/button support
|
||||
static const Event::Type SA_Axis[2][2];
|
||||
static const Event::Type SA_Button[2][4];
|
||||
static const Event::Type SA_Key[2][12];
|
||||
|
||||
// Handler for all joystick addition/removal/mapping
|
||||
unique_ptr<JoystickHandler> myJoyHandler;
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
EventHandler() = delete;
|
||||
EventHandler(const EventHandler&) = delete;
|
||||
|
|
|
@ -1,576 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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 <map>
|
||||
|
||||
#include "OSystem.hxx"
|
||||
#include "Settings.hxx"
|
||||
#include "Vec.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
#include "EventHandler.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventHandler::StellaJoystick::StellaJoystick()
|
||||
: type(JT_NONE),
|
||||
ID(-1),
|
||||
name("None"),
|
||||
numAxes(0),
|
||||
numButtons(0),
|
||||
numHats(0),
|
||||
axisTable(nullptr),
|
||||
btnTable(nullptr),
|
||||
hatTable(nullptr),
|
||||
axisLastValue(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventHandler::StellaJoystick::~StellaJoystick()
|
||||
{
|
||||
delete[] axisTable;
|
||||
delete[] btnTable;
|
||||
delete[] hatTable;
|
||||
delete[] axisLastValue;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::StellaJoystick::initialize(int index, const string& desc,
|
||||
int axes, int buttons, int hats, int /*balls*/)
|
||||
{
|
||||
ID = index;
|
||||
name = desc;
|
||||
|
||||
// Dynamically create the various mapping arrays for this joystick,
|
||||
// based on its specific attributes
|
||||
numAxes = axes;
|
||||
numButtons = buttons;
|
||||
numHats = hats;
|
||||
if(numAxes)
|
||||
axisTable = new Event::Type[numAxes][2][kNumModes];
|
||||
if(numButtons)
|
||||
btnTable = new Event::Type[numButtons][kNumModes];
|
||||
if(numHats)
|
||||
hatTable = new Event::Type[numHats][4][kNumModes];
|
||||
axisLastValue = new int[numAxes];
|
||||
|
||||
// Erase the joystick axis mapping array and last axis value
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
{
|
||||
axisLastValue[a] = 0;
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
axisTable[a][0][m] = axisTable[a][1][m] = Event::NoType;
|
||||
}
|
||||
|
||||
// Erase the joystick button mapping array
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
btnTable[b][m] = Event::NoType;
|
||||
|
||||
// Erase the joystick hat mapping array
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
hatTable[h][0][m] = hatTable[h][1][m] =
|
||||
hatTable[h][2][m] = hatTable[h][3][m] = Event::NoType;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string EventHandler::StellaJoystick::getMap() const
|
||||
{
|
||||
// The mapping structure (for remappable devices) is defined as follows:
|
||||
// NAME | AXIS # + values | BUTTON # + values | HAT # + values,
|
||||
// where each subsection of values is separated by ':'
|
||||
if(type == JT_REGULAR)
|
||||
{
|
||||
ostringstream joybuf;
|
||||
joybuf << name << "|" << numAxes;
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
for(int k = 0; k < 2; ++k)
|
||||
joybuf << " " << axisTable[a][k][m];
|
||||
joybuf << "|" << numButtons;
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
joybuf << " " << btnTable[b][m];
|
||||
joybuf << "|" << numHats;
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
for(int k = 0; k < 4; ++k)
|
||||
joybuf << " " << hatTable[h][k][m];
|
||||
|
||||
return joybuf.str();
|
||||
}
|
||||
return EmptyString;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool EventHandler::StellaJoystick::setMap(const string& mapString)
|
||||
{
|
||||
istringstream buf(mapString);
|
||||
StringList items;
|
||||
string item;
|
||||
while(getline(buf, item, '|'))
|
||||
items.push_back(item);
|
||||
|
||||
// Error checking
|
||||
if(items.size() != 4)
|
||||
return false;
|
||||
|
||||
IntArray map;
|
||||
|
||||
// Parse axis/button/hat values
|
||||
getValues(items[1], map);
|
||||
if(int(map.size()) == numAxes * 2 * kNumModes)
|
||||
{
|
||||
// Fill the axes table with events
|
||||
auto event = map.cbegin();
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
for(int k = 0; k < 2; ++k)
|
||||
axisTable[a][k][m] = Event::Type(*event++);
|
||||
}
|
||||
getValues(items[2], map);
|
||||
if(int(map.size()) == numButtons * kNumModes)
|
||||
{
|
||||
auto event = map.cbegin();
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
btnTable[b][m] = Event::Type(*event++);
|
||||
}
|
||||
getValues(items[3], map);
|
||||
if(int(map.size()) == numHats * 4 * kNumModes)
|
||||
{
|
||||
auto event = map.cbegin();
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
for(int k = 0; k < 4; ++k)
|
||||
hatTable[h][k][m] = Event::Type(*event++);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::StellaJoystick::eraseMap(EventMode mode)
|
||||
{
|
||||
// Erase axis mappings
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
axisTable[a][0][mode] = axisTable[a][1][mode] = Event::NoType;
|
||||
|
||||
// Erase button mappings
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
btnTable[b][mode] = Event::NoType;
|
||||
|
||||
// Erase hat mappings
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
hatTable[h][0][mode] = hatTable[h][1][mode] =
|
||||
hatTable[h][2][mode] = hatTable[h][3][mode] = Event::NoType;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::StellaJoystick::eraseEvent(Event::Type event, EventMode mode)
|
||||
{
|
||||
// Erase axis mappings
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
{
|
||||
if(axisTable[a][0][mode] == event) axisTable[a][0][mode] = Event::NoType;
|
||||
if(axisTable[a][1][mode] == event) axisTable[a][1][mode] = Event::NoType;
|
||||
}
|
||||
|
||||
// Erase button mappings
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
if(btnTable[b][mode] == event) btnTable[b][mode] = Event::NoType;
|
||||
|
||||
// Erase hat mappings
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
{
|
||||
if(hatTable[h][0][mode] == event) hatTable[h][0][mode] = Event::NoType;
|
||||
if(hatTable[h][1][mode] == event) hatTable[h][1][mode] = Event::NoType;
|
||||
if(hatTable[h][2][mode] == event) hatTable[h][2][mode] = Event::NoType;
|
||||
if(hatTable[h][3][mode] == event) hatTable[h][3][mode] = Event::NoType;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::StellaJoystick::getValues(const string& list, IntArray& map) const
|
||||
{
|
||||
map.clear();
|
||||
istringstream buf(list);
|
||||
|
||||
int value;
|
||||
buf >> value; // we don't need to know the # of items at this point
|
||||
while(buf >> value)
|
||||
map.push_back(value);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string EventHandler::StellaJoystick::about() const
|
||||
{
|
||||
ostringstream buf;
|
||||
buf << name;
|
||||
if(type == JT_REGULAR)
|
||||
buf << " with: " << numAxes << " axes, " << numButtons << " buttons, "
|
||||
<< numHats << " hats";
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventHandler::JoystickHandler::JoystickHandler(OSystem& system)
|
||||
: myOSystem(system)
|
||||
{
|
||||
// Load previously saved joystick mapping (if any) from settings
|
||||
istringstream buf(myOSystem.settings().getString("joymap"));
|
||||
string joymap, joyname;
|
||||
|
||||
// First check the event type, and disregard the entire mapping if it's invalid
|
||||
getline(buf, joymap, '^');
|
||||
if(atoi(joymap.c_str()) == Event::LastType)
|
||||
{
|
||||
// Otherwise, put each joystick mapping entry into the database
|
||||
while(getline(buf, joymap, '^'))
|
||||
{
|
||||
istringstream namebuf(joymap);
|
||||
getline(namebuf, joyname, '|');
|
||||
if(joyname.length() != 0)
|
||||
{
|
||||
StickInfo info(joymap);
|
||||
myDatabase.emplace(joyname, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventHandler::JoystickHandler::~JoystickHandler()
|
||||
{
|
||||
for(const auto& i: myDatabase)
|
||||
delete i.second.joy;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::JoystickHandler::printDatabase() const
|
||||
{
|
||||
cerr << "---------------------------------------------------------" << endl
|
||||
<< "joy database:" << endl;
|
||||
for(const auto& i: myDatabase)
|
||||
cerr << i.first << endl << i.second << endl << endl;
|
||||
|
||||
cerr << "---------------------" << endl
|
||||
<< "joy active:" << endl;
|
||||
for(const auto& i: mySticks)
|
||||
cerr << i.first << ": " << *i.second << endl;
|
||||
cerr << "---------------------------------------------------------" << endl << endl << endl;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool EventHandler::JoystickHandler::add(StellaJoystick* stick)
|
||||
{
|
||||
// Skip if we couldn't open it for any reason
|
||||
if(stick->ID < 0)
|
||||
return false;
|
||||
|
||||
// Figure out what type of joystick this is
|
||||
bool specialAdaptor = false;
|
||||
|
||||
if(BSPF::containsIgnoreCase(stick->name, "2600-daptor"))
|
||||
{
|
||||
// 2600-daptorII devices have 3 axes and 12 buttons, and the value of the z-axis
|
||||
// determines how those 12 buttons are used (not all buttons are used in all modes)
|
||||
if(stick->numAxes == 3)
|
||||
{
|
||||
// TODO - stubbed out for now, until we find a way to reliably get info
|
||||
// from the Z axis
|
||||
stick->name = "2600-daptor II";
|
||||
}
|
||||
else
|
||||
stick->name = "2600-daptor";
|
||||
|
||||
specialAdaptor = true;
|
||||
}
|
||||
else if(BSPF::containsIgnoreCase(stick->name, "Stelladaptor"))
|
||||
{
|
||||
stick->name = "Stelladaptor";
|
||||
specialAdaptor = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need unique names for mappable devices
|
||||
// For non-unique names that already have a database entry,
|
||||
// we append ' #x', where 'x' increases consecutively
|
||||
int count = 0;
|
||||
for(const auto& i: myDatabase)
|
||||
if(BSPF::startsWithIgnoreCase(i.first, stick->name) && i.second.joy)
|
||||
++count;
|
||||
|
||||
if(count > 0)
|
||||
{
|
||||
ostringstream name;
|
||||
name << stick->name << " #" << count+1;
|
||||
stick->name = name.str();
|
||||
}
|
||||
stick->type = StellaJoystick::JT_REGULAR;
|
||||
}
|
||||
// The stick *must* be inserted here, since it may be used below
|
||||
mySticks[stick->ID] = stick;
|
||||
|
||||
// Map the stelladaptors we've found according to the specified ports
|
||||
if(specialAdaptor)
|
||||
mapStelladaptors(myOSystem.settings().getString("saport"));
|
||||
|
||||
// Add stick to database
|
||||
auto it = myDatabase.find(stick->name);
|
||||
if(it != myDatabase.end()) // already present
|
||||
{
|
||||
it->second.joy = stick;
|
||||
stick->setMap(it->second.mapping);
|
||||
}
|
||||
else // adding for the first time
|
||||
{
|
||||
StickInfo info("", stick);
|
||||
myDatabase.emplace(stick->name, info);
|
||||
setStickDefaultMapping(stick->ID, Event::NoType, kEmulationMode);
|
||||
setStickDefaultMapping(stick->ID, Event::NoType, kMenuMode);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool EventHandler::JoystickHandler::remove(int id)
|
||||
{
|
||||
// When a joystick is removed, we delete the actual joystick object but
|
||||
// remember its mapping, since it will eventually be saved to settings
|
||||
|
||||
// Sticks that are removed must have initially been added
|
||||
// So we use the 'active' joystick list to access them
|
||||
try
|
||||
{
|
||||
StellaJoystick* stick = mySticks.at(id);
|
||||
|
||||
auto it = myDatabase.find(stick->name);
|
||||
if(it != myDatabase.end() && it->second.joy == stick)
|
||||
{
|
||||
ostringstream buf;
|
||||
buf << "Removed joystick " << mySticks[id]->ID << ":" << endl
|
||||
<< " " << mySticks[id]->about() << endl;
|
||||
myOSystem.logMessage(buf.str(), 1);
|
||||
|
||||
// Remove joystick, but remember mapping
|
||||
it->second.mapping = stick->getMap();
|
||||
delete it->second.joy; it->second.joy = nullptr;
|
||||
mySticks.erase(id);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch(std::out_of_range)
|
||||
{
|
||||
// fall through to indicate remove failed
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool EventHandler::JoystickHandler::remove(const string& name)
|
||||
{
|
||||
auto it = myDatabase.find(name);
|
||||
if(it != myDatabase.end() && it->second.joy == nullptr)
|
||||
{
|
||||
myDatabase.erase(it);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::JoystickHandler::mapStelladaptors(const string& saport)
|
||||
{
|
||||
// saport will have two values:
|
||||
// 'lr' means treat first valid adaptor as left port, second as right port
|
||||
// 'rl' means treat first valid adaptor as right port, second as left port
|
||||
// We know there will be only two such devices (at most), since the logic
|
||||
// in setupJoysticks take care of that
|
||||
int saCount = 0;
|
||||
int saOrder[2] = { 1, 2 };
|
||||
if(BSPF::equalsIgnoreCase(saport, "rl"))
|
||||
{
|
||||
saOrder[0] = 2; saOrder[1] = 1;
|
||||
}
|
||||
|
||||
for(auto& stick: mySticks)
|
||||
{
|
||||
if(BSPF::startsWithIgnoreCase(stick.second->name, "Stelladaptor"))
|
||||
{
|
||||
if(saOrder[saCount] == 1)
|
||||
{
|
||||
stick.second->name += " (emulates left joystick port)";
|
||||
stick.second->type = StellaJoystick::JT_STELLADAPTOR_LEFT;
|
||||
}
|
||||
else if(saOrder[saCount] == 2)
|
||||
{
|
||||
stick.second->name += " (emulates right joystick port)";
|
||||
stick.second->type = StellaJoystick::JT_STELLADAPTOR_RIGHT;
|
||||
}
|
||||
saCount++;
|
||||
}
|
||||
else if(BSPF::startsWithIgnoreCase(stick.second->name, "2600-daptor"))
|
||||
{
|
||||
if(saOrder[saCount] == 1)
|
||||
{
|
||||
stick.second->name += " (emulates left joystick port)";
|
||||
stick.second->type = StellaJoystick::JT_2600DAPTOR_LEFT;
|
||||
}
|
||||
else if(saOrder[saCount] == 2)
|
||||
{
|
||||
stick.second->name += " (emulates right joystick port)";
|
||||
stick.second->type = StellaJoystick::JT_2600DAPTOR_RIGHT;
|
||||
}
|
||||
saCount++;
|
||||
}
|
||||
}
|
||||
myOSystem.settings().setValue("saport", saport);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::JoystickHandler::setDefaultMapping(Event::Type event, EventMode mode)
|
||||
{
|
||||
eraseMapping(event, mode);
|
||||
for(auto& i: mySticks)
|
||||
setStickDefaultMapping(i.first, event, mode);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::JoystickHandler::setStickDefaultMapping(int stick,
|
||||
Event::Type event, EventMode mode)
|
||||
{
|
||||
EventHandler& handler = myOSystem.eventHandler();
|
||||
bool eraseAll = (event == Event::NoType);
|
||||
|
||||
auto setDefaultAxis = [&](int a_stick, int a_axis, int a_value, Event::Type a_event)
|
||||
{
|
||||
if(eraseAll || a_event == event)
|
||||
handler.addJoyAxisMapping(a_event, mode, a_stick, a_axis, a_value, false);
|
||||
};
|
||||
auto setDefaultBtn = [&](int b_stick, int b_button, Event::Type b_event)
|
||||
{
|
||||
if(eraseAll || b_event == event)
|
||||
handler.addJoyButtonMapping(b_event, mode, b_stick, b_button, false);
|
||||
};
|
||||
auto setDefaultHat = [&](int h_stick, int h_hat, JoyHat h_dir, Event::Type h_event)
|
||||
{
|
||||
if(eraseAll || h_event == event)
|
||||
handler.addJoyHatMapping(h_event, mode, h_stick, h_hat, h_dir, false);
|
||||
};
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case kEmulationMode: // Default emulation events
|
||||
if(stick == 0)
|
||||
{
|
||||
// Left joystick left/right directions (assume joystick zero)
|
||||
setDefaultAxis( 0, 0, 0, Event::JoystickZeroLeft );
|
||||
setDefaultAxis( 0, 0, 1, Event::JoystickZeroRight );
|
||||
// Left joystick up/down directions (assume joystick zero)
|
||||
setDefaultAxis( 0, 1, 0, Event::JoystickZeroUp );
|
||||
setDefaultAxis( 0, 1, 1, Event::JoystickZeroDown );
|
||||
// Left joystick (assume joystick zero, button zero)
|
||||
setDefaultBtn( 0, 0, Event::JoystickZeroFire );
|
||||
// Left joystick left/right directions (assume joystick zero and hat 0)
|
||||
setDefaultHat( 0, 0, JoyHat::LEFT, Event::JoystickZeroLeft );
|
||||
setDefaultHat( 0, 0, JoyHat::RIGHT, Event::JoystickZeroRight );
|
||||
// Left joystick up/down directions (assume joystick zero and hat 0)
|
||||
setDefaultHat( 0, 0, JoyHat::UP, Event::JoystickZeroUp );
|
||||
setDefaultHat( 0, 0, JoyHat::DOWN, Event::JoystickZeroDown );
|
||||
}
|
||||
else if(stick == 1)
|
||||
{
|
||||
// Right joystick left/right directions (assume joystick one)
|
||||
setDefaultAxis( 1, 0, 0, Event::JoystickOneLeft );
|
||||
setDefaultAxis( 1, 0, 1, Event::JoystickOneRight );
|
||||
// Right joystick left/right directions (assume joystick one)
|
||||
setDefaultAxis( 1, 1, 0, Event::JoystickOneUp );
|
||||
setDefaultAxis( 1, 1, 1, Event::JoystickOneDown );
|
||||
// Right joystick (assume joystick one, button zero)
|
||||
setDefaultBtn( 1, 0, Event::JoystickOneFire );
|
||||
// Right joystick left/right directions (assume joystick one and hat 0)
|
||||
setDefaultHat( 1, 0, JoyHat::LEFT, Event::JoystickOneLeft );
|
||||
setDefaultHat( 1, 0, JoyHat::RIGHT, Event::JoystickOneRight );
|
||||
// Right joystick up/down directions (assume joystick one and hat 0)
|
||||
setDefaultHat( 1, 0, JoyHat::UP, Event::JoystickOneUp );
|
||||
setDefaultHat( 1, 0, JoyHat::DOWN, Event::JoystickOneDown );
|
||||
}
|
||||
break;
|
||||
|
||||
case kMenuMode: // Default menu/UI events
|
||||
if(stick == 0)
|
||||
{
|
||||
setDefaultAxis( 0, 0, 0, Event::UILeft );
|
||||
setDefaultAxis( 0, 0, 1, Event::UIRight );
|
||||
setDefaultAxis( 0, 1, 0, Event::UIUp );
|
||||
setDefaultAxis( 0, 1, 1, Event::UIDown );
|
||||
|
||||
// Left joystick (assume joystick zero, button zero)
|
||||
setDefaultBtn( 0, 0, Event::UISelect );
|
||||
|
||||
setDefaultHat( 0, 0, JoyHat::LEFT, Event::UILeft );
|
||||
setDefaultHat( 0, 0, JoyHat::RIGHT, Event::UIRight );
|
||||
setDefaultHat( 0, 0, JoyHat::UP, Event::UIUp );
|
||||
setDefaultHat( 0, 0, JoyHat::DOWN, Event::UIDown );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::JoystickHandler::eraseMapping(Event::Type event, EventMode mode)
|
||||
{
|
||||
// If event is 'NoType', erase and reset all mappings
|
||||
// Otherwise, only reset the given event
|
||||
if(event == Event::NoType)
|
||||
{
|
||||
for(auto& stick: mySticks)
|
||||
stick.second->eraseMap(mode); // erase all events
|
||||
}
|
||||
else
|
||||
{
|
||||
for(auto& stick: mySticks)
|
||||
stick.second->eraseEvent(event, mode); // only reset the specific event
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::JoystickHandler::saveMapping()
|
||||
{
|
||||
// Save the joystick mapping hash table, making sure to update it with
|
||||
// any changes that have been made during the program run
|
||||
ostringstream joybuf;
|
||||
joybuf << Event::LastType;
|
||||
|
||||
for(const auto& i: myDatabase)
|
||||
{
|
||||
const string& map = i.second.joy ? i.second.joy->getMap() : i.second.mapping;
|
||||
if(map != "")
|
||||
joybuf << "^" << map;
|
||||
}
|
||||
myOSystem.settings().setValue("joymap", joybuf.str());
|
||||
}
|
|
@ -47,9 +47,10 @@ FrameBuffer::FrameBuffer(OSystem& osystem)
|
|||
myInitializedCount(0),
|
||||
myPausedCount(0),
|
||||
myStatsEnabled(false),
|
||||
myLastScanlines(0),
|
||||
myGrabMouse(false),
|
||||
myCurrentModeList(nullptr)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameBuffer::~FrameBuffer()
|
||||
|
@ -649,8 +650,8 @@ void FrameBuffer::setCursorState()
|
|||
bool emulation =
|
||||
myOSystem.eventHandler().state() == EventHandlerState::EMULATION;
|
||||
bool analog = myOSystem.hasConsole() ?
|
||||
(myOSystem.eventHandler().controllerIsAnalog(Controller::Left) ||
|
||||
myOSystem.eventHandler().controllerIsAnalog(Controller::Right)) : false;
|
||||
(myOSystem.console().controller(Controller::Left).isAnalog() ||
|
||||
myOSystem.console().controller(Controller::Right).isAnalog()) : false;
|
||||
bool alwaysUseMouse = BSPF::equalsIgnoreCase("always", myOSystem.settings().getString("usemouse"));
|
||||
|
||||
grabMouse(emulation && (analog || alwaysUseMouse) && myGrabMouse);
|
||||
|
|
|
@ -506,7 +506,9 @@ class FrameBuffer
|
|||
shared_ptr<FBSurface> surface;
|
||||
bool enabled;
|
||||
|
||||
Message() : counter(0), x(0), y(0), w(0), h(0), color(0), enabled(false) { }
|
||||
Message()
|
||||
: counter(0), x(0), y(0), w(0), h(0), position(MessagePosition::BottomCenter),
|
||||
color(0), enabled(false) { }
|
||||
};
|
||||
Message myMsg;
|
||||
Message myStatsMsg;
|
||||
|
|
|
@ -207,15 +207,6 @@ inline void M6502::handleHalt()
|
|||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void M6502::updateStepStateByInstruction()
|
||||
{
|
||||
// Currently only used in debugger mode
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
myStepStateByInstruction = myCondBreaks.size() || myCondSaveStates.size() || myTrapConds.size();
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool M6502::execute(uInt32 number)
|
||||
{
|
||||
|
@ -258,23 +249,19 @@ inline bool M6502::_execute(uInt32 number)
|
|||
{
|
||||
bool read = myJustHitReadTrapFlag;
|
||||
myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false;
|
||||
if(myDebugger && myDebugger->start(myHitTrapInfo.message, myHitTrapInfo.address, read))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (startDebugger(myHitTrapInfo.message, myHitTrapInfo.address, read)) return true;
|
||||
}
|
||||
|
||||
if(myBreakPoints.isInitialized() && myBreakPoints.isSet(PC))
|
||||
if(myDebugger && myDebugger->start("BP: ", PC))
|
||||
return true;
|
||||
if(myBreakPoints.isInitialized() && myBreakPoints.isSet(PC) && startDebugger("BP: ", PC))
|
||||
return true;
|
||||
|
||||
int cond = evalCondBreaks();
|
||||
if(cond > -1)
|
||||
{
|
||||
stringstream msg;
|
||||
msg << "CBP[" << Common::Base::HEX2 << cond << "]: " << myCondBreakNames[cond];
|
||||
if(myDebugger && myDebugger->start(msg.str()))
|
||||
return true;
|
||||
if (startDebugger(msg.str())) return true;
|
||||
}
|
||||
|
||||
cond = evalCondSaveStates();
|
||||
|
@ -611,4 +598,23 @@ const StringList& M6502::getCondTrapNames() const
|
|||
{
|
||||
return myTrapCondNames;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void M6502::updateStepStateByInstruction()
|
||||
{
|
||||
myStepStateByInstruction = myCondBreaks.size() || myCondSaveStates.size() ||
|
||||
myTrapConds.size();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool M6502::startDebugger(const string& message, int address, bool read)
|
||||
{
|
||||
handleHalt();
|
||||
|
||||
mySystem->tia().updateEmulation();
|
||||
mySystem->m6532().updateEmulation();
|
||||
|
||||
return myDebugger->start(message, address, read);
|
||||
}
|
||||
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
|
|
|
@ -314,6 +314,13 @@ class M6502 : public Serializable
|
|||
*/
|
||||
void handleHalt();
|
||||
|
||||
/**
|
||||
This is the actual dispatch function that does the grunt work. M6502::execute
|
||||
wraps it and makes sure that any pending halt is processed before returning.
|
||||
*/
|
||||
bool _execute(uInt32 number);
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
/**
|
||||
Check whether we are required to update hardware (TIA + RIOT) in lockstep
|
||||
with the CPU and update the flag accordingly.
|
||||
|
@ -321,10 +328,11 @@ class M6502 : public Serializable
|
|||
void updateStepStateByInstruction();
|
||||
|
||||
/**
|
||||
This is the actual dispatch function that does the grunt work. M6502::execute
|
||||
wraps it and makes sure that any pending halt is processed before returning.
|
||||
Make sure that the current hardware state is up to date (TIA & RIOT) and dispatch
|
||||
debugger.
|
||||
*/
|
||||
bool _execute(uInt32 number);
|
||||
bool startDebugger(const string& message = "", int address = -1, bool read = true);
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
|
||||
private:
|
||||
/**
|
||||
|
|
|
@ -72,6 +72,11 @@ class MindLink : public Controller
|
|||
*/
|
||||
void update() override;
|
||||
|
||||
/**
|
||||
Answers whether the controller is intrinsically an analog controller.
|
||||
*/
|
||||
bool isAnalog() const override { return true; }
|
||||
|
||||
/**
|
||||
Determines how this controller will treat values received from the
|
||||
X/Y axis and left/right buttons of the mouse. Since not all controllers
|
||||
|
|
|
@ -154,7 +154,7 @@ bool OSystem::create()
|
|||
myRandom->initSeed();
|
||||
|
||||
// Create PNG handler
|
||||
myPNGLib = make_unique<PNGLibrary>(*myFrameBuffer);
|
||||
myPNGLib = make_unique<PNGLibrary>(*this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,11 @@ class Paddles : public Controller
|
|||
*/
|
||||
void update() override;
|
||||
|
||||
/**
|
||||
Answers whether the controller is intrinsically an analog controller.
|
||||
*/
|
||||
bool isAnalog() const override { return true; }
|
||||
|
||||
/**
|
||||
Determines how this controller will treat values received from the
|
||||
X/Y axis and left/right buttons of the mouse. Since not all controllers
|
||||
|
|
|
@ -57,6 +57,11 @@ class PointingDevice : public Controller
|
|||
*/
|
||||
void update() override;
|
||||
|
||||
/**
|
||||
Answers whether the controller is intrinsically an analog controller.
|
||||
*/
|
||||
bool isAnalog() const override { return true; }
|
||||
|
||||
/**
|
||||
Determines how this controller will treat values received from the
|
||||
X/Y axis and left/right buttons of the mouse. Since not all controllers
|
||||
|
|
|
@ -53,7 +53,6 @@ MODULE_OBJS := \
|
|||
src/emucore/Control.o \
|
||||
src/emucore/Driving.o \
|
||||
src/emucore/EventHandler.o \
|
||||
src/emucore/EventJoyHandler.o \
|
||||
src/emucore/FrameBuffer.o \
|
||||
src/emucore/FBSurface.o \
|
||||
src/emucore/FSNode.o \
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Background::Background()
|
||||
: myTIA(nullptr)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ enum Count: Int8 {
|
|||
Ball::Ball(uInt32 collisionMask)
|
||||
: myCollisionMaskDisabled(collisionMask),
|
||||
myCollisionMaskEnabled(0xFFFF),
|
||||
myIsSuppressed(false)
|
||||
myIsSuppressed(false),
|
||||
myTIA(nullptr)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ void DelayQueue<length, capacity>::push(uInt8 address, uInt8 value, uInt8 delay)
|
|||
|
||||
uInt8 currentIndex = myIndices[address];
|
||||
|
||||
if (currentIndex < 0xFF)
|
||||
if (currentIndex < length)
|
||||
myMembers[currentIndex].remove(address);
|
||||
|
||||
uInt8 index = smartmod<length>(myIndex + delay);
|
||||
|
|
|
@ -28,6 +28,8 @@ class DelayQueueMember : public Serializable {
|
|||
struct Entry {
|
||||
uInt8 address;
|
||||
uInt8 value;
|
||||
|
||||
Entry() : address(0), value(0) { }
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -52,7 +54,6 @@ class DelayQueueMember : public Serializable {
|
|||
uInt8 mySize;
|
||||
|
||||
private:
|
||||
|
||||
DelayQueueMember(const DelayQueueMember<capacity>&) = delete;
|
||||
DelayQueueMember(DelayQueueMember<capacity>&&) = delete;
|
||||
DelayQueueMember<capacity>& operator=(const DelayQueueMember<capacity>&) = delete;
|
||||
|
@ -68,7 +69,8 @@ class DelayQueueMember : public Serializable {
|
|||
template<unsigned capacity>
|
||||
DelayQueueMember<capacity>::DelayQueueMember()
|
||||
: mySize(0)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
template<unsigned capacity>
|
||||
|
@ -110,7 +112,7 @@ void DelayQueueMember<capacity>::clear()
|
|||
template<unsigned capacity>
|
||||
bool DelayQueueMember<capacity>::save(Serializer& out) const
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
out.putInt(mySize);
|
||||
for(uInt8 i = 0; i < mySize; ++i)
|
||||
|
|
|
@ -28,7 +28,8 @@ Missile::Missile(uInt32 collisionMask)
|
|||
: myCollisionMaskDisabled(collisionMask),
|
||||
myCollisionMaskEnabled(0xFFFF),
|
||||
myIsSuppressed(false),
|
||||
myDecodesOffset(0)
|
||||
myDecodesOffset(0),
|
||||
myTIA(nullptr)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
|
|
@ -28,7 +28,8 @@ Player::Player(uInt32 collisionMask)
|
|||
: myCollisionMaskDisabled(collisionMask),
|
||||
myCollisionMaskEnabled(0xFFFF),
|
||||
myIsSuppressed(false),
|
||||
myDecodesOffset(0)
|
||||
myDecodesOffset(0),
|
||||
myTIA(nullptr)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
Playfield::Playfield(uInt32 collisionMask)
|
||||
: myCollisionMaskDisabled(collisionMask),
|
||||
myCollisionMaskEnabled(0xFFFF),
|
||||
myIsSuppressed(false)
|
||||
myIsSuppressed(false),
|
||||
myTIA(nullptr)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
@ -38,9 +39,11 @@ void Playfield::reset()
|
|||
myPf1 = 0;
|
||||
myPf2 = 0;
|
||||
|
||||
myX = 0;
|
||||
|
||||
myObjectColor = myDebugColor = 0;
|
||||
myColorP0 = 0;
|
||||
myColorP1 = 0;
|
||||
myColorLeft = myColorRight = 0;
|
||||
myColorP0 = myColorP1 = 0;
|
||||
myColorMode = ColorMode::normal;
|
||||
myDebugEnabled = false;
|
||||
|
||||
|
|
|
@ -170,11 +170,13 @@ void TIA::reset()
|
|||
|
||||
myDelayQueue.reset();
|
||||
|
||||
if (myFrameManager) myFrameManager->reset();
|
||||
|
||||
myCyclesAtFrameStart = 0;
|
||||
|
||||
frameReset(); // Recalculate the size of the display
|
||||
if (myFrameManager)
|
||||
{
|
||||
myFrameManager->reset();
|
||||
frameReset(); // Recalculate the size of the display
|
||||
}
|
||||
|
||||
// Must be done last, after all other items have reset
|
||||
enableFixedColors(mySettings.getBool(mySettings.getBool("dev.settings") ? "dev.debugcolors" : "plr.debugcolors"));
|
||||
|
|
|
@ -35,9 +35,21 @@ enum Metrics: uInt32 {
|
|||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameManager::FrameManager() :
|
||||
myHeight(0),
|
||||
myYStart(0)
|
||||
FrameManager::FrameManager()
|
||||
: myState(State::waitForVsyncStart),
|
||||
myLineInState(0),
|
||||
myVsyncLines(0),
|
||||
myY(0), myLastY(0),
|
||||
myVblankLines(0),
|
||||
myKernelLines(0),
|
||||
myOverscanLines(0),
|
||||
myFrameLines(0),
|
||||
myHeight(0),
|
||||
myFixedHeight(0),
|
||||
myYStart(0),
|
||||
myJitterEnabled(false),
|
||||
myStableFrameLines(-1),
|
||||
myStableFrameHeightCountdown(0)
|
||||
{
|
||||
onLayoutChange();
|
||||
}
|
||||
|
|
|
@ -25,9 +25,12 @@ enum Metrics: uInt32 {
|
|||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
JitterEmulation::JitterEmulation() :
|
||||
myYStart(0)
|
||||
{}
|
||||
JitterEmulation::JitterEmulation()
|
||||
: myJitterFactor(0),
|
||||
myYStart(0)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JitterEmulation::reset()
|
||||
|
|
|
@ -51,6 +51,7 @@ Dialog::Dialog(OSystem& instance, DialogContainer& parent, const GUI::Font& font
|
|||
_mouseWidget(nullptr),
|
||||
_focusedWidget(nullptr),
|
||||
_dragWidget(nullptr),
|
||||
_defaultWidget(nullptr),
|
||||
_okWidget(nullptr),
|
||||
_cancelWidget(nullptr),
|
||||
_visible(false),
|
||||
|
|
|
@ -271,7 +271,7 @@ void DialogContainer::handleMouseButtonEvent(MouseButton b, bool pressed,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DialogContainer::handleJoyEvent(int stick, int button, uInt8 state)
|
||||
void DialogContainer::handleJoyBtnEvent(int stick, int button, uInt8 state)
|
||||
{
|
||||
if(myDialogStack.empty())
|
||||
return;
|
||||
|
|
|
@ -99,7 +99,7 @@ class DialogContainer
|
|||
@param button The joystick button
|
||||
@param state The state (pressed or released)
|
||||
*/
|
||||
void handleJoyEvent(int stick, int button, uInt8 state);
|
||||
void handleJoyBtnEvent(int stick, int button, uInt8 state);
|
||||
|
||||
/**
|
||||
Handle a joystick axis event.
|
||||
|
|
|
@ -75,7 +75,7 @@ void JoystickDialog::loadConfig()
|
|||
myJoyIDs.clear();
|
||||
|
||||
StringList sticks;
|
||||
for(const auto& i: instance().eventHandler().joystickDatabase())
|
||||
for(const auto& i: instance().eventHandler().physicalJoystickDatabase())
|
||||
{
|
||||
sticks.push_back(i.first);
|
||||
myJoyIDs.push_back(i.second.toInt());
|
||||
|
@ -99,7 +99,8 @@ void JoystickDialog::handleCommand(CommandSender* sender, int cmd, int data, int
|
|||
break;
|
||||
|
||||
case kRemoveCmd:
|
||||
instance().eventHandler().removeJoystickFromDatabase(myJoyList->getSelectedString());
|
||||
instance().eventHandler().removePhysicalJoystickFromDatabase(
|
||||
myJoyList->getSelectedString());
|
||||
loadConfig();
|
||||
break;
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ RadioButtonWidget::RadioButtonWidget(GuiObject* boss, const GUI::Font& font,
|
|||
RadioButtonGroup* group,
|
||||
int cmd)
|
||||
: CheckboxWidget(boss, font, x, y, label, cmd),
|
||||
myGroup(group)
|
||||
myGroup(group)
|
||||
{
|
||||
_flags = WIDGET_ENABLED;
|
||||
_bgcolor = _bgcolorhi = kWidColor;
|
||||
|
@ -164,7 +164,7 @@ void RadioButtonWidget::drawWidget(bool hilite)
|
|||
|
||||
// Draw the inner bounding circle with enabled color
|
||||
s.drawBitmap(radio_img_innercircle, _x + 1, _y + _boxY + 1, isEnabled()
|
||||
? _bgcolor : kColor, 12, 12);
|
||||
? _bgcolor : uInt32(kColor), 12, 12);
|
||||
|
||||
// draw state
|
||||
if(_state)
|
||||
|
|
|
@ -56,7 +56,7 @@ class RadioButtonWidget : public CheckboxWidget
|
|||
class RadioButtonGroup
|
||||
{
|
||||
public:
|
||||
RadioButtonGroup() = default;
|
||||
RadioButtonGroup() : mySelected(0) { }
|
||||
|
||||
// add widget to group
|
||||
void addWidget(RadioButtonWidget* widget);
|
||||
|
|
|
@ -39,7 +39,8 @@ Widget::Widget(GuiObject* boss, const GUI::Font& font,
|
|||
_bgcolor(kWidColor),
|
||||
_bgcolorhi(kWidColor),
|
||||
_textcolor(kTextColor),
|
||||
_textcolorhi(kTextColorHi)
|
||||
_textcolorhi(kTextColorHi),
|
||||
_shadowcolor(kShadowColor)
|
||||
{
|
||||
// Insert into the widget list of the boss
|
||||
_next = _boss->_firstWidget;
|
||||
|
@ -354,7 +355,10 @@ ButtonWidget::ButtonWidget(GuiObject* boss, const GUI::Font& font,
|
|||
: StaticTextWidget(boss, font, x, y, w, h, label, TextAlign::Center),
|
||||
CommandSender(boss),
|
||||
_cmd(cmd),
|
||||
_useBitmap(false)
|
||||
_useBitmap(false),
|
||||
_bitmap(nullptr),
|
||||
_bmw(0),
|
||||
_bmh(0)
|
||||
{
|
||||
_flags = WIDGET_ENABLED | WIDGET_CLEARBG;
|
||||
_bgcolor = kBtnColor;
|
||||
|
@ -621,8 +625,8 @@ void CheckboxWidget::drawWidget(bool hilite)
|
|||
if(_drawBox)
|
||||
s.frameRect(_x, _y + _boxY, 14, 14, hilite && isEnabled() && isEditable() ? kWidColorHi : kColor);
|
||||
// Do we draw a square or cross?
|
||||
s.fillRect(_x + 1, _y + _boxY + 1, 12, 12, _changed ? kDbgChangedColor
|
||||
: isEnabled() ? _bgcolor : kColor);
|
||||
s.fillRect(_x + 1, _y + _boxY + 1, 12, 12, _changed ? uInt32(kDbgChangedColor)
|
||||
: isEnabled() ? _bgcolor : uInt32(kColor));
|
||||
if(_state)
|
||||
s.drawBitmap(_img, _x + 2, _y + _boxY + 2, isEnabled() ? hilite && isEditable() ? kWidColorHi : kCheckColor
|
||||
: kColor, 10);
|
||||
|
|
|
@ -233,6 +233,8 @@
|
|||
DC1B2EC41E50036100F62837 /* AmigaMouse.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1B2EBE1E50036100F62837 /* AmigaMouse.hxx */; };
|
||||
DC1B2EC61E50036100F62837 /* AtariMouse.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1B2EC01E50036100F62837 /* AtariMouse.hxx */; };
|
||||
DC1B2EC81E50036100F62837 /* TrakBall.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1B2EC21E50036100F62837 /* TrakBall.hxx */; };
|
||||
DC1BC6662066B4390076F74A /* PKeyboardHandler.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC1BC6642066B4390076F74A /* PKeyboardHandler.cxx */; };
|
||||
DC1BC6672066B4390076F74A /* PKeyboardHandler.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1BC6652066B4390076F74A /* PKeyboardHandler.hxx */; };
|
||||
DC1FC18A0DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC1FC1880DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx */; };
|
||||
DC1FC18B0DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1FC1890DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx */; };
|
||||
DC2874071F8F2278004BF21A /* TrapArray.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2874061F8F2278004BF21A /* TrapArray.hxx */; };
|
||||
|
@ -319,7 +321,6 @@
|
|||
DC5D2C550F117CFD004D1660 /* StellaMediumFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5D2C510F117CFD004D1660 /* StellaMediumFont.hxx */; };
|
||||
DC5D2C600F129B1E004D1660 /* LauncherFilterDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC5D2C5E0F129B1E004D1660 /* LauncherFilterDialog.cxx */; };
|
||||
DC5D2C610F129B1E004D1660 /* LauncherFilterDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5D2C5F0F129B1E004D1660 /* LauncherFilterDialog.hxx */; };
|
||||
DC5E473B19EC9A14000E45DF /* EventJoyHandler.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC5E473A19EC9A14000E45DF /* EventJoyHandler.cxx */; };
|
||||
DC5EE7C214F7C165001C628C /* NTSCFilter.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC5EE7C014F7C165001C628C /* NTSCFilter.cxx */; };
|
||||
DC5EE7C314F7C165001C628C /* NTSCFilter.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5EE7C114F7C165001C628C /* NTSCFilter.hxx */; };
|
||||
DC62E6471960E87B007AEF05 /* AtariVoxWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC62E6431960E87B007AEF05 /* AtariVoxWidget.cxx */; };
|
||||
|
@ -372,6 +373,10 @@
|
|||
DC6C726313CDEA0A008A5975 /* LoggerDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC6C726113CDEA0A008A5975 /* LoggerDialog.hxx */; };
|
||||
DC6D39871A3CE65000171E71 /* CartWDWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC6D39851A3CE65000171E71 /* CartWDWidget.cxx */; };
|
||||
DC6D39881A3CE65000171E71 /* CartWDWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC6D39861A3CE65000171E71 /* CartWDWidget.hxx */; };
|
||||
DC6DC91E205DB879004A5FC3 /* PhysicalJoystick.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC6DC91A205DB879004A5FC3 /* PhysicalJoystick.cxx */; };
|
||||
DC6DC91F205DB879004A5FC3 /* PhysicalJoystick.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC6DC91B205DB879004A5FC3 /* PhysicalJoystick.hxx */; };
|
||||
DC6DC920205DB879004A5FC3 /* PJoystickHandler.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC6DC91C205DB879004A5FC3 /* PJoystickHandler.cxx */; };
|
||||
DC6DC921205DB879004A5FC3 /* PJoystickHandler.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC6DC91D205DB879004A5FC3 /* PJoystickHandler.hxx */; };
|
||||
DC71EA9D1FDA06D2008827CB /* CartE78K.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC71EA991FDA06D2008827CB /* CartE78K.cxx */; };
|
||||
DC71EA9E1FDA06D2008827CB /* CartE78K.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC71EA9A1FDA06D2008827CB /* CartE78K.hxx */; };
|
||||
DC71EA9F1FDA06D2008827CB /* CartMNetwork.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC71EA9B1FDA06D2008827CB /* CartMNetwork.cxx */; };
|
||||
|
@ -905,6 +910,8 @@
|
|||
DC1B2EBE1E50036100F62837 /* AmigaMouse.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AmigaMouse.hxx; sourceTree = "<group>"; };
|
||||
DC1B2EC01E50036100F62837 /* AtariMouse.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AtariMouse.hxx; sourceTree = "<group>"; };
|
||||
DC1B2EC21E50036100F62837 /* TrakBall.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrakBall.hxx; sourceTree = "<group>"; };
|
||||
DC1BC6642066B4390076F74A /* PKeyboardHandler.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PKeyboardHandler.cxx; sourceTree = "<group>"; };
|
||||
DC1BC6652066B4390076F74A /* PKeyboardHandler.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PKeyboardHandler.hxx; sourceTree = "<group>"; };
|
||||
DC1FC1880DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SerialPortMACOSX.cxx; sourceTree = "<group>"; };
|
||||
DC1FC1890DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = SerialPortMACOSX.hxx; sourceTree = "<group>"; };
|
||||
DC2874061F8F2278004BF21A /* TrapArray.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrapArray.hxx; sourceTree = "<group>"; };
|
||||
|
@ -991,7 +998,6 @@
|
|||
DC5D2C510F117CFD004D1660 /* StellaMediumFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StellaMediumFont.hxx; sourceTree = "<group>"; };
|
||||
DC5D2C5E0F129B1E004D1660 /* LauncherFilterDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LauncherFilterDialog.cxx; sourceTree = "<group>"; };
|
||||
DC5D2C5F0F129B1E004D1660 /* LauncherFilterDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LauncherFilterDialog.hxx; sourceTree = "<group>"; };
|
||||
DC5E473A19EC9A14000E45DF /* EventJoyHandler.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventJoyHandler.cxx; sourceTree = "<group>"; };
|
||||
DC5EE7C014F7C165001C628C /* NTSCFilter.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NTSCFilter.cxx; sourceTree = "<group>"; };
|
||||
DC5EE7C114F7C165001C628C /* NTSCFilter.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = NTSCFilter.hxx; sourceTree = "<group>"; };
|
||||
DC62E6431960E87B007AEF05 /* AtariVoxWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AtariVoxWidget.cxx; sourceTree = "<group>"; };
|
||||
|
@ -1044,6 +1050,10 @@
|
|||
DC6C726113CDEA0A008A5975 /* LoggerDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LoggerDialog.hxx; sourceTree = "<group>"; };
|
||||
DC6D39851A3CE65000171E71 /* CartWDWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartWDWidget.cxx; sourceTree = "<group>"; };
|
||||
DC6D39861A3CE65000171E71 /* CartWDWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartWDWidget.hxx; sourceTree = "<group>"; };
|
||||
DC6DC91A205DB879004A5FC3 /* PhysicalJoystick.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PhysicalJoystick.cxx; sourceTree = "<group>"; };
|
||||
DC6DC91B205DB879004A5FC3 /* PhysicalJoystick.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PhysicalJoystick.hxx; sourceTree = "<group>"; };
|
||||
DC6DC91C205DB879004A5FC3 /* PJoystickHandler.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PJoystickHandler.cxx; sourceTree = "<group>"; };
|
||||
DC6DC91D205DB879004A5FC3 /* PJoystickHandler.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PJoystickHandler.hxx; sourceTree = "<group>"; };
|
||||
DC71EA991FDA06D2008827CB /* CartE78K.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartE78K.cxx; sourceTree = "<group>"; };
|
||||
DC71EA9A1FDA06D2008827CB /* CartE78K.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartE78K.hxx; sourceTree = "<group>"; };
|
||||
DC71EA9B1FDA06D2008827CB /* CartMNetwork.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartMNetwork.cxx; sourceTree = "<group>"; };
|
||||
|
@ -1593,6 +1603,12 @@
|
|||
DCB87E571A104C1E00BF2A3B /* MediaFactory.hxx */,
|
||||
DC56FCDC14CCCC4900A31CC3 /* MouseControl.cxx */,
|
||||
DC56FCDD14CCCC4900A31CC3 /* MouseControl.hxx */,
|
||||
DC6DC91A205DB879004A5FC3 /* PhysicalJoystick.cxx */,
|
||||
DC6DC91B205DB879004A5FC3 /* PhysicalJoystick.hxx */,
|
||||
DC6DC91C205DB879004A5FC3 /* PJoystickHandler.cxx */,
|
||||
DC6DC91D205DB879004A5FC3 /* PJoystickHandler.hxx */,
|
||||
DC1BC6642066B4390076F74A /* PKeyboardHandler.cxx */,
|
||||
DC1BC6652066B4390076F74A /* PKeyboardHandler.hxx */,
|
||||
DCD6FC9111C28C6F005DA767 /* PNGLibrary.cxx */,
|
||||
DCD6FC9211C28C6F005DA767 /* PNGLibrary.hxx */,
|
||||
DCDDEAC01F5DBF0400C67366 /* RewindManager.cxx */,
|
||||
|
@ -1754,7 +1770,6 @@
|
|||
2D733D6E062895B2006265D9 /* EventHandler.cxx */,
|
||||
2D733D6F062895B2006265D9 /* EventHandler.hxx */,
|
||||
DC5AAC261FCB24AB00C420A6 /* EventHandlerConstants.hxx */,
|
||||
DC5E473A19EC9A14000E45DF /* EventJoyHandler.cxx */,
|
||||
DC73BD871915E5E3003FAFAD /* FBSurface.cxx */,
|
||||
DC73BD881915E5E3003FAFAD /* FBSurface.hxx */,
|
||||
2D733D70062895B2006265D9 /* FrameBuffer.cxx */,
|
||||
|
@ -2264,6 +2279,7 @@
|
|||
2D91746109BA90380026E9FF /* TogglePixelWidget.hxx in Headers */,
|
||||
2D91746209BA90380026E9FF /* ToggleWidget.hxx in Headers */,
|
||||
2D91746409BA90380026E9FF /* TiaZoomWidget.hxx in Headers */,
|
||||
DC1BC6672066B4390076F74A /* PKeyboardHandler.hxx in Headers */,
|
||||
2D91746609BA90380026E9FF /* AudioWidget.hxx in Headers */,
|
||||
2D91746909BA90380026E9FF /* EventMappingWidget.hxx in Headers */,
|
||||
2D91746A09BA90380026E9FF /* InputDialog.hxx in Headers */,
|
||||
|
@ -2280,6 +2296,7 @@
|
|||
DC8078EB0B4BD697005E9305 /* UIDialog.hxx in Headers */,
|
||||
DCEECE570B5E5E540021D754 /* Cart0840.hxx in Headers */,
|
||||
DCE3BBFA0C95CEDC00A671DF /* RomInfoWidget.hxx in Headers */,
|
||||
DC6DC91F205DB879004A5FC3 /* PhysicalJoystick.hxx in Headers */,
|
||||
DC0984860D3985160073C852 /* CartSB.hxx in Headers */,
|
||||
DCEC585E1E945175002F0246 /* DelayQueueIterator.hxx in Headers */,
|
||||
DCA23AEA0D75B22500F77B33 /* CartX07.hxx in Headers */,
|
||||
|
@ -2376,6 +2393,7 @@
|
|||
DCAAE5DA1715887B0080BB82 /* Cart0840Widget.hxx in Headers */,
|
||||
DCAAE5DC1715887B0080BB82 /* CartCVWidget.hxx in Headers */,
|
||||
DCAAE5DD1715887B0080BB82 /* CartDebugWidget.hxx in Headers */,
|
||||
DC6DC921205DB879004A5FC3 /* PJoystickHandler.hxx in Headers */,
|
||||
DCAAE5DF1715887B0080BB82 /* CartEFSCWidget.hxx in Headers */,
|
||||
DCAAE5E11715887B0080BB82 /* CartEFWidget.hxx in Headers */,
|
||||
DCAAE5E31715887B0080BB82 /* CartF0Widget.hxx in Headers */,
|
||||
|
@ -2562,6 +2580,7 @@
|
|||
DCF3A6FA1DFC75E3008A8AF3 /* Player.cxx in Sources */,
|
||||
2D91748609BA90380026E9FF /* CartFE.cxx in Sources */,
|
||||
2D91748909BA90380026E9FF /* Console.cxx in Sources */,
|
||||
DC6DC91E205DB879004A5FC3 /* PhysicalJoystick.cxx in Sources */,
|
||||
2D91748A09BA90380026E9FF /* Control.cxx in Sources */,
|
||||
2D91748C09BA90380026E9FF /* Driving.cxx in Sources */,
|
||||
E0306E101F93E916003DDD52 /* FrameLayoutDetector.cxx in Sources */,
|
||||
|
@ -2594,7 +2613,6 @@
|
|||
2D9174B309BA90380026E9FF /* LauncherDialog.cxx in Sources */,
|
||||
2D9174B509BA90380026E9FF /* ListWidget.cxx in Sources */,
|
||||
2D9174B609BA90380026E9FF /* Menu.cxx in Sources */,
|
||||
DC5E473B19EC9A14000E45DF /* EventJoyHandler.cxx in Sources */,
|
||||
CFE3F60D1E84A9A200A8204E /* CartCDFWidget.cxx in Sources */,
|
||||
2D9174B709BA90380026E9FF /* OptionsDialog.cxx in Sources */,
|
||||
2D9174B809BA90380026E9FF /* PopUpWidget.cxx in Sources */,
|
||||
|
@ -2630,6 +2648,7 @@
|
|||
2D9174CE09BA90380026E9FF /* Cart3E.cxx in Sources */,
|
||||
2D9174CF09BA90380026E9FF /* CpuDebug.cxx in Sources */,
|
||||
2D9174F109BA90380026E9FF /* InputTextDialog.cxx in Sources */,
|
||||
DC6DC920205DB879004A5FC3 /* PJoystickHandler.cxx in Sources */,
|
||||
DC74E5C6198AF12700F37E36 /* CartDASHWidget.cxx in Sources */,
|
||||
2D9174F209BA90380026E9FF /* CheckListWidget.cxx in Sources */,
|
||||
2D9174F309BA90380026E9FF /* StringListWidget.cxx in Sources */,
|
||||
|
@ -2740,6 +2759,7 @@
|
|||
DC9616301F817830008A2206 /* FlashWidget.cxx in Sources */,
|
||||
DCFFE59D12100E1400DFA000 /* ComboDialog.cxx in Sources */,
|
||||
DCD2839812E39F1200A808DC /* Thumbulator.cxx in Sources */,
|
||||
DC1BC6662066B4390076F74A /* PKeyboardHandler.cxx in Sources */,
|
||||
DC6C726213CDEA0A008A5975 /* LoggerDialog.cxx in Sources */,
|
||||
DC8C1BAD14B25DE7006440EE /* CartCM.cxx in Sources */,
|
||||
DCDDEAC61F5DBF0400C67366 /* StateManager.cxx in Sources */,
|
||||
|
|
|
@ -236,6 +236,9 @@
|
|||
<ClCompile Include="..\common\FSNodeZIP.cxx" />
|
||||
<ClCompile Include="..\common\main.cxx" />
|
||||
<ClCompile Include="..\common\MouseControl.cxx" />
|
||||
<ClCompile Include="..\common\PhysicalJoystick.cxx" />
|
||||
<ClCompile Include="..\common\PJoystickHandler.cxx" />
|
||||
<ClCompile Include="..\common\PKeyboardHandler.cxx" />
|
||||
<ClCompile Include="..\common\RewindManager.cxx" />
|
||||
<ClCompile Include="..\common\StateManager.cxx" />
|
||||
<ClCompile Include="..\common\tv_filters\AtariNTSC.cxx" />
|
||||
|
@ -321,7 +324,6 @@
|
|||
<ClCompile Include="..\emucore\CartE78K.cxx" />
|
||||
<ClCompile Include="..\emucore\CartWD.cxx" />
|
||||
<ClCompile Include="..\emucore\CompuMate.cxx" />
|
||||
<ClCompile Include="..\emucore\EventJoyHandler.cxx" />
|
||||
<ClCompile Include="..\emucore\FBSurface.cxx" />
|
||||
<ClCompile Include="..\emucore\MindLink.cxx" />
|
||||
<ClCompile Include="..\emucore\PointingDevice.cxx" />
|
||||
|
@ -522,6 +524,9 @@
|
|||
<ClInclude Include="..\common\LinkedObjectPool.hxx" />
|
||||
<ClInclude Include="..\common\MediaFactory.hxx" />
|
||||
<ClInclude Include="..\common\MouseControl.hxx" />
|
||||
<ClInclude Include="..\common\PhysicalJoystick.hxx" />
|
||||
<ClInclude Include="..\common\PJoystickHandler.hxx" />
|
||||
<ClInclude Include="..\common\PKeyboardHandler.hxx" />
|
||||
<ClInclude Include="..\common\RewindManager.hxx" />
|
||||
<ClInclude Include="..\common\StateManager.hxx" />
|
||||
<ClInclude Include="..\common\StellaKeys.hxx" />
|
||||
|
|
|
@ -741,9 +741,6 @@
|
|||
<ClCompile Include="..\debugger\gui\CartMDMWidget.cxx">
|
||||
<Filter>Source Files\debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\emucore\EventJoyHandler.cxx">
|
||||
<Filter>Source Files\emucore</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\main.cxx">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -899,6 +896,15 @@
|
|||
<ClCompile Include="..\gui\TimeLineWidget.cxx">
|
||||
<Filter>Source Files\gui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\PhysicalJoystick.cxx">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\PJoystickHandler.cxx">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\PKeyboardHandler.cxx">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\common\bspf.hxx">
|
||||
|
@ -1839,6 +1845,15 @@
|
|||
<ClInclude Include="..\gui\TimeLineWidget.hxx">
|
||||
<Filter>Header Files\gui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\PhysicalJoystick.hxx">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\PJoystickHandler.hxx">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\PKeyboardHandler.hxx">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="stella.ico">
|
||||
|
|
Loading…
Reference in New Issue