mirror of https://github.com/stella-emu/stella.git
First pass at reworking EventHandler, splitting it up into more manageable pieces.
For now, joystick-related stuff is moved into its own classes. No improvements are made yet; just refactoring and moving code around. This reduces EventHandler from ~2500 lines to ~2000 lines.
This commit is contained in:
parent
593ec2fdc9
commit
76b6026d30
|
@ -96,8 +96,8 @@ void EventHandlerSDL2::pollEvent()
|
||||||
case SDL_JOYBUTTONUP:
|
case SDL_JOYBUTTONUP:
|
||||||
case SDL_JOYBUTTONDOWN:
|
case SDL_JOYBUTTONDOWN:
|
||||||
{
|
{
|
||||||
handleJoyEvent(myEvent.jbutton.which, myEvent.jbutton.button,
|
handleJoyBtnEvent(myEvent.jbutton.which, myEvent.jbutton.button,
|
||||||
myEvent.jbutton.state == SDL_PRESSED ? 1 : 0);
|
myEvent.jbutton.state == SDL_PRESSED ? 1 : 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,12 +127,12 @@ void EventHandlerSDL2::pollEvent()
|
||||||
|
|
||||||
case SDL_JOYDEVICEADDED:
|
case SDL_JOYDEVICEADDED:
|
||||||
{
|
{
|
||||||
addJoystick(new JoystickSDL2(myEvent.jdevice.which));
|
addPhysicalJoystick(new JoystickSDL2(myEvent.jdevice.which));
|
||||||
break; // SDL_JOYDEVICEADDED
|
break; // SDL_JOYDEVICEADDED
|
||||||
}
|
}
|
||||||
case SDL_JOYDEVICEREMOVED:
|
case SDL_JOYDEVICEREMOVED:
|
||||||
{
|
{
|
||||||
removeJoystick(myEvent.jdevice.which);
|
removePhysicalJoystick(myEvent.jdevice.which);
|
||||||
break; // SDL_JOYDEVICEREMOVED
|
break; // SDL_JOYDEVICEREMOVED
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "SDL_lib.hxx"
|
#include "SDL_lib.hxx"
|
||||||
#include "EventHandler.hxx"
|
#include "EventHandler.hxx"
|
||||||
|
#include "PhysicalJoystick.hxx"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This class handles event collection from the point of view of the specific
|
This class handles event collection from the point of view of the specific
|
||||||
|
@ -58,9 +59,9 @@ class EventHandlerSDL2 : public EventHandler
|
||||||
private:
|
private:
|
||||||
SDL_Event myEvent;
|
SDL_Event myEvent;
|
||||||
|
|
||||||
// A thin wrapper around a basic StellaJoystick, holding the pointer to
|
// A thin wrapper around a basic PhysicalJoystick, holding the pointer to
|
||||||
// the underlying SDL stick.
|
// the underlying SDL joystick device.
|
||||||
class JoystickSDL2 : public StellaJoystick
|
class JoystickSDL2 : public PhysicalJoystick
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
JoystickSDL2(int idx);
|
JoystickSDL2(int idx);
|
||||||
|
|
|
@ -0,0 +1,759 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
PhysicalJoystickHandler::~PhysicalJoystickHandler()
|
||||||
|
{
|
||||||
|
for(const auto& i: myDatabase)
|
||||||
|
delete i.second.joy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void PhysicalJoystickHandler::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
int PhysicalJoystickHandler::add(PhysicalJoystick* 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"))
|
||||||
|
{
|
||||||
|
// 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 = 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
|
||||||
|
{
|
||||||
|
PhysicalJoystick* 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(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 PhysicalJoystick* 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;
|
||||||
|
case JoyHat::CENTER: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool PhysicalJoystickHandler::addAxisMapping(Event::Type event, EventMode mode,
|
||||||
|
int stick, int axis, int value)
|
||||||
|
{
|
||||||
|
const PhysicalJoystick* 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 PhysicalJoystick* 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 PhysicalJoystick* 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 PhysicalJoystick* 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_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(axis < 2)
|
||||||
|
myEvent.set(SA_Axis[j->type-2][axis], value);
|
||||||
|
break; // Stelladaptor axis
|
||||||
|
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(axis < 2)
|
||||||
|
myEvent.set(SA_Axis[j->type-4][axis], value);
|
||||||
|
break; // 2600-daptor axis
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void PhysicalJoystickHandler::handleBtnEvent(int stick, int button, uInt8 state)
|
||||||
|
{
|
||||||
|
const PhysicalJoystick* 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.eventStateChange(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 PhysicalJoystick* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
// 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,130 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// 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"
|
||||||
|
|
||||||
|
/**
|
||||||
|
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, PhysicalJoystick* stick = nullptr)
|
||||||
|
: mapping(map), joy(stick) {}
|
||||||
|
|
||||||
|
string mapping;
|
||||||
|
PhysicalJoystick* 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, PhysicalJoystick*>;
|
||||||
|
|
||||||
|
PhysicalJoystickHandler(OSystem& system, EventHandler& handler, Event& event);
|
||||||
|
~PhysicalJoystickHandler();
|
||||||
|
|
||||||
|
/** Return stick ID on success, -1 on failure. */
|
||||||
|
int add(PhysicalJoystick* 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 PhysicalJoystick* j = joy(stick);
|
||||||
|
return j ? j->axisTable[axis][(value > 0)][mode] : Event::NoType;
|
||||||
|
}
|
||||||
|
Event::Type eventForButton(int stick, int button, EventMode mode) const {
|
||||||
|
const PhysicalJoystick* j = joy(stick);
|
||||||
|
return j ? j->btnTable[button][mode] : Event::NoType;
|
||||||
|
}
|
||||||
|
Event::Type eventForHat(int stick, int hat, JoyHat value, EventMode mode) const {
|
||||||
|
const PhysicalJoystick* j = joy(stick);
|
||||||
|
return j ? j->hatTable[hat][int(value)][mode] : Event::NoType;
|
||||||
|
}
|
||||||
|
|
||||||
|
VariantList database() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
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 PhysicalJoystick* joy(int id) const {
|
||||||
|
const auto& i = mySticks.find(id);
|
||||||
|
return i != mySticks.cend() ? i->second : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setStickDefaultMapping(int stick, Event::Type type, EventMode mode);
|
||||||
|
void printDatabase() const;
|
||||||
|
|
||||||
|
// 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,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 STELLA_JOYSTICK_HXX
|
||||||
|
#define STELLA_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
|
|
@ -1,16 +1,18 @@
|
||||||
MODULE := src/common
|
MODULE := src/common
|
||||||
|
|
||||||
MODULE_OBJS := \
|
MODULE_OBJS := \
|
||||||
src/common/main.o \
|
|
||||||
src/common/Base.o \
|
src/common/Base.o \
|
||||||
src/common/EventHandlerSDL2.o \
|
src/common/EventHandlerSDL2.o \
|
||||||
src/common/FrameBufferSDL2.o \
|
|
||||||
src/common/FBSurfaceSDL2.o \
|
src/common/FBSurfaceSDL2.o \
|
||||||
src/common/SoundSDL2.o \
|
src/common/FrameBufferSDL2.o \
|
||||||
src/common/FSNodeZIP.o \
|
src/common/FSNodeZIP.o \
|
||||||
src/common/PNGLibrary.o \
|
src/common/main.o \
|
||||||
src/common/MouseControl.o \
|
src/common/MouseControl.o \
|
||||||
|
src/common/PhysicalJoystick.o \
|
||||||
|
src/common/PJoystickHandler.o \
|
||||||
|
src/common/PNGLibrary.o \
|
||||||
src/common/RewindManager.o \
|
src/common/RewindManager.o \
|
||||||
|
src/common/SoundSDL2.o \
|
||||||
src/common/StateManager.o \
|
src/common/StateManager.o \
|
||||||
src/common/ZipHandler.o
|
src/common/ZipHandler.o
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "StellaKeys.hxx"
|
#include "StellaKeys.hxx"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@author Bradford W. Mott
|
@author Bradford W. Mott, Stephen Anthony
|
||||||
*/
|
*/
|
||||||
class Event
|
class Event
|
||||||
{
|
{
|
||||||
|
@ -82,23 +82,23 @@ class Event
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
Create a new event object
|
Create a new event object.
|
||||||
*/
|
*/
|
||||||
Event() { clear(); }
|
Event() { clear(); }
|
||||||
|
|
||||||
public:
|
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]; }
|
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; }
|
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()
|
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; }
|
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; }
|
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:
|
private:
|
||||||
// Array of values associated with each event type
|
// Array of values associated with each event type
|
||||||
Int32 myValues[LastType];
|
Int32 myValues[LastType];
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "OSystem.hxx"
|
#include "OSystem.hxx"
|
||||||
#include "Joystick.hxx"
|
#include "Joystick.hxx"
|
||||||
#include "Paddles.hxx"
|
#include "Paddles.hxx"
|
||||||
|
#include "PJoystickHandler.hxx"
|
||||||
#include "PointingDevice.hxx"
|
#include "PointingDevice.hxx"
|
||||||
#include "PropsSet.hxx"
|
#include "PropsSet.hxx"
|
||||||
#include "ListWidget.hxx"
|
#include "ListWidget.hxx"
|
||||||
|
@ -81,8 +82,8 @@ EventHandler::EventHandler(OSystem& osystem)
|
||||||
for(int j = 0; j < kEventsPerCombo; ++j)
|
for(int j = 0; j < kEventsPerCombo; ++j)
|
||||||
myComboTable[i][j] = Event::NoType;
|
myComboTable[i][j] = Event::NoType;
|
||||||
|
|
||||||
// Create joystick handler (to handle all joystick functionality)
|
// Create joystick handler (to handle all physical joystick functionality)
|
||||||
myJoyHandler = make_unique<JoystickHandler>(osystem);
|
myPJoyHandler = make_unique<PhysicalJoystickHandler>(osystem, *this, myEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -134,40 +135,28 @@ void EventHandler::reset(EventHandlerState state)
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void EventHandler::addJoystick(StellaJoystick* stick)
|
void EventHandler::addPhysicalJoystick(PhysicalJoystick* joy)
|
||||||
{
|
{
|
||||||
#ifdef JOYSTICK_SUPPORT
|
#ifdef JOYSTICK_SUPPORT
|
||||||
if(!myJoyHandler->add(stick))
|
int ID = myPJoyHandler->add(joy);
|
||||||
|
if(ID < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
setActionMappings(kEmulationMode);
|
setActionMappings(kEmulationMode);
|
||||||
setActionMappings(kMenuMode);
|
setActionMappings(kMenuMode);
|
||||||
|
|
||||||
ostringstream buf;
|
ostringstream buf;
|
||||||
buf << "Added joystick " << stick->ID << ":" << endl
|
buf << "Added joystick " << ID << ":" << endl
|
||||||
<< " " << stick->about() << endl;
|
<< " " << joy->about() << endl;
|
||||||
myOSystem.logMessage(buf.str(), 1);
|
myOSystem.logMessage(buf.str(), 1);
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void EventHandler::removeJoystick(int id)
|
void EventHandler::removePhysicalJoystick(int id)
|
||||||
{
|
{
|
||||||
#ifdef JOYSTICK_SUPPORT
|
#ifdef JOYSTICK_SUPPORT
|
||||||
myJoyHandler->remove(id);
|
myPJoyHandler->remove(id);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +164,7 @@ void EventHandler::removeJoystick(int id)
|
||||||
void EventHandler::mapStelladaptors(const string& saport)
|
void EventHandler::mapStelladaptors(const string& saport)
|
||||||
{
|
{
|
||||||
#ifdef JOYSTICK_SUPPORT
|
#ifdef JOYSTICK_SUPPORT
|
||||||
myJoyHandler->mapStelladaptors(saport);
|
myPJoyHandler->mapStelladaptors(saport);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -692,211 +681,6 @@ void EventHandler::handleMouseButtonEvent(MouseButton b, bool pressed,
|
||||||
myOverlay->handleMouseButtonEvent(b, pressed, x, y);
|
myOverlay->handleMouseButtonEvent(b, pressed, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void EventHandler::handleJoyEvent(int stick, int button, uInt8 state)
|
|
||||||
{
|
|
||||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
|
||||||
if(!joy) return;
|
|
||||||
|
|
||||||
// Stelladaptors handle buttons differently than regular joysticks
|
|
||||||
switch(joy->type)
|
|
||||||
{
|
|
||||||
case StellaJoystick::JT_REGULAR:
|
|
||||||
// Handle buttons which switch eventhandler state
|
|
||||||
if(state && eventStateChange(joy->btnTable[button][kEmulationMode]))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Determine which mode we're in, then send the event to the appropriate place
|
|
||||||
if(myState == EventHandlerState::EMULATION)
|
|
||||||
handleEvent(joy->btnTable[button][kEmulationMode], state);
|
|
||||||
else if(myOverlay)
|
|
||||||
myOverlay->handleJoyEvent(stick, button, state);
|
|
||||||
break; // Regular button
|
|
||||||
|
|
||||||
// These events don't have to pass through handleEvent, since
|
|
||||||
// they can never be remapped
|
|
||||||
case StellaJoystick::JT_STELLADAPTOR_LEFT:
|
|
||||||
case StellaJoystick::JT_STELLADAPTOR_RIGHT:
|
|
||||||
// The 'type-2' here refers to the fact that 'StellaJoystick::JT_STELLADAPTOR_LEFT'
|
|
||||||
// and 'StellaJoystick::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[joy->type-2][button], state);
|
|
||||||
break; // Stelladaptor button
|
|
||||||
case StellaJoystick::JT_2600DAPTOR_LEFT:
|
|
||||||
case StellaJoystick::JT_2600DAPTOR_RIGHT:
|
|
||||||
// The 'type-4' here refers to the fact that 'StellaJoystick::JT_2600DAPTOR_LEFT'
|
|
||||||
// and 'StellaJoystick::JT_2600DAPTOR_RIGHT' are at index 4 and 5 in the JoyType
|
|
||||||
// enum; subtracting four gives us Controller 0 and 1
|
|
||||||
if(myState == EventHandlerState::EMULATION)
|
|
||||||
{
|
|
||||||
switch(myOSystem.console().leftController().type())
|
|
||||||
{
|
|
||||||
case Controller::Keyboard:
|
|
||||||
if(button < 12) myEvent.set(SA_Key[joy->type-4][button], state);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if(button < 4) myEvent.set(SA_Button[joy->type-4][button], state);
|
|
||||||
}
|
|
||||||
switch(myOSystem.console().rightController().type())
|
|
||||||
{
|
|
||||||
case Controller::Keyboard:
|
|
||||||
if(button < 12) myEvent.set(SA_Key[joy->type-4][button], state);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if(button < 4) myEvent.set(SA_Button[joy->type-4][button], state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break; // 2600DAPTOR button
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void EventHandler::handleJoyAxisEvent(int stick, int axis, int value)
|
|
||||||
{
|
|
||||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
|
||||||
if(!joy) return;
|
|
||||||
|
|
||||||
// Stelladaptors handle axis differently than regular joysticks
|
|
||||||
switch(joy->type)
|
|
||||||
{
|
|
||||||
case StellaJoystick::JT_REGULAR:
|
|
||||||
if(myState == EventHandlerState::EMULATION)
|
|
||||||
{
|
|
||||||
// Every axis event has two associated values, negative and positive
|
|
||||||
Event::Type eventAxisNeg = joy->axisTable[axis][0][kEmulationMode];
|
|
||||||
Event::Type eventAxisPos = joy->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())
|
|
||||||
handleEvent(eventAxisPos, 1);
|
|
||||||
else if(value < -Joystick::deadzone())
|
|
||||||
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(joy->axisLastValue[axis] != value)
|
|
||||||
{
|
|
||||||
// Turn off both events, since we don't know exactly which one
|
|
||||||
// was previously activated.
|
|
||||||
handleEvent(eventAxisNeg, 0);
|
|
||||||
handleEvent(eventAxisPos, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
joy->axisLastValue[axis] = value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(myOverlay)
|
|
||||||
{
|
|
||||||
// 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 != joy->axisLastValue[axis])
|
|
||||||
{
|
|
||||||
myOverlay->handleJoyAxisEvent(stick, axis, value);
|
|
||||||
joy->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 StellaJoystick::JT_STELLADAPTOR_LEFT:
|
|
||||||
case StellaJoystick::JT_STELLADAPTOR_RIGHT:
|
|
||||||
// The 'type-2' here refers to the fact that 'StellaJoystick::JT_STELLADAPTOR_LEFT'
|
|
||||||
// and 'StellaJoystick::JT_STELLADAPTOR_RIGHT' are at index 2 and 3 in the JoyType
|
|
||||||
// enum; subtracting two gives us Controller 0 and 1
|
|
||||||
if(axis < 2)
|
|
||||||
myEvent.set(SA_Axis[joy->type-2][axis], value);
|
|
||||||
break; // Stelladaptor axis
|
|
||||||
case StellaJoystick::JT_2600DAPTOR_LEFT:
|
|
||||||
case StellaJoystick::JT_2600DAPTOR_RIGHT:
|
|
||||||
// The 'type-4' here refers to the fact that 'StellaJoystick::JT_2600DAPTOR_LEFT'
|
|
||||||
// and 'StellaJoystick::JT_2600DAPTOR_RIGHT' are at index 4 and 5 in the JoyType
|
|
||||||
// enum; subtracting four gives us Controller 0 and 1
|
|
||||||
if(axis < 2)
|
|
||||||
myEvent.set(SA_Axis[joy->type-4][axis], value);
|
|
||||||
break; // 2600-daptor axis
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void EventHandler::handleJoyHatEvent(int stick, int hat, int value)
|
|
||||||
{
|
|
||||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
|
||||||
if(!joy) return;
|
|
||||||
|
|
||||||
// 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(myState == EventHandlerState::EMULATION)
|
|
||||||
{
|
|
||||||
handleEvent(joy->hatTable[hat][int(JoyHat::UP)][kEmulationMode],
|
|
||||||
value & EVENT_HATUP_M);
|
|
||||||
handleEvent(joy->hatTable[hat][int(JoyHat::RIGHT)][kEmulationMode],
|
|
||||||
value & EVENT_HATRIGHT_M);
|
|
||||||
handleEvent(joy->hatTable[hat][int(JoyHat::DOWN)][kEmulationMode],
|
|
||||||
value & EVENT_HATDOWN_M);
|
|
||||||
handleEvent(joy->hatTable[hat][int(JoyHat::LEFT)][kEmulationMode],
|
|
||||||
value & EVENT_HATLEFT_M);
|
|
||||||
}
|
|
||||||
else if(myOverlay)
|
|
||||||
{
|
|
||||||
if(value == EVENT_HATCENTER_M)
|
|
||||||
myOverlay->handleJoyHatEvent(stick, hat, JoyHat::CENTER);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(value & EVENT_HATUP_M)
|
|
||||||
myOverlay->handleJoyHatEvent(stick, hat, JoyHat::UP);
|
|
||||||
if(value & EVENT_HATRIGHT_M)
|
|
||||||
myOverlay->handleJoyHatEvent(stick, hat, JoyHat::RIGHT);
|
|
||||||
if(value & EVENT_HATDOWN_M)
|
|
||||||
myOverlay->handleJoyHatEvent(stick, hat, JoyHat::DOWN);
|
|
||||||
if(value & EVENT_HATLEFT_M)
|
|
||||||
myOverlay->handleJoyHatEvent(stick, hat, JoyHat::LEFT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void EventHandler::handleSystemEvent(SystemEvent e, int, int)
|
void EventHandler::handleSystemEvent(SystemEvent e, int, int)
|
||||||
{
|
{
|
||||||
|
@ -1289,8 +1073,6 @@ void EventHandler::setActionMappings(EventMode mode)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ostringstream buf;
|
|
||||||
|
|
||||||
// Fill the ActionList with the current key and joystick mappings
|
// Fill the ActionList with the current key and joystick mappings
|
||||||
for(int i = 0; i < listsize; ++i)
|
for(int i = 0; i < listsize; ++i)
|
||||||
{
|
{
|
||||||
|
@ -1309,77 +1091,12 @@ void EventHandler::setActionMappings(EventMode mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JOYSTICK_SUPPORT
|
#ifdef JOYSTICK_SUPPORT
|
||||||
for(const auto& st: myJoyHandler->sticks())
|
string joydesc = myPJoyHandler->getMappingDesc(event, mode);
|
||||||
|
if(joydesc != "")
|
||||||
{
|
{
|
||||||
uInt32 stick = st.first;
|
if(key != "")
|
||||||
const StellaJoystick* joy = st.second;
|
key += ", ";
|
||||||
if(!joy) continue;
|
key += joydesc;
|
||||||
|
|
||||||
// Joystick button mapping/labeling
|
|
||||||
for(int button = 0; button < joy->numButtons; ++button)
|
|
||||||
{
|
|
||||||
if(joy->btnTable[button][mode] == event)
|
|
||||||
{
|
|
||||||
buf.str("");
|
|
||||||
buf << "J" << stick << "/B" << button;
|
|
||||||
if(key == "")
|
|
||||||
key = key + buf.str();
|
|
||||||
else
|
|
||||||
key = key + ", " + buf.str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Joystick axis mapping/labeling
|
|
||||||
for(int axis = 0; axis < joy->numAxes; ++axis)
|
|
||||||
{
|
|
||||||
for(int dir = 0; dir < 2; ++dir)
|
|
||||||
{
|
|
||||||
if(joy->axisTable[axis][dir][mode] == event)
|
|
||||||
{
|
|
||||||
buf.str("");
|
|
||||||
buf << "J" << stick << "/A" << axis;
|
|
||||||
if(eventIsAnalog(event))
|
|
||||||
{
|
|
||||||
dir = 2; // Immediately exit the inner loop after this iteration
|
|
||||||
buf << "/+|-";
|
|
||||||
}
|
|
||||||
else if(dir == 0)
|
|
||||||
buf << "/-";
|
|
||||||
else
|
|
||||||
buf << "/+";
|
|
||||||
|
|
||||||
if(key == "")
|
|
||||||
key = key + buf.str();
|
|
||||||
else
|
|
||||||
key = key + ", " + buf.str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Joystick hat mapping/labeling
|
|
||||||
for(int hat = 0; hat < joy->numHats; ++hat)
|
|
||||||
{
|
|
||||||
for(int dir = 0; dir < 4; ++dir)
|
|
||||||
{
|
|
||||||
if(joy->hatTable[hat][dir][mode] == event)
|
|
||||||
{
|
|
||||||
buf.str("");
|
|
||||||
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;
|
|
||||||
case JoyHat::CENTER: break;
|
|
||||||
}
|
|
||||||
if(key == "")
|
|
||||||
key = key + buf.str();
|
|
||||||
else
|
|
||||||
key = key + ", " + buf.str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1487,26 +1204,18 @@ void EventHandler::setComboMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
VariantList EventHandler::joystickDatabase() const
|
void EventHandler::removePhysicalJoystickFromDatabase(const string& name)
|
||||||
{
|
{
|
||||||
VariantList db;
|
#ifdef JOYSTICK_SUPPORT
|
||||||
for(const auto& i: myJoyHandler->database())
|
myPJoyHandler->remove(name);
|
||||||
VarList::push_back(db, i.first, i.second.joy ? i.second.joy->ID : -1);
|
#endif
|
||||||
|
|
||||||
return db;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void EventHandler::removeJoystickFromDatabase(const string& name)
|
|
||||||
{
|
|
||||||
myJoyHandler->remove(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool EventHandler::addKeyMapping(Event::Type event, EventMode mode, StellaKey key)
|
bool EventHandler::addKeyMapping(Event::Type event, EventMode mode, StellaKey key)
|
||||||
{
|
{
|
||||||
// These keys cannot be remapped
|
// These keys cannot be remapped
|
||||||
if(key == KBDK_TAB || eventIsAnalog(event))
|
if(key == KBDK_TAB || Event::isAnalog(event))
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1523,33 +1232,14 @@ bool EventHandler::addJoyAxisMapping(Event::Type event, EventMode mode,
|
||||||
bool updateMenus)
|
bool updateMenus)
|
||||||
{
|
{
|
||||||
#ifdef JOYSTICK_SUPPORT
|
#ifdef JOYSTICK_SUPPORT
|
||||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
bool mapped = myPJoyHandler->addAxisMapping(event, mode, stick, axis, value);
|
||||||
if(joy)
|
if(mapped && updateMenus)
|
||||||
{
|
setActionMappings(mode);
|
||||||
if(axis >= 0 && axis < joy->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(eventIsAnalog(event))
|
|
||||||
joy->axisTable[axis][0][mode] =
|
|
||||||
joy->axisTable[axis][1][mode] = event;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Otherwise, turn off the analog event(s) for this axis
|
|
||||||
if(eventIsAnalog(joy->axisTable[axis][0][mode]))
|
|
||||||
joy->axisTable[axis][0][mode] = Event::NoType;
|
|
||||||
if(eventIsAnalog(joy->axisTable[axis][1][mode]))
|
|
||||||
joy->axisTable[axis][1][mode] = Event::NoType;
|
|
||||||
|
|
||||||
joy->axisTable[axis][(value > 0)][mode] = event;
|
return mapped;
|
||||||
}
|
#else
|
||||||
if(updateMenus)
|
|
||||||
setActionMappings(mode);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -1558,19 +1248,14 @@ bool EventHandler::addJoyButtonMapping(Event::Type event, EventMode mode,
|
||||||
bool updateMenus)
|
bool updateMenus)
|
||||||
{
|
{
|
||||||
#ifdef JOYSTICK_SUPPORT
|
#ifdef JOYSTICK_SUPPORT
|
||||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
bool mapped = myPJoyHandler->addBtnMapping(event, mode, stick, button);
|
||||||
if(joy)
|
if(mapped && updateMenus)
|
||||||
{
|
setActionMappings(mode);
|
||||||
if(button >= 0 && button < joy->numButtons && event < Event::LastType)
|
|
||||||
{
|
return mapped;
|
||||||
joy->btnTable[button][mode] = event;
|
#else
|
||||||
if(updateMenus)
|
|
||||||
setActionMappings(mode);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -1579,20 +1264,14 @@ bool EventHandler::addJoyHatMapping(Event::Type event, EventMode mode,
|
||||||
bool updateMenus)
|
bool updateMenus)
|
||||||
{
|
{
|
||||||
#ifdef JOYSTICK_SUPPORT
|
#ifdef JOYSTICK_SUPPORT
|
||||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
bool mapped = myPJoyHandler->addHatMapping(event, mode, stick, hat, value);
|
||||||
if(joy)
|
if(mapped && updateMenus)
|
||||||
{
|
setActionMappings(mode);
|
||||||
if(hat >= 0 && hat < joy->numHats && event < Event::LastType &&
|
|
||||||
value != JoyHat::CENTER)
|
return mapped;
|
||||||
{
|
#else
|
||||||
joy->hatTable[hat][int(value)][mode] = event;
|
|
||||||
if(updateMenus)
|
|
||||||
setActionMappings(mode);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -1605,7 +1284,7 @@ void EventHandler::eraseMapping(Event::Type event, EventMode mode)
|
||||||
|
|
||||||
#ifdef JOYSTICK_SUPPORT
|
#ifdef JOYSTICK_SUPPORT
|
||||||
// Erase the joystick mapping arrays
|
// Erase the joystick mapping arrays
|
||||||
myJoyHandler->eraseMapping(event, mode);
|
myPJoyHandler->eraseMapping(event, mode);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
setActionMappings(mode);
|
setActionMappings(mode);
|
||||||
|
@ -1731,8 +1410,10 @@ void EventHandler::setDefaultKeymap(Event::Type event, EventMode mode)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void EventHandler::setDefaultJoymap(Event::Type event, EventMode mode)
|
void EventHandler::setDefaultJoymap(Event::Type event, EventMode mode)
|
||||||
{
|
{
|
||||||
myJoyHandler->setDefaultMapping(event, mode);
|
#ifdef JOYSTICK_SUPPORT
|
||||||
|
myPJoyHandler->setDefaultMapping(event, mode);
|
||||||
setActionMappings(mode);
|
setActionMappings(mode);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -1752,7 +1433,9 @@ void EventHandler::saveKeyMapping()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void EventHandler::saveJoyMapping()
|
void EventHandler::saveJoyMapping()
|
||||||
{
|
{
|
||||||
myJoyHandler->saveMapping();
|
#ifdef JOYSTICK_SUPPORT
|
||||||
|
myPJoyHandler->saveMapping();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -1772,21 +1455,6 @@ void EventHandler::saveComboMapping()
|
||||||
myOSystem.settings().setValue("combomap", buf.str());
|
myOSystem.settings().setValue("combomap", buf.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
inline bool EventHandler::eventIsAnalog(Event::Type event) const
|
|
||||||
{
|
|
||||||
switch(event)
|
|
||||||
{
|
|
||||||
case Event::PaddleZeroAnalog:
|
|
||||||
case Event::PaddleOneAnalog:
|
|
||||||
case Event::PaddleTwoAnalog:
|
|
||||||
case Event::PaddleThreeAnalog:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
StringList EventHandler::getActionList(EventMode mode) const
|
StringList EventHandler::getActionList(EventMode mode) const
|
||||||
{
|
{
|
||||||
|
@ -2059,9 +1727,8 @@ void EventHandler::setMouseControllerMode(const string& enable)
|
||||||
usemouse = false;
|
usemouse = false;
|
||||||
else // 'analog'
|
else // 'analog'
|
||||||
{
|
{
|
||||||
if(controllerIsAnalog(Controller::Left) ||
|
usemouse = controllerIsAnalog(Controller::Left) ||
|
||||||
controllerIsAnalog(Controller::Right))
|
controllerIsAnalog(Controller::Right);
|
||||||
usemouse = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const string& control = usemouse ?
|
const string& control = usemouse ?
|
||||||
|
@ -2170,10 +1837,10 @@ void EventHandler::setEventState(EventHandlerState state)
|
||||||
|
|
||||||
// Only enable text input in GUI modes, since in emulation mode the
|
// Only enable text input in GUI modes, since in emulation mode the
|
||||||
// keyboard acts as one large joystick with many (single) buttons
|
// keyboard acts as one large joystick with many (single) buttons
|
||||||
|
myOverlay = nullptr;
|
||||||
switch(myState)
|
switch(myState)
|
||||||
{
|
{
|
||||||
case EventHandlerState::EMULATION:
|
case EventHandlerState::EMULATION:
|
||||||
myOverlay = nullptr;
|
|
||||||
myOSystem.sound().mute(false);
|
myOSystem.sound().mute(false);
|
||||||
enableTextEvents(false);
|
enableTextEvents(false);
|
||||||
if(myOSystem.console().leftController().type() == Controller::CompuMate)
|
if(myOSystem.console().leftController().type() == Controller::CompuMate)
|
||||||
|
@ -2181,7 +1848,6 @@ void EventHandler::setEventState(EventHandlerState state)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EventHandlerState::PAUSE:
|
case EventHandlerState::PAUSE:
|
||||||
myOverlay = nullptr;
|
|
||||||
myOSystem.sound().mute(true);
|
myOSystem.sound().mute(true);
|
||||||
enableTextEvents(false);
|
enableTextEvents(false);
|
||||||
break;
|
break;
|
||||||
|
@ -2216,7 +1882,6 @@ void EventHandler::setEventState(EventHandlerState state)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EventHandlerState::NONE:
|
case EventHandlerState::NONE:
|
||||||
myOverlay = nullptr;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2362,33 +2027,3 @@ EventHandler::ActionList EventHandler::ourMenuActionList[kMenuActionListSize] =
|
||||||
|
|
||||||
{ Event::UIPrevDir, "Parent directory", "", false }
|
{ Event::UIPrevDir, "Parent directory", "", false }
|
||||||
};
|
};
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
// Used by the Stelladaptor to send absolute axis values
|
|
||||||
const Event::Type EventHandler::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 EventHandler::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 EventHandler::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 }
|
|
||||||
};
|
|
||||||
|
|
|
@ -24,11 +24,13 @@ class Console;
|
||||||
class OSystem;
|
class OSystem;
|
||||||
class MouseControl;
|
class MouseControl;
|
||||||
class DialogContainer;
|
class DialogContainer;
|
||||||
|
class PhysicalJoystick;
|
||||||
|
|
||||||
#include "Event.hxx"
|
#include "Event.hxx"
|
||||||
#include "EventHandlerConstants.hxx"
|
#include "EventHandlerConstants.hxx"
|
||||||
#include "Control.hxx"
|
#include "Control.hxx"
|
||||||
#include "StellaKeys.hxx"
|
#include "StellaKeys.hxx"
|
||||||
|
#include "PJoystickHandler.hxx"
|
||||||
#include "Variant.hxx"
|
#include "Variant.hxx"
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
|
||||||
|
@ -163,19 +165,17 @@ class EventHandler
|
||||||
StringList getComboListForEvent(Event::Type event) const;
|
StringList getComboListForEvent(Event::Type event) const;
|
||||||
void setComboListForEvent(Event::Type event, const StringList& events);
|
void setComboListForEvent(Event::Type event, const StringList& events);
|
||||||
|
|
||||||
|
/** Convert keys and physical joystick events into Stella events. */
|
||||||
Event::Type eventForKey(StellaKey key, EventMode mode) const
|
Event::Type eventForKey(StellaKey key, EventMode mode) const
|
||||||
{ return myKeyTable[key][mode]; }
|
{ return myKeyTable[key][mode]; }
|
||||||
Event::Type eventForJoyAxis(int stick, int axis, int value, EventMode mode) const {
|
Event::Type eventForJoyAxis(int stick, int axis, int value, EventMode mode) const {
|
||||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
return myPJoyHandler->eventForAxis(stick, axis, value, mode);
|
||||||
return joy ? joy->axisTable[axis][(value > 0)][mode] : Event::NoType;
|
|
||||||
}
|
}
|
||||||
Event::Type eventForJoyButton(int stick, int button, EventMode mode) const {
|
Event::Type eventForJoyButton(int stick, int button, EventMode mode) const {
|
||||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
return myPJoyHandler->eventForButton(stick, button, mode);
|
||||||
return joy ? joy->btnTable[button][mode] : Event::NoType;
|
|
||||||
}
|
}
|
||||||
Event::Type eventForJoyHat(int stick, int hat, JoyHat value, EventMode mode) const {
|
Event::Type eventForJoyHat(int stick, int hat, JoyHat value, EventMode mode) const {
|
||||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
return myPJoyHandler->eventForHat(stick, hat, value, mode);
|
||||||
return joy ? joy->hatTable[hat][int(value)][mode] : Event::NoType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::Type eventAtIndex(int idx, EventMode mode) const;
|
Event::Type eventAtIndex(int idx, EventMode mode) const;
|
||||||
|
@ -192,7 +192,7 @@ class EventHandler
|
||||||
bool addKeyMapping(Event::Type event, EventMode mode, StellaKey key);
|
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).
|
the mapping array(s).
|
||||||
|
|
||||||
@param event The event we are remapping
|
@param event The event we are remapping
|
||||||
|
@ -209,7 +209,7 @@ class EventHandler
|
||||||
bool updateMenus = true);
|
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).
|
mapping array(s).
|
||||||
|
|
||||||
@param event The event we are remapping
|
@param event The event we are remapping
|
||||||
|
@ -224,7 +224,7 @@ class EventHandler
|
||||||
bool updateMenus = true);
|
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).
|
the mapping array(s).
|
||||||
|
|
||||||
@param event The event we are remapping
|
@param event The event we are remapping
|
||||||
|
@ -278,16 +278,35 @@ class EventHandler
|
||||||
bool controllerIsAnalog(Controller::Jack jack) const;
|
bool controllerIsAnalog(Controller::Jack jack) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Return a list of all joysticks currently in the internal database
|
Detects and changes the eventhandler state.
|
||||||
(first part of variant) and its internal ID (second part of variant).
|
|
||||||
|
@param type The event
|
||||||
|
@return True if the state changed, else false
|
||||||
*/
|
*/
|
||||||
VariantList joystickDatabase() const;
|
bool eventStateChange(Event::Type type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Remove the joystick identified by 'name' from the joystick database,
|
Get the current overlay in use. The overlay won't always exist,
|
||||||
only if it is not currently active.
|
so we should test if it's available.
|
||||||
|
|
||||||
|
@return The overlay object
|
||||||
*/
|
*/
|
||||||
void removeJoystickFromDatabase(const string& name);
|
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 physicalJoystickDatabase() const {
|
||||||
|
return myPJoyHandler->database();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Remove the physical joystick identified by 'name' from the joystick
|
||||||
|
database, only if it is not currently active.
|
||||||
|
*/
|
||||||
|
void removePhysicalJoystickFromDatabase(const string& name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Enable/disable text events (distinct from single-key events).
|
Enable/disable text events (distinct from single-key events).
|
||||||
|
@ -306,9 +325,15 @@ class EventHandler
|
||||||
void handleKeyEvent(StellaKey key, StellaMod mod, bool state);
|
void handleKeyEvent(StellaKey key, StellaMod mod, bool state);
|
||||||
void handleMouseMotionEvent(int x, int y, int xrel, int yrel);
|
void handleMouseMotionEvent(int x, int y, int xrel, int yrel);
|
||||||
void handleMouseButtonEvent(MouseButton b, bool pressed, int x, int y);
|
void handleMouseButtonEvent(MouseButton b, bool pressed, int x, int y);
|
||||||
void handleJoyEvent(int stick, int button, uInt8 state);
|
void handleJoyBtnEvent(int stick, int button, uInt8 state) {
|
||||||
void handleJoyAxisEvent(int stick, int axis, int value);
|
myPJoyHandler->handleBtnEvent(stick, button, state);
|
||||||
void handleJoyHatEvent(int stick, int hat, int value);
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns the human-readable name for a StellaKey.
|
Returns the human-readable name for a StellaKey.
|
||||||
|
@ -338,120 +363,15 @@ class EventHandler
|
||||||
};
|
};
|
||||||
void handleSystemEvent(SystemEvent e, int data1 = 0, int data2 = 0);
|
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
|
Add the given joystick to the list of physical joysticks available to the handler.
|
||||||
// which is dynamically allocated based on the actual number of buttons,
|
*/
|
||||||
// axes, etc that the device contains.
|
void addPhysicalJoystick(PhysicalJoystick* stick);
|
||||||
// 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 sticks available to the handler.
|
Remove physical joystick at the current index.
|
||||||
*/
|
*/
|
||||||
void addJoystick(StellaJoystick* stick);
|
void removePhysicalJoystick(int index);
|
||||||
|
|
||||||
/**
|
|
||||||
Remove joystick at the current index.
|
|
||||||
*/
|
|
||||||
void removeJoystick(int index);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum {
|
enum {
|
||||||
|
@ -461,14 +381,6 @@ class EventHandler
|
||||||
kMenuActionListSize = 14
|
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.
|
The following methods take care of assigning action mappings.
|
||||||
*/
|
*/
|
||||||
|
@ -480,14 +392,6 @@ class EventHandler
|
||||||
void saveJoyMapping();
|
void saveJoyMapping();
|
||||||
void saveComboMapping();
|
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);
|
void setEventState(EventHandlerState state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -509,6 +413,9 @@ class EventHandler
|
||||||
// all possible controller modes
|
// all possible controller modes
|
||||||
unique_ptr<MouseControl> myMouseControl;
|
unique_ptr<MouseControl> myMouseControl;
|
||||||
|
|
||||||
|
// Handler for all joystick addition/removal/mapping
|
||||||
|
unique_ptr<PhysicalJoystickHandler> myPJoyHandler;
|
||||||
|
|
||||||
// Array of key events, indexed by StellaKey
|
// Array of key events, indexed by StellaKey
|
||||||
Event::Type myKeyTable[KBDK_LAST][kNumModes];
|
Event::Type myKeyTable[KBDK_LAST][kNumModes];
|
||||||
|
|
||||||
|
@ -518,7 +425,7 @@ class EventHandler
|
||||||
// Indicates the current state of the system (ie, which mode is current)
|
// Indicates the current state of the system (ie, which mode is current)
|
||||||
EventHandlerState myState;
|
EventHandlerState myState;
|
||||||
|
|
||||||
// Indicates whether the joystick emulates 'impossible' directions
|
// Indicates whether the virtual joystick emulates 'impossible' directions
|
||||||
bool myAllowAllDirectionsFlag;
|
bool myAllowAllDirectionsFlag;
|
||||||
|
|
||||||
// Indicates whether or not we're in frying mode
|
// Indicates whether or not we're in frying mode
|
||||||
|
@ -559,14 +466,6 @@ class EventHandler
|
||||||
static ActionList ourEmulActionList[kEmulActionListSize];
|
static ActionList ourEmulActionList[kEmulActionListSize];
|
||||||
static ActionList ourMenuActionList[kMenuActionListSize];
|
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
|
// Following constructors and assignment operators not supported
|
||||||
EventHandler() = delete;
|
EventHandler() = delete;
|
||||||
EventHandler(const 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());
|
|
||||||
}
|
|
|
@ -53,7 +53,6 @@ MODULE_OBJS := \
|
||||||
src/emucore/Control.o \
|
src/emucore/Control.o \
|
||||||
src/emucore/Driving.o \
|
src/emucore/Driving.o \
|
||||||
src/emucore/EventHandler.o \
|
src/emucore/EventHandler.o \
|
||||||
src/emucore/EventJoyHandler.o \
|
|
||||||
src/emucore/FrameBuffer.o \
|
src/emucore/FrameBuffer.o \
|
||||||
src/emucore/FBSurface.o \
|
src/emucore/FBSurface.o \
|
||||||
src/emucore/FSNode.o \
|
src/emucore/FSNode.o \
|
||||||
|
|
|
@ -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())
|
if(myDialogStack.empty())
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -99,7 +99,7 @@ class DialogContainer
|
||||||
@param button The joystick button
|
@param button The joystick button
|
||||||
@param state The state (pressed or released)
|
@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.
|
Handle a joystick axis event.
|
||||||
|
|
|
@ -75,7 +75,7 @@ void JoystickDialog::loadConfig()
|
||||||
myJoyIDs.clear();
|
myJoyIDs.clear();
|
||||||
|
|
||||||
StringList sticks;
|
StringList sticks;
|
||||||
for(const auto& i: instance().eventHandler().joystickDatabase())
|
for(const auto& i: instance().eventHandler().physicalJoystickDatabase())
|
||||||
{
|
{
|
||||||
sticks.push_back(i.first);
|
sticks.push_back(i.first);
|
||||||
myJoyIDs.push_back(i.second.toInt());
|
myJoyIDs.push_back(i.second.toInt());
|
||||||
|
@ -99,7 +99,8 @@ void JoystickDialog::handleCommand(CommandSender* sender, int cmd, int data, int
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kRemoveCmd:
|
case kRemoveCmd:
|
||||||
instance().eventHandler().removeJoystickFromDatabase(myJoyList->getSelectedString());
|
instance().eventHandler().removePhysicalJoystickFromDatabase(
|
||||||
|
myJoyList->getSelectedString());
|
||||||
loadConfig();
|
loadConfig();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue