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_JOYBUTTONDOWN:
|
||||
{
|
||||
handleJoyEvent(myEvent.jbutton.which, myEvent.jbutton.button,
|
||||
myEvent.jbutton.state == SDL_PRESSED ? 1 : 0);
|
||||
handleJoyBtnEvent(myEvent.jbutton.which, myEvent.jbutton.button,
|
||||
myEvent.jbutton.state == SDL_PRESSED ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -127,12 +127,12 @@ void EventHandlerSDL2::pollEvent()
|
|||
|
||||
case SDL_JOYDEVICEADDED:
|
||||
{
|
||||
addJoystick(new JoystickSDL2(myEvent.jdevice.which));
|
||||
addPhysicalJoystick(new JoystickSDL2(myEvent.jdevice.which));
|
||||
break; // SDL_JOYDEVICEADDED
|
||||
}
|
||||
case SDL_JOYDEVICEREMOVED:
|
||||
{
|
||||
removeJoystick(myEvent.jdevice.which);
|
||||
removePhysicalJoystick(myEvent.jdevice.which);
|
||||
break; // SDL_JOYDEVICEREMOVED
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "SDL_lib.hxx"
|
||||
#include "EventHandler.hxx"
|
||||
#include "PhysicalJoystick.hxx"
|
||||
|
||||
/**
|
||||
This class handles event collection from the point of view of the specific
|
||||
|
@ -58,9 +59,9 @@ class EventHandlerSDL2 : public EventHandler
|
|||
private:
|
||||
SDL_Event myEvent;
|
||||
|
||||
// A thin wrapper around a basic StellaJoystick, holding the pointer to
|
||||
// the underlying SDL stick.
|
||||
class JoystickSDL2 : public StellaJoystick
|
||||
// A thin wrapper around a basic PhysicalJoystick, holding the pointer to
|
||||
// the underlying SDL joystick device.
|
||||
class JoystickSDL2 : public PhysicalJoystick
|
||||
{
|
||||
public:
|
||||
JoystickSDL2(int idx);
|
||||
|
|
|
@ -0,0 +1,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_OBJS := \
|
||||
src/common/main.o \
|
||||
src/common/Base.o \
|
||||
src/common/EventHandlerSDL2.o \
|
||||
src/common/FrameBufferSDL2.o \
|
||||
src/common/FBSurfaceSDL2.o \
|
||||
src/common/SoundSDL2.o \
|
||||
src/common/FrameBufferSDL2.o \
|
||||
src/common/FSNodeZIP.o \
|
||||
src/common/PNGLibrary.o \
|
||||
src/common/main.o \
|
||||
src/common/MouseControl.o \
|
||||
src/common/PhysicalJoystick.o \
|
||||
src/common/PJoystickHandler.o \
|
||||
src/common/PNGLibrary.o \
|
||||
src/common/RewindManager.o \
|
||||
src/common/SoundSDL2.o \
|
||||
src/common/StateManager.o \
|
||||
src/common/ZipHandler.o
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "StellaKeys.hxx"
|
||||
|
||||
/**
|
||||
@author Bradford W. Mott
|
||||
@author Bradford W. Mott, Stephen Anthony
|
||||
*/
|
||||
class Event
|
||||
{
|
||||
|
@ -82,23 +82,23 @@ class Event
|
|||
|
||||
public:
|
||||
/**
|
||||
Create a new event object
|
||||
Create a new event object.
|
||||
*/
|
||||
Event() { clear(); }
|
||||
|
||||
public:
|
||||
/**
|
||||
Get the value associated with the event of the specified type
|
||||
Get the value associated with the event of the specified type.
|
||||
*/
|
||||
Int32 get(Type type) const { return myValues[type]; }
|
||||
|
||||
/**
|
||||
Set the value associated with the event of the specified type
|
||||
Set the value associated with the event of the specified type.
|
||||
*/
|
||||
void set(Type type, Int32 value) { myValues[type] = value; }
|
||||
|
||||
/**
|
||||
Clears the event array (resets to initial state)
|
||||
Clears the event array (resets to initial state).
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
|
@ -110,15 +110,32 @@ class Event
|
|||
}
|
||||
|
||||
/**
|
||||
Get the keytable associated with this event
|
||||
Get the keytable associated with this event.
|
||||
*/
|
||||
const bool* getKeys() const { return myKeyTable; }
|
||||
|
||||
/**
|
||||
Set the value associated with the event of the specified type
|
||||
Set the value associated with the event of the specified type.
|
||||
*/
|
||||
void setKey(StellaKey key, bool state) { myKeyTable[key] = state; }
|
||||
|
||||
/**
|
||||
Tests if a given event represents continuous or analog values.
|
||||
*/
|
||||
static bool isAnalog(Type type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case Event::PaddleZeroAnalog:
|
||||
case Event::PaddleOneAnalog:
|
||||
case Event::PaddleTwoAnalog:
|
||||
case Event::PaddleThreeAnalog:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Array of values associated with each event type
|
||||
Int32 myValues[LastType];
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "OSystem.hxx"
|
||||
#include "Joystick.hxx"
|
||||
#include "Paddles.hxx"
|
||||
#include "PJoystickHandler.hxx"
|
||||
#include "PointingDevice.hxx"
|
||||
#include "PropsSet.hxx"
|
||||
#include "ListWidget.hxx"
|
||||
|
@ -81,8 +82,8 @@ EventHandler::EventHandler(OSystem& osystem)
|
|||
for(int j = 0; j < kEventsPerCombo; ++j)
|
||||
myComboTable[i][j] = Event::NoType;
|
||||
|
||||
// Create joystick handler (to handle all joystick functionality)
|
||||
myJoyHandler = make_unique<JoystickHandler>(osystem);
|
||||
// Create joystick handler (to handle all physical joystick functionality)
|
||||
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
|
||||
if(!myJoyHandler->add(stick))
|
||||
int ID = myPJoyHandler->add(joy);
|
||||
if(ID < 0)
|
||||
return;
|
||||
|
||||
setActionMappings(kEmulationMode);
|
||||
setActionMappings(kMenuMode);
|
||||
|
||||
ostringstream buf;
|
||||
buf << "Added joystick " << stick->ID << ":" << endl
|
||||
<< " " << stick->about() << endl;
|
||||
buf << "Added joystick " << ID << ":" << endl
|
||||
<< " " << joy->about() << endl;
|
||||
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
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::removeJoystick(int id)
|
||||
void EventHandler::removePhysicalJoystick(int id)
|
||||
{
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
myJoyHandler->remove(id);
|
||||
myPJoyHandler->remove(id);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -175,7 +164,7 @@ void EventHandler::removeJoystick(int id)
|
|||
void EventHandler::mapStelladaptors(const string& saport)
|
||||
{
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
myJoyHandler->mapStelladaptors(saport);
|
||||
myPJoyHandler->mapStelladaptors(saport);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -692,211 +681,6 @@ void EventHandler::handleMouseButtonEvent(MouseButton b, bool pressed,
|
|||
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)
|
||||
{
|
||||
|
@ -1289,8 +1073,6 @@ void EventHandler::setActionMappings(EventMode mode)
|
|||
return;
|
||||
}
|
||||
|
||||
ostringstream buf;
|
||||
|
||||
// Fill the ActionList with the current key and joystick mappings
|
||||
for(int i = 0; i < listsize; ++i)
|
||||
{
|
||||
|
@ -1309,77 +1091,12 @@ void EventHandler::setActionMappings(EventMode mode)
|
|||
}
|
||||
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
for(const auto& st: myJoyHandler->sticks())
|
||||
string joydesc = myPJoyHandler->getMappingDesc(event, mode);
|
||||
if(joydesc != "")
|
||||
{
|
||||
uInt32 stick = st.first;
|
||||
const StellaJoystick* joy = st.second;
|
||||
if(!joy) continue;
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(key != "")
|
||||
key += ", ";
|
||||
key += joydesc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1487,26 +1204,18 @@ void EventHandler::setComboMap()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
VariantList EventHandler::joystickDatabase() const
|
||||
void EventHandler::removePhysicalJoystickFromDatabase(const string& name)
|
||||
{
|
||||
VariantList db;
|
||||
for(const auto& i: myJoyHandler->database())
|
||||
VarList::push_back(db, i.first, i.second.joy ? i.second.joy->ID : -1);
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::removeJoystickFromDatabase(const string& name)
|
||||
{
|
||||
myJoyHandler->remove(name);
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
myPJoyHandler->remove(name);
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool EventHandler::addKeyMapping(Event::Type event, EventMode mode, StellaKey key)
|
||||
{
|
||||
// These keys cannot be remapped
|
||||
if(key == KBDK_TAB || eventIsAnalog(event))
|
||||
if(key == KBDK_TAB || Event::isAnalog(event))
|
||||
return false;
|
||||
else
|
||||
{
|
||||
|
@ -1523,33 +1232,14 @@ bool EventHandler::addJoyAxisMapping(Event::Type event, EventMode mode,
|
|||
bool updateMenus)
|
||||
{
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
||||
if(joy)
|
||||
{
|
||||
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;
|
||||
bool mapped = myPJoyHandler->addAxisMapping(event, mode, stick, axis, value);
|
||||
if(mapped && updateMenus)
|
||||
setActionMappings(mode);
|
||||
|
||||
joy->axisTable[axis][(value > 0)][mode] = event;
|
||||
}
|
||||
if(updateMenus)
|
||||
setActionMappings(mode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return mapped;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1558,19 +1248,14 @@ bool EventHandler::addJoyButtonMapping(Event::Type event, EventMode mode,
|
|||
bool updateMenus)
|
||||
{
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
||||
if(joy)
|
||||
{
|
||||
if(button >= 0 && button < joy->numButtons && event < Event::LastType)
|
||||
{
|
||||
joy->btnTable[button][mode] = event;
|
||||
if(updateMenus)
|
||||
setActionMappings(mode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
bool mapped = myPJoyHandler->addBtnMapping(event, mode, stick, button);
|
||||
if(mapped && updateMenus)
|
||||
setActionMappings(mode);
|
||||
|
||||
return mapped;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1579,20 +1264,14 @@ bool EventHandler::addJoyHatMapping(Event::Type event, EventMode mode,
|
|||
bool updateMenus)
|
||||
{
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
||||
if(joy)
|
||||
{
|
||||
if(hat >= 0 && hat < joy->numHats && event < Event::LastType &&
|
||||
value != JoyHat::CENTER)
|
||||
{
|
||||
joy->hatTable[hat][int(value)][mode] = event;
|
||||
if(updateMenus)
|
||||
setActionMappings(mode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
bool mapped = myPJoyHandler->addHatMapping(event, mode, stick, hat, value);
|
||||
if(mapped && updateMenus)
|
||||
setActionMappings(mode);
|
||||
|
||||
return mapped;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1605,7 +1284,7 @@ void EventHandler::eraseMapping(Event::Type event, EventMode mode)
|
|||
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
// Erase the joystick mapping arrays
|
||||
myJoyHandler->eraseMapping(event, mode);
|
||||
myPJoyHandler->eraseMapping(event, mode);
|
||||
#endif
|
||||
|
||||
setActionMappings(mode);
|
||||
|
@ -1731,8 +1410,10 @@ void EventHandler::setDefaultKeymap(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);
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1752,7 +1433,9 @@ void EventHandler::saveKeyMapping()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::saveJoyMapping()
|
||||
{
|
||||
myJoyHandler->saveMapping();
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
myPJoyHandler->saveMapping();
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1772,21 +1455,6 @@ void EventHandler::saveComboMapping()
|
|||
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
|
||||
{
|
||||
|
@ -2059,9 +1727,8 @@ void EventHandler::setMouseControllerMode(const string& enable)
|
|||
usemouse = false;
|
||||
else // 'analog'
|
||||
{
|
||||
if(controllerIsAnalog(Controller::Left) ||
|
||||
controllerIsAnalog(Controller::Right))
|
||||
usemouse = true;
|
||||
usemouse = controllerIsAnalog(Controller::Left) ||
|
||||
controllerIsAnalog(Controller::Right);
|
||||
}
|
||||
|
||||
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
|
||||
// keyboard acts as one large joystick with many (single) buttons
|
||||
myOverlay = nullptr;
|
||||
switch(myState)
|
||||
{
|
||||
case EventHandlerState::EMULATION:
|
||||
myOverlay = nullptr;
|
||||
myOSystem.sound().mute(false);
|
||||
enableTextEvents(false);
|
||||
if(myOSystem.console().leftController().type() == Controller::CompuMate)
|
||||
|
@ -2181,7 +1848,6 @@ void EventHandler::setEventState(EventHandlerState state)
|
|||
break;
|
||||
|
||||
case EventHandlerState::PAUSE:
|
||||
myOverlay = nullptr;
|
||||
myOSystem.sound().mute(true);
|
||||
enableTextEvents(false);
|
||||
break;
|
||||
|
@ -2216,7 +1882,6 @@ void EventHandler::setEventState(EventHandlerState state)
|
|||
break;
|
||||
|
||||
case EventHandlerState::NONE:
|
||||
myOverlay = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2362,33 +2027,3 @@ EventHandler::ActionList EventHandler::ourMenuActionList[kMenuActionListSize] =
|
|||
|
||||
{ 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 MouseControl;
|
||||
class DialogContainer;
|
||||
class PhysicalJoystick;
|
||||
|
||||
#include "Event.hxx"
|
||||
#include "EventHandlerConstants.hxx"
|
||||
#include "Control.hxx"
|
||||
#include "StellaKeys.hxx"
|
||||
#include "PJoystickHandler.hxx"
|
||||
#include "Variant.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
|
@ -163,19 +165,17 @@ class EventHandler
|
|||
StringList getComboListForEvent(Event::Type event) const;
|
||||
void setComboListForEvent(Event::Type event, const StringList& events);
|
||||
|
||||
/** Convert keys and physical joystick events into Stella events. */
|
||||
Event::Type eventForKey(StellaKey key, EventMode mode) const
|
||||
{ return myKeyTable[key][mode]; }
|
||||
Event::Type eventForJoyAxis(int stick, int axis, int value, EventMode mode) const {
|
||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
||||
return joy ? joy->axisTable[axis][(value > 0)][mode] : Event::NoType;
|
||||
return myPJoyHandler->eventForAxis(stick, axis, value, mode);
|
||||
}
|
||||
Event::Type eventForJoyButton(int stick, int button, EventMode mode) const {
|
||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
||||
return joy ? joy->btnTable[button][mode] : Event::NoType;
|
||||
return myPJoyHandler->eventForButton(stick, button, mode);
|
||||
}
|
||||
Event::Type eventForJoyHat(int stick, int hat, JoyHat value, EventMode mode) const {
|
||||
const StellaJoystick* joy = myJoyHandler->joy(stick);
|
||||
return joy ? joy->hatTable[hat][int(value)][mode] : Event::NoType;
|
||||
return myPJoyHandler->eventForHat(stick, hat, value, mode);
|
||||
}
|
||||
|
||||
Event::Type eventAtIndex(int idx, EventMode mode) const;
|
||||
|
@ -192,7 +192,7 @@ class EventHandler
|
|||
bool addKeyMapping(Event::Type event, EventMode mode, StellaKey key);
|
||||
|
||||
/**
|
||||
Bind a joystick axis direction to an event/action and regenerate
|
||||
Bind a physical joystick axis direction to an event/action and regenerate
|
||||
the mapping array(s).
|
||||
|
||||
@param event The event we are remapping
|
||||
|
@ -209,7 +209,7 @@ class EventHandler
|
|||
bool updateMenus = true);
|
||||
|
||||
/**
|
||||
Bind a joystick button to an event/action and regenerate the
|
||||
Bind a physical joystick button to an event/action and regenerate the
|
||||
mapping array(s).
|
||||
|
||||
@param event The event we are remapping
|
||||
|
@ -224,7 +224,7 @@ class EventHandler
|
|||
bool updateMenus = true);
|
||||
|
||||
/**
|
||||
Bind a joystick hat direction to an event/action and regenerate
|
||||
Bind a physical joystick hat direction to an event/action and regenerate
|
||||
the mapping array(s).
|
||||
|
||||
@param event The event we are remapping
|
||||
|
@ -278,16 +278,35 @@ class EventHandler
|
|||
bool controllerIsAnalog(Controller::Jack jack) const;
|
||||
|
||||
/**
|
||||
Return a list of all joysticks currently in the internal database
|
||||
(first part of variant) and its internal ID (second part of variant).
|
||||
Detects and changes the eventhandler state.
|
||||
|
||||
@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,
|
||||
only if it is not currently active.
|
||||
Get the current overlay in use. The overlay won't always exist,
|
||||
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).
|
||||
|
@ -306,9 +325,15 @@ class EventHandler
|
|||
void handleKeyEvent(StellaKey key, StellaMod mod, bool state);
|
||||
void handleMouseMotionEvent(int x, int y, int xrel, int yrel);
|
||||
void handleMouseButtonEvent(MouseButton b, bool pressed, int x, int y);
|
||||
void handleJoyEvent(int stick, int button, uInt8 state);
|
||||
void handleJoyAxisEvent(int stick, int axis, int value);
|
||||
void handleJoyHatEvent(int stick, int hat, int value);
|
||||
void handleJoyBtnEvent(int stick, int button, uInt8 state) {
|
||||
myPJoyHandler->handleBtnEvent(stick, button, state);
|
||||
}
|
||||
void handleJoyAxisEvent(int stick, int axis, int value) {
|
||||
myPJoyHandler->handleAxisEvent(stick, axis, value);
|
||||
}
|
||||
void handleJoyHatEvent(int stick, int hat, int value) {
|
||||
myPJoyHandler->handleHatEvent(stick, hat, value);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the human-readable name for a StellaKey.
|
||||
|
@ -338,120 +363,15 @@ class EventHandler
|
|||
};
|
||||
void handleSystemEvent(SystemEvent e, int data1 = 0, int data2 = 0);
|
||||
|
||||
// An abstraction of a joystick in Stella.
|
||||
// A StellaJoystick holds its own event mapping information, space for
|
||||
// which is dynamically allocated based on the actual number of buttons,
|
||||
// axes, etc that the device contains.
|
||||
// Specific backend class(es) will inherit from this class, and implement
|
||||
// functionality specific to the device.
|
||||
class StellaJoystick
|
||||
{
|
||||
friend class EventHandler;
|
||||
|
||||
public:
|
||||
StellaJoystick();
|
||||
virtual ~StellaJoystick();
|
||||
|
||||
string getMap() const;
|
||||
bool setMap(const string& map);
|
||||
void eraseMap(EventMode mode);
|
||||
void eraseEvent(Event::Type event, EventMode mode);
|
||||
string about() const;
|
||||
|
||||
protected:
|
||||
void initialize(int index, const string& desc,
|
||||
int axes, int buttons, int hats, int balls);
|
||||
|
||||
private:
|
||||
enum JoyType {
|
||||
JT_NONE = 0,
|
||||
JT_REGULAR = 1,
|
||||
JT_STELLADAPTOR_LEFT = 2,
|
||||
JT_STELLADAPTOR_RIGHT = 3,
|
||||
JT_2600DAPTOR_LEFT = 4,
|
||||
JT_2600DAPTOR_RIGHT = 5
|
||||
};
|
||||
|
||||
JoyType type;
|
||||
int ID;
|
||||
string name;
|
||||
int numAxes, numButtons, numHats;
|
||||
Event::Type (*axisTable)[2][kNumModes];
|
||||
Event::Type (*btnTable)[kNumModes];
|
||||
Event::Type (*hatTable)[4][kNumModes];
|
||||
int* axisLastValue;
|
||||
|
||||
private:
|
||||
void getValues(const string& list, IntArray& map) const;
|
||||
|
||||
friend ostream& operator<<(ostream& os, const StellaJoystick& s) {
|
||||
os << " ID: " << s.ID << ", name: " << s.name << ", numaxis: " << s.numAxes
|
||||
<< ", numbtns: " << s.numButtons << ", numhats: " << s.numHats;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
class JoystickHandler
|
||||
{
|
||||
private:
|
||||
struct StickInfo
|
||||
{
|
||||
StickInfo(const string& map = EmptyString, StellaJoystick* stick = nullptr)
|
||||
: mapping(map), joy(stick) {}
|
||||
|
||||
string mapping;
|
||||
StellaJoystick* joy;
|
||||
|
||||
friend ostream& operator<<(ostream& os, const StickInfo& si) {
|
||||
os << " joy: " << si.joy << endl << " map: " << si.mapping;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
using StickDatabase = std::map<string,StickInfo>;
|
||||
using StickList = std::map<int, StellaJoystick*>;
|
||||
|
||||
JoystickHandler(OSystem& system);
|
||||
~JoystickHandler();
|
||||
|
||||
bool add(StellaJoystick* stick);
|
||||
bool remove(int id);
|
||||
bool remove(const string& name);
|
||||
void mapStelladaptors(const string& saport);
|
||||
void setDefaultMapping(Event::Type type, EventMode mode);
|
||||
void eraseMapping(Event::Type event, EventMode mode);
|
||||
void saveMapping();
|
||||
|
||||
const StellaJoystick* joy(int id) const {
|
||||
const auto& i = mySticks.find(id);
|
||||
return i != mySticks.cend() ? i->second : nullptr;
|
||||
}
|
||||
const StickDatabase& database() const { return myDatabase; }
|
||||
const StickList& sticks() const { return mySticks; }
|
||||
|
||||
private:
|
||||
OSystem& myOSystem;
|
||||
|
||||
// Contains all joysticks that Stella knows about, indexed by name
|
||||
StickDatabase myDatabase;
|
||||
|
||||
// Contains only joysticks that are currently available, indexed by id
|
||||
StickList mySticks;
|
||||
|
||||
void setStickDefaultMapping(int stick, Event::Type type, EventMode mode);
|
||||
void printDatabase() const;
|
||||
};
|
||||
/**
|
||||
Add the given joystick to the list of physical joysticks available to the handler.
|
||||
*/
|
||||
void addPhysicalJoystick(PhysicalJoystick* stick);
|
||||
|
||||
/**
|
||||
Add the given joystick to the list of sticks available to the handler.
|
||||
Remove physical joystick at the current index.
|
||||
*/
|
||||
void addJoystick(StellaJoystick* stick);
|
||||
|
||||
/**
|
||||
Remove joystick at the current index.
|
||||
*/
|
||||
void removeJoystick(int index);
|
||||
void removePhysicalJoystick(int index);
|
||||
|
||||
private:
|
||||
enum {
|
||||
|
@ -461,14 +381,6 @@ class EventHandler
|
|||
kMenuActionListSize = 14
|
||||
};
|
||||
|
||||
/**
|
||||
Detects and changes the eventhandler state
|
||||
|
||||
@param type The event
|
||||
@return True if the state changed, else false
|
||||
*/
|
||||
bool eventStateChange(Event::Type type);
|
||||
|
||||
/**
|
||||
The following methods take care of assigning action mappings.
|
||||
*/
|
||||
|
@ -480,14 +392,6 @@ class EventHandler
|
|||
void saveJoyMapping();
|
||||
void saveComboMapping();
|
||||
|
||||
/**
|
||||
Tests if a given event should use continuous/analog values.
|
||||
|
||||
@param event The event to test for analog processing
|
||||
@return True if analog, else false
|
||||
*/
|
||||
bool eventIsAnalog(Event::Type event) const;
|
||||
|
||||
void setEventState(EventHandlerState state);
|
||||
|
||||
private:
|
||||
|
@ -509,6 +413,9 @@ class EventHandler
|
|||
// all possible controller modes
|
||||
unique_ptr<MouseControl> myMouseControl;
|
||||
|
||||
// Handler for all joystick addition/removal/mapping
|
||||
unique_ptr<PhysicalJoystickHandler> myPJoyHandler;
|
||||
|
||||
// Array of key events, indexed by StellaKey
|
||||
Event::Type myKeyTable[KBDK_LAST][kNumModes];
|
||||
|
||||
|
@ -518,7 +425,7 @@ class EventHandler
|
|||
// Indicates the current state of the system (ie, which mode is current)
|
||||
EventHandlerState myState;
|
||||
|
||||
// Indicates whether the joystick emulates 'impossible' directions
|
||||
// Indicates whether the virtual joystick emulates 'impossible' directions
|
||||
bool myAllowAllDirectionsFlag;
|
||||
|
||||
// Indicates whether or not we're in frying mode
|
||||
|
@ -559,14 +466,6 @@ class EventHandler
|
|||
static ActionList ourEmulActionList[kEmulActionListSize];
|
||||
static ActionList ourMenuActionList[kMenuActionListSize];
|
||||
|
||||
// Static lookup tables for Stelladaptor/2600-daptor axis/button support
|
||||
static const Event::Type SA_Axis[2][2];
|
||||
static const Event::Type SA_Button[2][4];
|
||||
static const Event::Type SA_Key[2][12];
|
||||
|
||||
// Handler for all joystick addition/removal/mapping
|
||||
unique_ptr<JoystickHandler> myJoyHandler;
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
EventHandler() = delete;
|
||||
EventHandler(const EventHandler&) = delete;
|
||||
|
|
|
@ -1,576 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "OSystem.hxx"
|
||||
#include "Settings.hxx"
|
||||
#include "Vec.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
#include "EventHandler.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventHandler::StellaJoystick::StellaJoystick()
|
||||
: type(JT_NONE),
|
||||
ID(-1),
|
||||
name("None"),
|
||||
numAxes(0),
|
||||
numButtons(0),
|
||||
numHats(0),
|
||||
axisTable(nullptr),
|
||||
btnTable(nullptr),
|
||||
hatTable(nullptr),
|
||||
axisLastValue(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventHandler::StellaJoystick::~StellaJoystick()
|
||||
{
|
||||
delete[] axisTable;
|
||||
delete[] btnTable;
|
||||
delete[] hatTable;
|
||||
delete[] axisLastValue;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::StellaJoystick::initialize(int index, const string& desc,
|
||||
int axes, int buttons, int hats, int /*balls*/)
|
||||
{
|
||||
ID = index;
|
||||
name = desc;
|
||||
|
||||
// Dynamically create the various mapping arrays for this joystick,
|
||||
// based on its specific attributes
|
||||
numAxes = axes;
|
||||
numButtons = buttons;
|
||||
numHats = hats;
|
||||
if(numAxes)
|
||||
axisTable = new Event::Type[numAxes][2][kNumModes];
|
||||
if(numButtons)
|
||||
btnTable = new Event::Type[numButtons][kNumModes];
|
||||
if(numHats)
|
||||
hatTable = new Event::Type[numHats][4][kNumModes];
|
||||
axisLastValue = new int[numAxes];
|
||||
|
||||
// Erase the joystick axis mapping array and last axis value
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
{
|
||||
axisLastValue[a] = 0;
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
axisTable[a][0][m] = axisTable[a][1][m] = Event::NoType;
|
||||
}
|
||||
|
||||
// Erase the joystick button mapping array
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
btnTable[b][m] = Event::NoType;
|
||||
|
||||
// Erase the joystick hat mapping array
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
hatTable[h][0][m] = hatTable[h][1][m] =
|
||||
hatTable[h][2][m] = hatTable[h][3][m] = Event::NoType;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string EventHandler::StellaJoystick::getMap() const
|
||||
{
|
||||
// The mapping structure (for remappable devices) is defined as follows:
|
||||
// NAME | AXIS # + values | BUTTON # + values | HAT # + values,
|
||||
// where each subsection of values is separated by ':'
|
||||
if(type == JT_REGULAR)
|
||||
{
|
||||
ostringstream joybuf;
|
||||
joybuf << name << "|" << numAxes;
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
for(int k = 0; k < 2; ++k)
|
||||
joybuf << " " << axisTable[a][k][m];
|
||||
joybuf << "|" << numButtons;
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
joybuf << " " << btnTable[b][m];
|
||||
joybuf << "|" << numHats;
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
for(int k = 0; k < 4; ++k)
|
||||
joybuf << " " << hatTable[h][k][m];
|
||||
|
||||
return joybuf.str();
|
||||
}
|
||||
return EmptyString;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool EventHandler::StellaJoystick::setMap(const string& mapString)
|
||||
{
|
||||
istringstream buf(mapString);
|
||||
StringList items;
|
||||
string item;
|
||||
while(getline(buf, item, '|'))
|
||||
items.push_back(item);
|
||||
|
||||
// Error checking
|
||||
if(items.size() != 4)
|
||||
return false;
|
||||
|
||||
IntArray map;
|
||||
|
||||
// Parse axis/button/hat values
|
||||
getValues(items[1], map);
|
||||
if(int(map.size()) == numAxes * 2 * kNumModes)
|
||||
{
|
||||
// Fill the axes table with events
|
||||
auto event = map.cbegin();
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
for(int k = 0; k < 2; ++k)
|
||||
axisTable[a][k][m] = Event::Type(*event++);
|
||||
}
|
||||
getValues(items[2], map);
|
||||
if(int(map.size()) == numButtons * kNumModes)
|
||||
{
|
||||
auto event = map.cbegin();
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
btnTable[b][m] = Event::Type(*event++);
|
||||
}
|
||||
getValues(items[3], map);
|
||||
if(int(map.size()) == numHats * 4 * kNumModes)
|
||||
{
|
||||
auto event = map.cbegin();
|
||||
for(int m = 0; m < kNumModes; ++m)
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
for(int k = 0; k < 4; ++k)
|
||||
hatTable[h][k][m] = Event::Type(*event++);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::StellaJoystick::eraseMap(EventMode mode)
|
||||
{
|
||||
// Erase axis mappings
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
axisTable[a][0][mode] = axisTable[a][1][mode] = Event::NoType;
|
||||
|
||||
// Erase button mappings
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
btnTable[b][mode] = Event::NoType;
|
||||
|
||||
// Erase hat mappings
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
hatTable[h][0][mode] = hatTable[h][1][mode] =
|
||||
hatTable[h][2][mode] = hatTable[h][3][mode] = Event::NoType;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::StellaJoystick::eraseEvent(Event::Type event, EventMode mode)
|
||||
{
|
||||
// Erase axis mappings
|
||||
for(int a = 0; a < numAxes; ++a)
|
||||
{
|
||||
if(axisTable[a][0][mode] == event) axisTable[a][0][mode] = Event::NoType;
|
||||
if(axisTable[a][1][mode] == event) axisTable[a][1][mode] = Event::NoType;
|
||||
}
|
||||
|
||||
// Erase button mappings
|
||||
for(int b = 0; b < numButtons; ++b)
|
||||
if(btnTable[b][mode] == event) btnTable[b][mode] = Event::NoType;
|
||||
|
||||
// Erase hat mappings
|
||||
for(int h = 0; h < numHats; ++h)
|
||||
{
|
||||
if(hatTable[h][0][mode] == event) hatTable[h][0][mode] = Event::NoType;
|
||||
if(hatTable[h][1][mode] == event) hatTable[h][1][mode] = Event::NoType;
|
||||
if(hatTable[h][2][mode] == event) hatTable[h][2][mode] = Event::NoType;
|
||||
if(hatTable[h][3][mode] == event) hatTable[h][3][mode] = Event::NoType;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::StellaJoystick::getValues(const string& list, IntArray& map) const
|
||||
{
|
||||
map.clear();
|
||||
istringstream buf(list);
|
||||
|
||||
int value;
|
||||
buf >> value; // we don't need to know the # of items at this point
|
||||
while(buf >> value)
|
||||
map.push_back(value);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string EventHandler::StellaJoystick::about() const
|
||||
{
|
||||
ostringstream buf;
|
||||
buf << name;
|
||||
if(type == JT_REGULAR)
|
||||
buf << " with: " << numAxes << " axes, " << numButtons << " buttons, "
|
||||
<< numHats << " hats";
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventHandler::JoystickHandler::JoystickHandler(OSystem& system)
|
||||
: myOSystem(system)
|
||||
{
|
||||
// Load previously saved joystick mapping (if any) from settings
|
||||
istringstream buf(myOSystem.settings().getString("joymap"));
|
||||
string joymap, joyname;
|
||||
|
||||
// First check the event type, and disregard the entire mapping if it's invalid
|
||||
getline(buf, joymap, '^');
|
||||
if(atoi(joymap.c_str()) == Event::LastType)
|
||||
{
|
||||
// Otherwise, put each joystick mapping entry into the database
|
||||
while(getline(buf, joymap, '^'))
|
||||
{
|
||||
istringstream namebuf(joymap);
|
||||
getline(namebuf, joyname, '|');
|
||||
if(joyname.length() != 0)
|
||||
{
|
||||
StickInfo info(joymap);
|
||||
myDatabase.emplace(joyname, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventHandler::JoystickHandler::~JoystickHandler()
|
||||
{
|
||||
for(const auto& i: myDatabase)
|
||||
delete i.second.joy;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::JoystickHandler::printDatabase() const
|
||||
{
|
||||
cerr << "---------------------------------------------------------" << endl
|
||||
<< "joy database:" << endl;
|
||||
for(const auto& i: myDatabase)
|
||||
cerr << i.first << endl << i.second << endl << endl;
|
||||
|
||||
cerr << "---------------------" << endl
|
||||
<< "joy active:" << endl;
|
||||
for(const auto& i: mySticks)
|
||||
cerr << i.first << ": " << *i.second << endl;
|
||||
cerr << "---------------------------------------------------------" << endl << endl << endl;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool EventHandler::JoystickHandler::add(StellaJoystick* stick)
|
||||
{
|
||||
// Skip if we couldn't open it for any reason
|
||||
if(stick->ID < 0)
|
||||
return false;
|
||||
|
||||
// Figure out what type of joystick this is
|
||||
bool specialAdaptor = false;
|
||||
|
||||
if(BSPF::containsIgnoreCase(stick->name, "2600-daptor"))
|
||||
{
|
||||
// 2600-daptorII devices have 3 axes and 12 buttons, and the value of the z-axis
|
||||
// determines how those 12 buttons are used (not all buttons are used in all modes)
|
||||
if(stick->numAxes == 3)
|
||||
{
|
||||
// TODO - stubbed out for now, until we find a way to reliably get info
|
||||
// from the Z axis
|
||||
stick->name = "2600-daptor II";
|
||||
}
|
||||
else
|
||||
stick->name = "2600-daptor";
|
||||
|
||||
specialAdaptor = true;
|
||||
}
|
||||
else if(BSPF::containsIgnoreCase(stick->name, "Stelladaptor"))
|
||||
{
|
||||
stick->name = "Stelladaptor";
|
||||
specialAdaptor = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need unique names for mappable devices
|
||||
// For non-unique names that already have a database entry,
|
||||
// we append ' #x', where 'x' increases consecutively
|
||||
int count = 0;
|
||||
for(const auto& i: myDatabase)
|
||||
if(BSPF::startsWithIgnoreCase(i.first, stick->name) && i.second.joy)
|
||||
++count;
|
||||
|
||||
if(count > 0)
|
||||
{
|
||||
ostringstream name;
|
||||
name << stick->name << " #" << count+1;
|
||||
stick->name = name.str();
|
||||
}
|
||||
stick->type = StellaJoystick::JT_REGULAR;
|
||||
}
|
||||
// The stick *must* be inserted here, since it may be used below
|
||||
mySticks[stick->ID] = stick;
|
||||
|
||||
// Map the stelladaptors we've found according to the specified ports
|
||||
if(specialAdaptor)
|
||||
mapStelladaptors(myOSystem.settings().getString("saport"));
|
||||
|
||||
// Add stick to database
|
||||
auto it = myDatabase.find(stick->name);
|
||||
if(it != myDatabase.end()) // already present
|
||||
{
|
||||
it->second.joy = stick;
|
||||
stick->setMap(it->second.mapping);
|
||||
}
|
||||
else // adding for the first time
|
||||
{
|
||||
StickInfo info("", stick);
|
||||
myDatabase.emplace(stick->name, info);
|
||||
setStickDefaultMapping(stick->ID, Event::NoType, kEmulationMode);
|
||||
setStickDefaultMapping(stick->ID, Event::NoType, kMenuMode);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool EventHandler::JoystickHandler::remove(int id)
|
||||
{
|
||||
// When a joystick is removed, we delete the actual joystick object but
|
||||
// remember its mapping, since it will eventually be saved to settings
|
||||
|
||||
// Sticks that are removed must have initially been added
|
||||
// So we use the 'active' joystick list to access them
|
||||
try
|
||||
{
|
||||
StellaJoystick* stick = mySticks.at(id);
|
||||
|
||||
auto it = myDatabase.find(stick->name);
|
||||
if(it != myDatabase.end() && it->second.joy == stick)
|
||||
{
|
||||
ostringstream buf;
|
||||
buf << "Removed joystick " << mySticks[id]->ID << ":" << endl
|
||||
<< " " << mySticks[id]->about() << endl;
|
||||
myOSystem.logMessage(buf.str(), 1);
|
||||
|
||||
// Remove joystick, but remember mapping
|
||||
it->second.mapping = stick->getMap();
|
||||
delete it->second.joy; it->second.joy = nullptr;
|
||||
mySticks.erase(id);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch(std::out_of_range)
|
||||
{
|
||||
// fall through to indicate remove failed
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool EventHandler::JoystickHandler::remove(const string& name)
|
||||
{
|
||||
auto it = myDatabase.find(name);
|
||||
if(it != myDatabase.end() && it->second.joy == nullptr)
|
||||
{
|
||||
myDatabase.erase(it);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::JoystickHandler::mapStelladaptors(const string& saport)
|
||||
{
|
||||
// saport will have two values:
|
||||
// 'lr' means treat first valid adaptor as left port, second as right port
|
||||
// 'rl' means treat first valid adaptor as right port, second as left port
|
||||
// We know there will be only two such devices (at most), since the logic
|
||||
// in setupJoysticks take care of that
|
||||
int saCount = 0;
|
||||
int saOrder[2] = { 1, 2 };
|
||||
if(BSPF::equalsIgnoreCase(saport, "rl"))
|
||||
{
|
||||
saOrder[0] = 2; saOrder[1] = 1;
|
||||
}
|
||||
|
||||
for(auto& stick: mySticks)
|
||||
{
|
||||
if(BSPF::startsWithIgnoreCase(stick.second->name, "Stelladaptor"))
|
||||
{
|
||||
if(saOrder[saCount] == 1)
|
||||
{
|
||||
stick.second->name += " (emulates left joystick port)";
|
||||
stick.second->type = StellaJoystick::JT_STELLADAPTOR_LEFT;
|
||||
}
|
||||
else if(saOrder[saCount] == 2)
|
||||
{
|
||||
stick.second->name += " (emulates right joystick port)";
|
||||
stick.second->type = StellaJoystick::JT_STELLADAPTOR_RIGHT;
|
||||
}
|
||||
saCount++;
|
||||
}
|
||||
else if(BSPF::startsWithIgnoreCase(stick.second->name, "2600-daptor"))
|
||||
{
|
||||
if(saOrder[saCount] == 1)
|
||||
{
|
||||
stick.second->name += " (emulates left joystick port)";
|
||||
stick.second->type = StellaJoystick::JT_2600DAPTOR_LEFT;
|
||||
}
|
||||
else if(saOrder[saCount] == 2)
|
||||
{
|
||||
stick.second->name += " (emulates right joystick port)";
|
||||
stick.second->type = StellaJoystick::JT_2600DAPTOR_RIGHT;
|
||||
}
|
||||
saCount++;
|
||||
}
|
||||
}
|
||||
myOSystem.settings().setValue("saport", saport);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::JoystickHandler::setDefaultMapping(Event::Type event, EventMode mode)
|
||||
{
|
||||
eraseMapping(event, mode);
|
||||
for(auto& i: mySticks)
|
||||
setStickDefaultMapping(i.first, event, mode);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::JoystickHandler::setStickDefaultMapping(int stick,
|
||||
Event::Type event, EventMode mode)
|
||||
{
|
||||
EventHandler& handler = myOSystem.eventHandler();
|
||||
bool eraseAll = (event == Event::NoType);
|
||||
|
||||
auto setDefaultAxis = [&](int a_stick, int a_axis, int a_value, Event::Type a_event)
|
||||
{
|
||||
if(eraseAll || a_event == event)
|
||||
handler.addJoyAxisMapping(a_event, mode, a_stick, a_axis, a_value, false);
|
||||
};
|
||||
auto setDefaultBtn = [&](int b_stick, int b_button, Event::Type b_event)
|
||||
{
|
||||
if(eraseAll || b_event == event)
|
||||
handler.addJoyButtonMapping(b_event, mode, b_stick, b_button, false);
|
||||
};
|
||||
auto setDefaultHat = [&](int h_stick, int h_hat, JoyHat h_dir, Event::Type h_event)
|
||||
{
|
||||
if(eraseAll || h_event == event)
|
||||
handler.addJoyHatMapping(h_event, mode, h_stick, h_hat, h_dir, false);
|
||||
};
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case kEmulationMode: // Default emulation events
|
||||
if(stick == 0)
|
||||
{
|
||||
// Left joystick left/right directions (assume joystick zero)
|
||||
setDefaultAxis( 0, 0, 0, Event::JoystickZeroLeft );
|
||||
setDefaultAxis( 0, 0, 1, Event::JoystickZeroRight );
|
||||
// Left joystick up/down directions (assume joystick zero)
|
||||
setDefaultAxis( 0, 1, 0, Event::JoystickZeroUp );
|
||||
setDefaultAxis( 0, 1, 1, Event::JoystickZeroDown );
|
||||
// Left joystick (assume joystick zero, button zero)
|
||||
setDefaultBtn( 0, 0, Event::JoystickZeroFire );
|
||||
// Left joystick left/right directions (assume joystick zero and hat 0)
|
||||
setDefaultHat( 0, 0, JoyHat::LEFT, Event::JoystickZeroLeft );
|
||||
setDefaultHat( 0, 0, JoyHat::RIGHT, Event::JoystickZeroRight );
|
||||
// Left joystick up/down directions (assume joystick zero and hat 0)
|
||||
setDefaultHat( 0, 0, JoyHat::UP, Event::JoystickZeroUp );
|
||||
setDefaultHat( 0, 0, JoyHat::DOWN, Event::JoystickZeroDown );
|
||||
}
|
||||
else if(stick == 1)
|
||||
{
|
||||
// Right joystick left/right directions (assume joystick one)
|
||||
setDefaultAxis( 1, 0, 0, Event::JoystickOneLeft );
|
||||
setDefaultAxis( 1, 0, 1, Event::JoystickOneRight );
|
||||
// Right joystick left/right directions (assume joystick one)
|
||||
setDefaultAxis( 1, 1, 0, Event::JoystickOneUp );
|
||||
setDefaultAxis( 1, 1, 1, Event::JoystickOneDown );
|
||||
// Right joystick (assume joystick one, button zero)
|
||||
setDefaultBtn( 1, 0, Event::JoystickOneFire );
|
||||
// Right joystick left/right directions (assume joystick one and hat 0)
|
||||
setDefaultHat( 1, 0, JoyHat::LEFT, Event::JoystickOneLeft );
|
||||
setDefaultHat( 1, 0, JoyHat::RIGHT, Event::JoystickOneRight );
|
||||
// Right joystick up/down directions (assume joystick one and hat 0)
|
||||
setDefaultHat( 1, 0, JoyHat::UP, Event::JoystickOneUp );
|
||||
setDefaultHat( 1, 0, JoyHat::DOWN, Event::JoystickOneDown );
|
||||
}
|
||||
break;
|
||||
|
||||
case kMenuMode: // Default menu/UI events
|
||||
if(stick == 0)
|
||||
{
|
||||
setDefaultAxis( 0, 0, 0, Event::UILeft );
|
||||
setDefaultAxis( 0, 0, 1, Event::UIRight );
|
||||
setDefaultAxis( 0, 1, 0, Event::UIUp );
|
||||
setDefaultAxis( 0, 1, 1, Event::UIDown );
|
||||
|
||||
// Left joystick (assume joystick zero, button zero)
|
||||
setDefaultBtn( 0, 0, Event::UISelect );
|
||||
|
||||
setDefaultHat( 0, 0, JoyHat::LEFT, Event::UILeft );
|
||||
setDefaultHat( 0, 0, JoyHat::RIGHT, Event::UIRight );
|
||||
setDefaultHat( 0, 0, JoyHat::UP, Event::UIUp );
|
||||
setDefaultHat( 0, 0, JoyHat::DOWN, Event::UIDown );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::JoystickHandler::eraseMapping(Event::Type event, EventMode mode)
|
||||
{
|
||||
// If event is 'NoType', erase and reset all mappings
|
||||
// Otherwise, only reset the given event
|
||||
if(event == Event::NoType)
|
||||
{
|
||||
for(auto& stick: mySticks)
|
||||
stick.second->eraseMap(mode); // erase all events
|
||||
}
|
||||
else
|
||||
{
|
||||
for(auto& stick: mySticks)
|
||||
stick.second->eraseEvent(event, mode); // only reset the specific event
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandler::JoystickHandler::saveMapping()
|
||||
{
|
||||
// Save the joystick mapping hash table, making sure to update it with
|
||||
// any changes that have been made during the program run
|
||||
ostringstream joybuf;
|
||||
joybuf << Event::LastType;
|
||||
|
||||
for(const auto& i: myDatabase)
|
||||
{
|
||||
const string& map = i.second.joy ? i.second.joy->getMap() : i.second.mapping;
|
||||
if(map != "")
|
||||
joybuf << "^" << map;
|
||||
}
|
||||
myOSystem.settings().setValue("joymap", joybuf.str());
|
||||
}
|
|
@ -53,7 +53,6 @@ MODULE_OBJS := \
|
|||
src/emucore/Control.o \
|
||||
src/emucore/Driving.o \
|
||||
src/emucore/EventHandler.o \
|
||||
src/emucore/EventJoyHandler.o \
|
||||
src/emucore/FrameBuffer.o \
|
||||
src/emucore/FBSurface.o \
|
||||
src/emucore/FSNode.o \
|
||||
|
|
|
@ -271,7 +271,7 @@ void DialogContainer::handleMouseButtonEvent(MouseButton b, bool pressed,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DialogContainer::handleJoyEvent(int stick, int button, uInt8 state)
|
||||
void DialogContainer::handleJoyBtnEvent(int stick, int button, uInt8 state)
|
||||
{
|
||||
if(myDialogStack.empty())
|
||||
return;
|
||||
|
|
|
@ -99,7 +99,7 @@ class DialogContainer
|
|||
@param button The joystick button
|
||||
@param state The state (pressed or released)
|
||||
*/
|
||||
void handleJoyEvent(int stick, int button, uInt8 state);
|
||||
void handleJoyBtnEvent(int stick, int button, uInt8 state);
|
||||
|
||||
/**
|
||||
Handle a joystick axis event.
|
||||
|
|
|
@ -75,7 +75,7 @@ void JoystickDialog::loadConfig()
|
|||
myJoyIDs.clear();
|
||||
|
||||
StringList sticks;
|
||||
for(const auto& i: instance().eventHandler().joystickDatabase())
|
||||
for(const auto& i: instance().eventHandler().physicalJoystickDatabase())
|
||||
{
|
||||
sticks.push_back(i.first);
|
||||
myJoyIDs.push_back(i.second.toInt());
|
||||
|
@ -99,7 +99,8 @@ void JoystickDialog::handleCommand(CommandSender* sender, int cmd, int data, int
|
|||
break;
|
||||
|
||||
case kRemoveCmd:
|
||||
instance().eventHandler().removeJoystickFromDatabase(myJoyList->getSelectedString());
|
||||
instance().eventHandler().removePhysicalJoystickFromDatabase(
|
||||
myJoyList->getSelectedString());
|
||||
loadConfig();
|
||||
break;
|
||||
|
||||
|
|
Loading…
Reference in New Issue