diff --git a/src/common/JoyMap.cxx b/src/common/JoyMap.cxx new file mode 100644 index 000000000..f74bfcba5 --- /dev/null +++ b/src/common/JoyMap.cxx @@ -0,0 +1,248 @@ +//============================================================================ +// +// 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-2019 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 "JoyMap.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +JoyMap::JoyMap(void) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoyMap::add(const Event::Type event, const JoyMapping& mapping) +{ + myMap[mapping] = event; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoyMap::add(const Event::Type event, const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir, + const int hat, const JoyHat hdir) +{ + add(event, JoyMapping(mode, button, axis, adir, hat, hdir)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoyMap::add(const Event::Type event, const EventMode mode, const int button, + const int hat, const JoyHat hdir) +{ + add(event, JoyMapping(mode, button, hat, hdir)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoyMap::erase(const JoyMapping& mapping) +{ + myMap.erase(mapping); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoyMap::erase(const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir) +{ + erase(JoyMapping(mode, button, axis, adir)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoyMap::erase(const EventMode mode, const int button, + const int hat, const JoyHat hdir) +{ + erase(JoyMapping(mode, button, hat, hdir)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Event::Type JoyMap::get(const JoyMapping& mapping) const +{ + auto find = myMap.find(mapping); + if (find != myMap.end()) + return find->second; + + // try without button as modifier + JoyMapping m = mapping; + + m.button = JOY_CTRL_NONE; + + find = myMap.find(m); + if (find != myMap.end()) + return find->second; + + return Event::Type::NoType; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Event::Type JoyMap::get(const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir) const +{ + return get(JoyMapping(mode, button, axis, adir)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Event::Type JoyMap::get(const EventMode mode, const int button, + const int hat, const JoyHat hdir) const +{ + return get(JoyMapping(mode, button, hat, hdir)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool JoyMap::check(const JoyMapping & mapping) const +{ + auto find = myMap.find(mapping); + + return (find != myMap.end()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool JoyMap::check(const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir, + const int hat, const JoyHat hdir) const +{ + return check(JoyMapping(mode, button, axis, adir, hat, hdir)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string JoyMap::getDesc(const Event::Type event, const JoyMapping& mapping) const +{ + ostringstream buf; + + // button description + if (mapping.button != JOY_CTRL_NONE) + buf << "/B" << mapping.button; + + // axis description + if (mapping.axis != JoyAxis::NONE) + { + buf << "/A"; + switch (mapping.axis) + { + case JoyAxis::X: buf << "X"; break; + case JoyAxis::Y: buf << "Y"; break; + case JoyAxis::Z: buf << "Z"; break; + default: buf << int(mapping.axis); break; + } + + if (Event::isAnalog(event)) + buf << "+|-"; + else if (mapping.adir == JoyDir::NEG) + buf << "-"; + else + buf << "+"; + } + + // hat description + if (mapping.hat != JOY_CTRL_NONE) + { + buf << "/H" << mapping.hat; + switch (mapping.hdir) + { + case JoyHat::UP: buf << "/up"; break; + case JoyHat::DOWN: buf << "/down"; break; + case JoyHat::LEFT: buf << "/left"; break; + case JoyHat::RIGHT: buf << "/right"; break; + default: break; + } + } + + return buf.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string JoyMap::getEventMappingDesc(int stick, const Event::Type event, const EventMode mode) const +{ + ostringstream buf; + + for (auto item : myMap) + { + if (item.second == event && item.first.mode == mode) + { + if (buf.str() != "") + buf << ", "; + buf << "J" << stick << getDesc(event, item.first); + } + } + return buf.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +JoyMap::JoyMappingArray JoyMap::getEventMapping(const Event::Type event, const EventMode mode) const +{ + JoyMappingArray map; + + for (auto item : myMap) + if (item.second == event && item.first.mode == mode) + map.push_back(item.first); + + return map; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string JoyMap::saveMapping(const EventMode mode) const +{ + ostringstream buf; + + for (auto item : myMap) + { + if (item.first.mode == mode) + { + if (buf.str() != "") + buf << "|"; + buf << item.second << ":" << item.first.button << "," + << int(item.first.axis) << "," << int(item.first.adir) << "," + << item.first.hat << "," << int(item.first.hdir); + } + } + return buf.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int JoyMap::loadMapping(string& list, const EventMode mode) +{ + // Since istringstream swallows whitespace, we have to make the + // delimiters be spaces + std::replace(list.begin(), list.end(), '|', ' '); + std::replace(list.begin(), list.end(), ':', ' '); + std::replace(list.begin(), list.end(), ',', ' '); + istringstream buf(list); + int event, button, axis, adir, hat, hdir, i = 0; + + while (buf >> event && buf >> button + && buf >> axis && buf >> adir + && buf >> hat && buf >> hdir && ++i) + add(Event::Type(event), EventMode(mode), button, JoyAxis(axis), JoyDir(adir), hat, JoyHat(hdir)); + + return i; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoyMap::eraseMode(const EventMode mode) +{ + for (auto item = myMap.begin(); item != myMap.end();) + if (item->first.mode == mode) { + auto _item = item++; + erase(_item->first); + } + else item++; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoyMap::eraseEvent(const Event::Type event, const EventMode mode) +{ + for (auto item = myMap.begin(); item != myMap.end();) + if (item->second == event && item->first.mode == mode) { + auto _item = item++; + erase(_item->first); + } + else item++; +} diff --git a/src/common/JoyMap.hxx b/src/common/JoyMap.hxx new file mode 100644 index 000000000..6706bb49b --- /dev/null +++ b/src/common/JoyMap.hxx @@ -0,0 +1,147 @@ +//============================================================================ +// +// 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-2019 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 CONTROLLERMAP_HXX +#define CONTROLLERMAP_HXX + +#include +#include "Event.hxx" +#include "EventHandlerConstants.hxx" + +/** + This class handles controller mappings in Stella. + + @author Thomas Jentzsch +*/ +class JoyMap +{ + public: + + struct JoyMapping + { + EventMode mode; + int button; // button number + JoyAxis axis; // horizontal/vertical + JoyDir adir; // axis direction (neg/pos) + int hat; // hat number + JoyHat hdir; // hat direction (left/right/up/down) + + JoyMapping() + : mode(EventMode(0)), button(0), + axis(JoyAxis(0)), adir(JoyDir(0)), + hat(0), hdir(JoyHat(0)) { } + JoyMapping(const JoyMapping& m) + : mode(m.mode), button(m.button), + axis(m.axis), adir(m.adir), + hat(m.hat), hdir(m.hdir) { } + explicit JoyMapping(EventMode c_mode, int c_button, + JoyAxis c_axis, JoyDir c_adir, + int c_hat, JoyHat c_hdir) + : mode(c_mode), button(c_button), + axis(c_axis), adir(c_adir), + hat(c_hat), hdir(c_hdir) { } + explicit JoyMapping(EventMode c_mode, int c_button, + JoyAxis c_axis, JoyDir c_adir) + : mode(c_mode), button(c_button), + axis(c_axis), adir(c_adir), + hat(JOY_CTRL_NONE), hdir(JoyHat::CENTER) { } + explicit JoyMapping(EventMode c_mode, int c_button, + int c_hat, JoyHat c_hdir) + : mode(c_mode), button(c_button), + axis(JoyAxis::NONE), adir(JoyDir::NONE), + hat(c_hat), hdir(c_hdir) { } + + bool operator==(const JoyMapping& other) const + { + return (mode == other.mode + && button == other.button + && axis == other.axis + && adir == other.adir + && hat == other.hat + && hdir == other.hdir + ); + } + }; + using JoyMappingArray = std::vector; + + JoyMap(); + virtual ~JoyMap() = default; + + /** Add new mapping for given event */ + void add(const Event::Type event, const JoyMapping& mapping); + void add(const Event::Type event, const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir, + const int hat = JOY_CTRL_NONE, const JoyHat hdir = JoyHat::CENTER); + void add(const Event::Type event, const EventMode mode, const int button, + const int hat, const JoyHat hdir); + + /** Erase mapping */ + void erase(const JoyMapping& mapping); + void erase(const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir); + void erase(const EventMode mode, const int button, + const int hat, const JoyHat hdir); + + + /** Get event for mapping */ + Event::Type get(const JoyMapping& mapping) const; + Event::Type get(const EventMode mode, const int button, + const JoyAxis axis = JoyAxis::NONE, const JoyDir adir = JoyDir::NONE) const; + Event::Type get(const EventMode mode, const int button, + const int hat, const JoyHat hdir) const; + + /** Check if a mapping exists */ + bool check(const JoyMapping& mapping) const; + bool check(const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir, + const int hat = JOY_CTRL_NONE, const JoyHat hdir = JoyHat::CENTER) const; + + /** Get mapping description */ + string getEventMappingDesc(int stick, const Event::Type event, const EventMode mode) const; + + JoyMappingArray getEventMapping(const Event::Type event, const EventMode mode) const; + + string saveMapping(const EventMode mode) const; + int loadMapping(string& list, const EventMode mode); + + /** Erase all mappings for given mode */ + void eraseMode(const EventMode mode); + /** Erase given event's mapping for given mode */ + void eraseEvent(const Event::Type event, const EventMode mode); + /** clear all mappings for a modes */ + // void clear() { myMap.clear(); } + size_t size() { return myMap.size(); } + + private: + string getDesc(const Event::Type event, const JoyMapping& mapping) const; + + struct JoyHash { + size_t operator()(const JoyMapping& m)const { + return std::hash()((uInt64(m.mode)) // 3 bit + ^ ((uInt64(m.button)) << 2) // 2 bits + ^ ((uInt64(m.axis)) << 4) // 1 bit + ^ ((uInt64(m.adir)) << 5) // 1 bit + ^ ((uInt64(m.hat)) << 6) // 1 bit + ^ ((uInt64(m.hdir)) << 7) // 2 bits + ); + } + }; + + std::unordered_map myMap; +}; + +#endif diff --git a/src/common/KeyMap.cxx b/src/common/KeyMap.cxx index 4f5515828..551b1a86e 100644 --- a/src/common/KeyMap.cxx +++ b/src/common/KeyMap.cxx @@ -161,9 +161,9 @@ string KeyMap::getEventMappingDesc(const Event::Type event, const int mode) cons } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -std::vector KeyMap::getEventMapping(const Event::Type event, const int mode) const +KeyMap::MappingArray KeyMap::getEventMapping(const Event::Type event, const int mode) const { - std::vector map; + MappingArray map; for (auto item : myMap) if (item.second == event && item.first.mode == mode) diff --git a/src/common/KeyMap.hxx b/src/common/KeyMap.hxx index 5b0d82ef5..f69d92b1e 100644 --- a/src/common/KeyMap.hxx +++ b/src/common/KeyMap.hxx @@ -55,6 +55,7 @@ class KeyMap ); } }; + using MappingArray = std::vector; KeyMap(); virtual ~KeyMap() = default; @@ -82,7 +83,7 @@ class KeyMap /** Get the mapping description(s) for given event and mode */ string getEventMappingDesc(const Event::Type event, const int mode) const; - std::vector getEventMapping(const Event::Type event, const int mode) const; + MappingArray getEventMapping(const Event::Type event, const int mode) const; string saveMapping(const int mode) const; int loadMapping(string& list, const int mode); diff --git a/src/common/PJoystickHandler.cxx b/src/common/PJoystickHandler.cxx index 7af501c8f..a2bfb94db 100644 --- a/src/common/PJoystickHandler.cxx +++ b/src/common/PJoystickHandler.cxx @@ -27,6 +27,8 @@ #include "DialogContainer.hxx" #endif +static constexpr char CTRL_DELIM = '^'; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PhysicalJoystickHandler::PhysicalJoystickHandler( OSystem& system, EventHandler& handler, Event& event) @@ -40,14 +42,14 @@ PhysicalJoystickHandler::PhysicalJoystickHandler( string joymap, joyname; // First compare if event list version has changed, and disregard the entire mapping if true - getline(buf, joymap, '^'); // event list size, ignore + getline(buf, joymap, CTRL_DELIM); // event list size, ignore if(version == Event::VERSION) { // Otherwise, put each joystick mapping entry into the database - while(getline(buf, joymap, '^')) + while(getline(buf, joymap, CTRL_DELIM)) { istringstream namebuf(joymap); - getline(namebuf, joyname, '|'); + getline(namebuf, joyname, PhysicalJoystick::MODE_DELIM); if(joyname.length() != 0) myDatabase.emplace(joyname, StickInfo(joymap)); } @@ -111,30 +113,17 @@ int PhysicalJoystickHandler::add(PhysicalJoystickPtr stick) // Add stick to database auto it = myDatabase.find(stick->name); - if(it != myDatabase.end()) // already present + if(it != myDatabase.end()) // already present { it->second.joy = stick; stick->setMap(it->second.mapping); } - else // adding for the first time + 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 < NUM_PORTS; ++i) - { - for(int j = 0; j < NUM_JOY_AXIS; ++j) - myEvent.set(SA_Axis[i][j], 0); - for(int j = 0; j < NUM_JOY_BTN; ++j) - myEvent.set(SA_Button[i][j], 0); - for(int j = 0; j < NUM_KEY_BTN; ++j) - myEvent.set(SA_Key[i][j], 0); + setStickDefaultMapping(stick->ID, Event::NoType, kEmulationMode, true); + setStickDefaultMapping(stick->ID, Event::NoType, kMenuMode, true); } return stick->ID; @@ -205,6 +194,12 @@ void PhysicalJoystickHandler::mapStelladaptors(const string& saport) for(auto& stick: mySticks) { + // remove previously added emulated ports + size_t pos = stick.second->name.find(" (emulates "); + + if (pos != std::string::npos) + stick.second->name.erase(pos); + if(BSPF::startsWithIgnoreCase(stick.second->name, "Stelladaptor")) { if(saOrder[saCount] == 1) @@ -237,122 +232,247 @@ void PhysicalJoystickHandler::mapStelladaptors(const string& saport) myOSystem.settings().setValue("saport", saport); } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Depending on parameters, this method does the following: +// 1. update all events with default (event == Event::NoType, updateDefault == true) +// 2. reset all events to default (event == Event::NoType, updateDefault == false) +// 3. reset one event to default (event != Event::NoType) +void PhysicalJoystickHandler::setDefaultAction(const PhysicalJoystickPtr& j, + EventMapping map, Event::Type event, + EventMode mode, bool updateDefaults) +{ + // If event is 'NoType', erase and reset all mappings + // Otherwise, only reset the given event + bool eraseAll = !updateDefaults && (event == Event::NoType); + + if (updateDefaults) + { + // if there is no existing mapping for the event or + // the default mapping for the event is unused, set default key for event + if (j->joyMap.getEventMapping(map.event, mode).size() == 0 || + !j->joyMap.check(mode, map.button, map.axis, map.adir, map.hat, map.hdir)) + { + j->joyMap.add(map.event, mode, map.button, map.axis, map.adir, map.hat, map.hdir); + } + } + else if (eraseAll || map.event == event) + { + // TODO: allow for multiple defaults + //j->joyMap.eraseEvent(map.event, mode); + j->joyMap.add(map.event, mode, map.button, map.axis, map.adir, map.hat, map.hdir); + } + +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type event, + EventMode mode, bool updateDefaults) +{ + const PhysicalJoystickPtr j = joy(stick); + + if(j) + { + switch (mode) + { + case kEmulationMode: + if ((stick % 2) == 0) // even sticks + { + // put all controller events into their own mode's mappings + for (const auto& item : DefaultLeftJoystickMapping) + setDefaultAction(j, item, event, kJoystickMode, updateDefaults); + for (const auto& item : DefaultLeftPaddlesMapping) + setDefaultAction(j, item, event, kPaddlesMode, updateDefaults); + for (const auto& item : DefaultLeftKeypadMapping) + setDefaultAction(j, item, event, kKeypadMode, updateDefaults); + } + else // odd sticks + { + // put all controller events into their own mode's mappings + for (const auto& item : DefaultRightJoystickMapping) + setDefaultAction(j, item, event, kJoystickMode, updateDefaults); + for (const auto& item : DefaultRightPaddlesMapping) + setDefaultAction(j, item, event, kPaddlesMode, updateDefaults); + for (const auto& item : DefaultRightKeypadMapping) + setDefaultAction(j, item, event, kKeypadMode, updateDefaults); + } + break; + + case kMenuMode: + for (const auto& item : DefaultMenuMapping) + setDefaultAction(j, item, event, kMenuMode, updateDefaults); + break; + + default: + break; + } + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PhysicalJoystickHandler::setDefaultMapping(Event::Type event, EventMode mode) { eraseMapping(event, mode); - for(auto& i: mySticks) + for (auto& i : mySticks) setStickDefaultMapping(i.first, event, mode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PhysicalJoystickHandler::setStickDefaultMapping(int stick, - Event::Type event, EventMode mode) +void PhysicalJoystickHandler::defineControllerMappings(const string& controllerName, Controller::Jack port) { - bool eraseAll = (event == Event::NoType); + // determine controller events to use + if ((controllerName == "KEYBOARD") || (controllerName == "KEYPAD")) + { + if (port == Controller::Jack::Left) + myLeftMode = kKeypadMode; + else + myRightMode = kKeypadMode; + } + else if (BSPF::startsWithIgnoreCase(controllerName, "PADDLES")) + { + if (port == Controller::Jack::Left) + myLeftMode = kPaddlesMode; + else + myRightMode = kPaddlesMode; + } + else if (controllerName == "CM") + { + myLeftMode = myRightMode = kCompuMateMode; + } + else + { + if (port == Controller::Jack::Left) + myLeftMode = kJoystickMode; + else + myRightMode = kJoystickMode; + } +} - auto setDefaultAxis = [&](int a_stick, JoyAxis a_axis, JoyDir a_value, Event::Type a_event) +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PhysicalJoystickHandler::enableEmulationMappings() +{ + for (auto& stick : mySticks) { - if(eraseAll || a_event == event) - myHandler.addJoyAxisMapping(a_event, mode, a_stick, int(a_axis), int(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); - }; + const PhysicalJoystickPtr j = stick.second; - switch(mode) + // start from scratch and enable common mappings + j->joyMap.eraseMode(kEmulationMode); + } + + enableCommonMappings(); + + // enable right mode first, so that in case of mapping clashes the left controller has preference + switch (myRightMode) { - case kEmulationMode: // Default emulation events - switch (stick) - { - case 0: - case 2: - // Left joystick left/right directions (assume joystick zero or two) - setDefaultAxis(stick, JoyAxis::X, JoyDir::NEG, Event::JoystickZeroLeft); - setDefaultAxis(stick, JoyAxis::X, JoyDir::POS, Event::JoystickZeroRight); - // Left joystick up/down directions (assume joystick zero or two) - setDefaultAxis(stick, JoyAxis::Y, JoyDir::NEG, Event::JoystickZeroUp); - setDefaultAxis(stick, JoyAxis::Y, JoyDir::POS, Event::JoystickZeroDown); - // Left joystick (assume joystick zero or two, buttons zero..two) - setDefaultBtn(stick, 0, Event::JoystickZeroFire); - setDefaultBtn(stick, 1, Event::JoystickZeroFire5); - setDefaultBtn(stick, 2, Event::JoystickZeroFire9); - // Left joystick left/right directions (assume joystick zero or two and hat 0) - setDefaultHat(stick, 0, JoyHat::LEFT, Event::JoystickZeroLeft); - setDefaultHat(stick, 0, JoyHat::RIGHT, Event::JoystickZeroRight); - // Left joystick up/down directions (assume joystick zero or two and hat 0) - setDefaultHat(stick, 0, JoyHat::UP, Event::JoystickZeroUp); - setDefaultHat(stick, 0, JoyHat::DOWN, Event::JoystickZeroDown); - #if defined(RETRON77) - // Left joystick (assume joystick zero or two, buttons two..four) - setDefaultBtn(stick, 2, Event::CmdMenuMode); - setDefaultBtn(stick, 3, Event::OptionsMenuMode); - setDefaultBtn(stick, 4, Event::ExitMode); - #endif - break; - case 1: - case 3: - // Right joystick left/right directions (assume joystick one or three) - setDefaultAxis(stick, JoyAxis::X, JoyDir::NEG, Event::JoystickOneLeft); - setDefaultAxis(stick, JoyAxis::X, JoyDir::POS, Event::JoystickOneRight); - // Right joystick left/right directions (assume joystick one or three) - setDefaultAxis(stick, JoyAxis::Y, JoyDir::NEG, Event::JoystickOneUp); - setDefaultAxis(stick, JoyAxis::Y, JoyDir::POS, Event::JoystickOneDown); - // Right joystick (assume joystick one or three, buttons zero..two) - setDefaultBtn(stick, 0, Event::JoystickOneFire); - setDefaultBtn(stick, 1, Event::JoystickOneFire5); - setDefaultBtn(stick, 2, Event::JoystickOneFire9); - // Right joystick left/right directions (assume joystick one or three and hat 0) - setDefaultHat(stick, 0, JoyHat::LEFT, Event::JoystickOneLeft); - setDefaultHat(stick, 0, JoyHat::RIGHT, Event::JoystickOneRight); - // Right joystick up/down directions (assume joystick one or three and hat 0) - setDefaultHat(stick, 0, JoyHat::UP, Event::JoystickOneUp); - setDefaultHat(stick, 0, JoyHat::DOWN, Event::JoystickOneDown); - #if defined(RETRON77) - // Right joystick (assume joystick one or three, buttons two..four) - setDefaultBtn(stick, 2, Event::CmdMenuMode); - setDefaultBtn(stick, 3, Event::OptionsMenuMode); - setDefaultBtn(stick, 4, Event::ExitMode); - setDefaultBtn(stick, 5, Event::RewindPause); - setDefaultBtn(stick, 7, Event::ConsoleSelect); - setDefaultBtn(stick, 8, Event::ConsoleReset); - #endif - break; - default: - break; - } + case kPaddlesMode: + enableMappings(RightPaddlesEvents, kPaddlesMode); break; - case kMenuMode: // Default menu/UI events - setDefaultAxis( stick, JoyAxis::X, JoyDir::NEG, Event::UINavPrev ); - setDefaultAxis( stick, JoyAxis::X, JoyDir::POS, Event::UINavNext ); - setDefaultAxis( stick, JoyAxis::Y, JoyDir::NEG, Event::UIUp ); - setDefaultAxis( stick, JoyAxis::Y, JoyDir::POS, Event::UIDown ); - - // joystick (assume buttons zero..three) - setDefaultBtn( stick, 0, Event::UISelect ); - setDefaultBtn( stick, 1, Event::UIOK ); - setDefaultBtn( stick, 2, Event::UITabNext); - setDefaultBtn( stick, 3, Event::UITabPrev ); - setDefaultBtn( stick, 5, Event::UICancel); - - setDefaultHat( stick, 0, JoyHat::LEFT, Event::UINavPrev ); - setDefaultHat( stick, 0, JoyHat::RIGHT, Event::UINavNext ); - setDefaultHat( stick, 0, JoyHat::UP, Event::UIUp ); - setDefaultHat( stick, 0, JoyHat::DOWN, Event::UIDown ); + case kKeypadMode: + enableMappings(RightKeypadEvents, kKeypadMode); break; default: + enableMappings(RightJoystickEvents, kJoystickMode); break; } + switch (myLeftMode) + { + case kPaddlesMode: + enableMappings(LeftPaddlesEvents, kPaddlesMode); + break; + + case kKeypadMode: + enableMappings(LeftKeypadEvents, kKeypadMode); + break; + + default: + enableMappings(LeftJoystickEvents, kJoystickMode); + break; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PhysicalJoystickHandler::enableCommonMappings() +{ + for (int i = Event::NoType + 1; i < Event::LastType; i++) + { + Event::Type event = static_cast(i); + + if (isCommonEvent(event)) + enableMapping(event, kCommonMode); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PhysicalJoystickHandler::enableMappings(const Event::EventSet events, EventMode mode) +{ + for (const auto& event : events) + enableMapping(event, mode); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PhysicalJoystickHandler::enableMapping(const Event::Type event, EventMode mode) +{ + // copy from controller mode into emulation mode + for (auto& stick : mySticks) + { + const PhysicalJoystickPtr j = stick.second; + + JoyMap::JoyMappingArray joyMappings = j->joyMap.getEventMapping(event, mode); + + for (const auto& mapping : joyMappings) + j->joyMap.add(event, kEmulationMode, mapping.button, mapping.axis, mapping.adir); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +EventMode PhysicalJoystickHandler::getEventMode(const Event::Type event, const EventMode mode) const +{ + if (mode == kEmulationMode) + { + if (isJoystickEvent(event)) + return kJoystickMode; + + if (isPaddleEvent(event)) + return kPaddlesMode; + + if (isKeypadEvent(event)) + return kKeypadMode; + + if (isCommonEvent(event)) + return kCommonMode; + } + + return mode; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool PhysicalJoystickHandler::isJoystickEvent(const Event::Type event) const +{ + return LeftJoystickEvents.find(event) != LeftJoystickEvents.end() + || RightJoystickEvents.find(event) != RightJoystickEvents.end(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool PhysicalJoystickHandler::isPaddleEvent(const Event::Type event) const +{ + return LeftPaddlesEvents.find(event) != LeftPaddlesEvents.end() + || RightPaddlesEvents.find(event) != RightPaddlesEvents.end(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool PhysicalJoystickHandler::isKeypadEvent(const Event::Type event) const +{ + return LeftKeypadEvents.find(event) != LeftKeypadEvents.end() + || RightKeypadEvents.find(event) != RightKeypadEvents.end(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool PhysicalJoystickHandler::isCommonEvent(const Event::Type event) const +{ + return !(isJoystickEvent(event) || isPaddleEvent(event) || isKeypadEvent(event)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -362,13 +482,25 @@ void PhysicalJoystickHandler::eraseMapping(Event::Type event, EventMode mode) // Otherwise, only reset the given event if(event == Event::NoType) { - for(auto& stick: mySticks) + for (auto& stick : mySticks) + { stick.second->eraseMap(mode); // erase all events + if (mode == kEmulationMode) + { + stick.second->eraseMap(kCommonMode); + stick.second->eraseMap(kJoystickMode); + stick.second->eraseMap(kPaddlesMode); + stick.second->eraseMap(kKeypadMode); + } + } } else { - for(auto& stick: mySticks) + for (auto& stick : mySticks) + { stick.second->eraseEvent(event, mode); // only reset the specific event + stick.second->eraseEvent(event, getEventMode(event, mode)); + } } } @@ -378,13 +510,12 @@ 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; + joybuf << CTRL_DELIM << map; } myOSystem.settings().setValue("joymap", joybuf.str()); } @@ -393,66 +524,21 @@ void PhysicalJoystickHandler::saveMapping() string PhysicalJoystickHandler::getMappingDesc(Event::Type event, EventMode mode) const { ostringstream buf; + EventMode evMode = getEventMode(event, mode); for(const auto& s: mySticks) { uInt32 stick = s.first; const PhysicalJoystickPtr j = s.second; - if(!j) continue; - // Joystick button mapping/labeling - for(int button = 0; button < j->numButtons; ++button) + if (j) { - if(j->btnTable[button][mode] == event) + //Joystick mapping / labeling + if (j->joyMap.getEventMapping(event, evMode).size()) { - if(buf.str() != "") + 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 < NUM_JOY_DIRS; ++dir) - { - if(j->axisTable[axis][dir][mode] == event) - { - if(buf.str() != "") - buf << ", "; - buf << "J" << stick << "/A" << axis; - if(Event::isAnalog(event)) - { - dir = NUM_JOY_DIRS; // 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 < NUM_JOY_HAT_DIRS; ++dir) - { - if(j->hatTable[hat][dir][mode] == event) - { - if(buf.str() != "") - buf << ", "; - buf << "J" << stick << "/H" << hat; - switch(JoyHat(dir)) - { - case JoyHat::UP: buf << "/up"; break; - case JoyHat::DOWN: buf << "/down"; break; - case JoyHat::LEFT: buf << "/left"; break; - case JoyHat::RIGHT: buf << "/right"; break; - default: break; - } - } + buf << j->joyMap.getEventMappingDesc(stick, event, evMode); } } } @@ -460,63 +546,48 @@ string PhysicalJoystickHandler::getMappingDesc(Event::Type event, EventMode mode } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool PhysicalJoystickHandler::addAxisMapping(Event::Type event, EventMode mode, - int stick, int axis, int value) +bool PhysicalJoystickHandler::addJoyMapping(Event::Type event, EventMode mode, int stick, + int button, JoyAxis axis, int value) { const PhysicalJoystickPtr j = joy(stick); - if(j) - { - if(int(axis) >= 0 && int(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][int(JoyDir::NEG)][mode] = j->axisTable[axis][int(JoyDir::POS)][mode] = event; - else - { - // Otherwise, turn off the analog event(s) for this axis - if(Event::isAnalog(j->axisTable[axis][int(JoyDir::NEG)][mode])) - j->axisTable[axis][int(JoyDir::NEG)][mode] = Event::NoType; - if(Event::isAnalog(j->axisTable[axis][int(JoyDir::POS)][mode])) - j->axisTable[axis][int(JoyDir::POS)][mode] = Event::NoType; - j->axisTable[axis][(value > int(JoyDir::NEG))][mode] = event; - } - return true; + if (j && event < Event::LastType && + button >= JOY_CTRL_NONE && button < j->numButtons && + axis >= JoyAxis::NONE && int(axis) < j->numAxes) + { + EventMode evMode = getEventMode(event, mode); + + // 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->joyMap.add(event, evMode, button, axis, JoyDir::ANALOG); } + else + { + // Otherwise, turn off the analog event(s) for this axis + if (Event::isAnalog(j->joyMap.get(evMode, button, axis, JoyDir::ANALOG))) + j->joyMap.erase(evMode, button, axis, JoyDir::ANALOG); + + j->joyMap.add(event, evMode, button, axis, convertAxisValue(value)); + } + return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool PhysicalJoystickHandler::addBtnMapping(Event::Type event, EventMode mode, - int stick, int button) +bool PhysicalJoystickHandler::addJoyHatMapping(Event::Type event, EventMode mode, int stick, + int button, int hat, JoyHat dir) { const PhysicalJoystickPtr j = joy(stick); - if(j) - { - if(button >= 0 && button < j->numButtons && event < Event::LastType) - { - j->btnTable[button][mode] = event; - return true; - } - } - return false; -} -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool PhysicalJoystickHandler::addHatMapping(Event::Type event, EventMode mode, - int stick, int hat, JoyHat value) -{ - const PhysicalJoystickPtr j = joy(stick); - if(j) + if (j && event < Event::LastType && + button >= JOY_CTRL_NONE && button < j->numButtons && + hat >= 0 && hat < j->numHats && dir != JoyHat::CENTER) { - if(hat >= 0 && hat < j->numHats && event < Event::LastType && - value != JoyHat::CENTER) - { - j->hatTable[hat][int(value)][mode] = event; - return true; - } + j->joyMap.add(event, getEventMode(event, mode), button, hat, dir); + return true; } return false; } @@ -525,102 +596,71 @@ bool PhysicalJoystickHandler::addHatMapping(Event::Type event, EventMode mode, void PhysicalJoystickHandler::handleAxisEvent(int stick, int axis, int value) { const PhysicalJoystickPtr j = joy(stick); - if(!j) return; - // Stelladaptors handle axis differently than regular joysticks - switch(j->type) + if (j) { - case PhysicalJoystick::JT_REGULAR: - if(myHandler.state() == EventHandlerState::EMULATION) + int button = j->buttonLast[stick]; + + if (myHandler.state() == EventHandlerState::EMULATION) + { + Event::Type eventAxisAnalog = j->joyMap.get(kEmulationMode, button, JoyAxis(axis), JoyDir::ANALOG); + + // Check for analog events, which are handled differently + if (Event::isAnalog(eventAxisAnalog)) { - // Every axis event has two associated values, negative and positive - Event::Type eventAxisNeg = j->axisTable[axis][int(JoyDir::NEG)][kEmulationMode]; - Event::Type eventAxisPos = j->axisTable[axis][int(JoyDir::POS)][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); - else if(value < -Joystick::deadzone()) - myHandler.handleEvent(eventAxisNeg); - 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, false); - myHandler.handleEvent(eventAxisPos, false); - } - } - j->axisLastValue[axis] = value; - break; - } - } + myHandler.handleEvent(eventAxisAnalog, value); } - else if(myHandler.hasOverlay()) + else { - // 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; + // Otherwise, we know the event is digital + // Every axis event has two associated values, negative and positive + Event::Type eventAxisNeg = j->joyMap.get(kEmulationMode, button, JoyAxis(axis), JoyDir::NEG); + Event::Type eventAxisPos = j->joyMap.get(kEmulationMode, button, JoyAxis(axis), JoyDir::POS); + + if (value > Joystick::deadzone()) + myHandler.handleEvent(eventAxisPos); + else if (value < -Joystick::deadzone()) + myHandler.handleEvent(eventAxisNeg); 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(value != j->axisLastValue[axis]) - { - #ifdef GUI_SUPPORT - myHandler.overlay().handleJoyAxisEvent(stick, axis, value); - #endif - j->axisLastValue[axis] = value; + // 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, false); + myHandler.handleEvent(eventAxisPos, false); + } } + j->axisLastValue[axis] = value; } - break; // Regular joystick axis + } + 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; - // Since the various controller classes deal with Stelladaptor - // devices differently, we send the raw X and Y axis data directly, - // and let the controller handle it - // These events don't have to pass through handleEvent, since - // they can never be remapped - case PhysicalJoystick::JT_STELLADAPTOR_LEFT: - case PhysicalJoystick::JT_2600DAPTOR_LEFT: - if(axis < NUM_JOY_AXIS) - myEvent.set(SA_Axis[int(Controller::Jack::Left)][axis], value); - break; // axis on left controller (0) - case PhysicalJoystick::JT_STELLADAPTOR_RIGHT: - case PhysicalJoystick::JT_2600DAPTOR_RIGHT: - if(axis < NUM_JOY_AXIS) - myEvent.set(SA_Axis[int(Controller::Jack::Right)][axis], value); - break; // axis on right controller (1) - default: - break; + // Now filter out consecutive, similar values + // (only pass on the event if the state has changed) + if (value != j->axisLastValue[axis]) + { +#ifdef GUI_SUPPORT + cerr << "axis event" << endl; + myHandler.overlay().handleJoyAxisEvent(stick, axis, value, button); +#endif + j->axisLastValue[axis] = value; + } + } } } @@ -628,64 +668,23 @@ void PhysicalJoystickHandler::handleAxisEvent(int stick, int axis, int value) void PhysicalJoystickHandler::handleBtnEvent(int stick, int button, bool pressed) { const PhysicalJoystickPtr j = joy(stick); - if(!j) return; - // Stelladaptors handle buttons differently than regular joysticks - switch(j->type) + if (j) { - case PhysicalJoystick::JT_REGULAR: - // Handle buttons which switch eventhandler state - if(pressed && myHandler.changeStateByEvent(j->btnTable[button][kEmulationMode])) - return; + j->buttonLast[stick] = pressed ? button : JOY_CTRL_NONE; - // 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], pressed); - #ifdef GUI_SUPPORT - else if(myHandler.hasOverlay()) - myHandler.overlay().handleJoyBtnEvent(stick, button, pressed); - #endif - 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-PhysicalJoystick::JT_STELLADAPTOR_LEFT][button], pressed ? 1 : 0); - 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::Type::Keyboard: - if(button < NUM_KEY_BTN) - myEvent.set(SA_Key[j->type-PhysicalJoystick::JT_2600DAPTOR_LEFT][button], pressed ? 1 : 0); - break; - default: - if(button < NUM_JOY_BTN) myEvent.set(SA_Button[j->type-PhysicalJoystick::JT_2600DAPTOR_LEFT][button], pressed ? 1 : 0); - } - switch(myOSystem.console().rightController().type()) - { - case Controller::Type::Keyboard: - if(button < NUM_KEY_BTN) - myEvent.set(SA_Key[j->type-PhysicalJoystick::JT_2600DAPTOR_LEFT][button], pressed ? 1 : 0); - break; - default: - if(button < NUM_JOY_BTN) myEvent.set(SA_Button[j->type-PhysicalJoystick::JT_2600DAPTOR_LEFT][button], pressed ? 1 : 0); - } - } - break; // 2600DAPTOR button - default: - break; + // Handle buttons which switch eventhandler state + if (pressed && myHandler.changeStateByEvent(j->joyMap.get(kEmulationMode, button))) + return; + + // Determine which mode we're in, then send the event to the appropriate place + if (myHandler.state() == EventHandlerState::EMULATION) + myHandler.handleEvent(j->joyMap.get(kEmulationMode, button), pressed); +#ifdef GUI_SUPPORT + else if (myHandler.hasOverlay()) + myHandler.overlay().handleJoyBtnEvent(stick, button, pressed); +#endif } } @@ -695,35 +694,40 @@ void PhysicalJoystickHandler::handleHatEvent(int stick, int hat, int value) // Preprocess all hat events, converting to Stella JoyHat type // Generate multiple equivalent hat events representing combined direction // when we get a diagonal hat event - if(myHandler.state() == EventHandlerState::EMULATION) - { - const PhysicalJoystickPtr j = joy(stick); - if(!j) return; - myHandler.handleEvent(j->hatTable[hat][int(JoyHat::UP)][kEmulationMode], - value & EVENT_HATUP_M); - myHandler.handleEvent(j->hatTable[hat][int(JoyHat::RIGHT)][kEmulationMode], - value & EVENT_HATRIGHT_M); - myHandler.handleEvent(j->hatTable[hat][int(JoyHat::DOWN)][kEmulationMode], - value & EVENT_HATDOWN_M); - myHandler.handleEvent(j->hatTable[hat][int(JoyHat::LEFT)][kEmulationMode], - value & EVENT_HATLEFT_M); - } -#ifdef GUI_SUPPORT - else if(myHandler.hasOverlay()) + const PhysicalJoystickPtr j = joy(stick); + + if (j) { - if(value == EVENT_HATCENTER_M) - myHandler.overlay().handleJoyHatEvent(stick, hat, JoyHat::CENTER); - else + const int button = j->buttonLast[stick]; + + if (myHandler.state() == EventHandlerState::EMULATION) { - 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); + myHandler.handleEvent(j->joyMap.get(kEmulationMode, button, hat, JoyHat::UP), + value & EVENT_HATUP_M); + myHandler.handleEvent(j->joyMap.get(kEmulationMode, button, hat, JoyHat::RIGHT), + value & EVENT_HATRIGHT_M); + myHandler.handleEvent(j->joyMap.get(kEmulationMode, button, hat, JoyHat::DOWN), + value & EVENT_HATDOWN_M); + myHandler.handleEvent(j->joyMap.get(kEmulationMode, button, hat, JoyHat::LEFT), + value & EVENT_HATLEFT_M); + } +#ifdef GUI_SUPPORT + else if (myHandler.hasOverlay()) + { + if (value == EVENT_HATCENTER_M) + myHandler.overlay().handleJoyHatEvent(stick, hat, JoyHat::CENTER, button); + else + { + if (value & EVENT_HATUP_M) + myHandler.overlay().handleJoyHatEvent(stick, hat, JoyHat::UP, button); + if (value & EVENT_HATRIGHT_M) + myHandler.overlay().handleJoyHatEvent(stick, hat, JoyHat::RIGHT, button); + if (value & EVENT_HATDOWN_M) + myHandler.overlay().handleJoyHatEvent(stick, hat, JoyHat::DOWN, button); + if (value & EVENT_HATLEFT_M) + myHandler.overlay().handleJoyHatEvent(stick, hat, JoyHat::LEFT, button); + } } } #endif @@ -758,31 +762,134 @@ ostream& operator<<(ostream& os, const PhysicalJoystickHandler& jh) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Used by the Stelladaptor to send absolute axis values -const Event::Type PhysicalJoystickHandler::SA_Axis[NUM_PORTS][NUM_JOY_AXIS] = { - { Event::SALeftAxis0Value, Event::SALeftAxis1Value }, - { Event::SARightAxis0Value, Event::SARightAxis1Value } +PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftJoystickMapping = { + // Left joystick (assume buttons zero..two) + {Event::JoystickZeroFire, 0}, + {Event::JoystickZeroFire5, 1}, + {Event::JoystickZeroFire9, 2}, +#if defined(RETRON77) + // Left joystick (assume buttons two..four) + {Event::CmdMenuMode, 2), + {Event::OptionsMenuMode, 3), + {Event::ExitMode, 4), +#endif + // Left joystick left/right directions + {Event::JoystickZeroLeft, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG}, + {Event::JoystickZeroRight, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS}, + // Left joystick up/down directions + {Event::JoystickZeroUp, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG}, + {Event::JoystickZeroDown, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS}, + // Left joystick left/right directions (assume hat 0) + {Event::JoystickZeroLeft, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHat::LEFT}, + {Event::JoystickZeroRight, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHat::RIGHT}, + // Left joystick up/down directions (assume hat 0) + {Event::JoystickZeroUp, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHat::UP}, + {Event::JoystickZeroDown, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHat::DOWN}, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// 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[NUM_PORTS][NUM_JOY_BTN] = { - { Event::JoystickZeroFire, Event::JoystickZeroFire9, - Event::JoystickZeroFire5, Event::JoystickZeroFire9 }, - { Event::JoystickOneFire, Event::JoystickOneFire9, - Event::JoystickOneFire5, Event::JoystickOneFire9 } +PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRightJoystickMapping = { + // Right joystick (assume buttons zero..two) + {Event::JoystickOneFire, 0}, + {Event::JoystickOneFire5, 1}, + {Event::JoystickOneFire9, 2}, +#if defined(RETRON77) + // Right joystick (assume buttons two..eight) + {Event::CmdMenuMode, 2}, + {Event::OptionsMenuMode, 3}, + {Event::ExitMode, 4}, + {Event::RewindPause, 5}, + {Event::ConsoleSelect, 7}, + {Event::ConsoleReset, 8}, +#endif + // Right joystick left/right directions + {Event::JoystickOneLeft, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG}, + {Event::JoystickOneRight, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS}, + // Right joystick up/down directions + {Event::JoystickOneUp, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG}, + {Event::JoystickOneDown, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS}, + // Right joystick left/right directions (assume hat 0) + {Event::JoystickOneLeft, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHat::LEFT}, + {Event::JoystickOneRight, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHat::RIGHT}, + // Right joystick up/down directions (assume hat 0) + {Event::JoystickOneUp, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHat::UP}, + {Event::JoystickOneDown, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHat::DOWN}, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Used by the 2600-daptor to map button presses to keypad keys -const Event::Type PhysicalJoystickHandler::SA_Key[NUM_PORTS][NUM_KEY_BTN] = { - { 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 } +PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftPaddlesMapping = { + {Event::PaddleZeroAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG}, + {Event::PaddleZeroDecrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS}, + {Event::PaddleZeroIncrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG}, + {Event::PaddleZeroFire, 0}, + {Event::PaddleOneAnalog, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::ANALOG}, + {Event::PaddleOneDecrease, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS}, + {Event::PaddleOneIncrease, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG}, + {Event::PaddleOneFire, 1}, +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRightPaddlesMapping = { + {Event::PaddleTwoAnalog, JOY_CTRL_NONE, JoyAxis::Z, JoyDir::ANALOG}, + {Event::PaddleTwoDecrease, JOY_CTRL_NONE, JoyAxis::Z, JoyDir::POS}, + {Event::PaddleTwoIncrease, JOY_CTRL_NONE, JoyAxis::Z, JoyDir::NEG}, + {Event::PaddleTwoFire, 2}, + {Event::PaddleThreeAnalog, JOY_CTRL_NONE, JoyAxis(3), JoyDir::ANALOG}, + {Event::PaddleThreeDecrease,JOY_CTRL_NONE, JoyAxis(3), JoyDir::POS}, + {Event::PaddleThreeIncrease,JOY_CTRL_NONE, JoyAxis(3), JoyDir::NEG}, + {Event::PaddleThreeFire, 3}, +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftKeypadMapping = { + {Event::KeyboardZero1, 0}, + {Event::KeyboardZero2, 1}, + {Event::KeyboardZero3, 2}, + {Event::KeyboardZero4, 3}, + {Event::KeyboardZero5, 4}, + {Event::KeyboardZero6, 5}, + {Event::KeyboardZero7, 6}, + {Event::KeyboardZero8, 7}, + {Event::KeyboardZero9, 8}, + {Event::KeyboardZeroStar, 9}, + {Event::KeyboardZero0, 10}, + {Event::KeyboardZeroPound, 11}, +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRightKeypadMapping = { + {Event::KeyboardOne1, 0}, + {Event::KeyboardOne2, 1}, + {Event::KeyboardOne3, 2}, + {Event::KeyboardOne4, 3}, + {Event::KeyboardOne5, 4}, + {Event::KeyboardOne6, 5}, + {Event::KeyboardOne7, 6}, + {Event::KeyboardOne8, 7}, + {Event::KeyboardOne9, 8}, + {Event::KeyboardOneStar, 9}, + {Event::KeyboardOne0, 10}, + {Event::KeyboardOnePound, 11}, +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultMenuMapping = { + // valid for all joysticks + {Event::UISelect, 0}, + {Event::UIOK, 1}, + {Event::UITabNext, 2}, + {Event::UITabPrev, 3}, + {Event::UICancel, 5}, + + {Event::UINavPrev, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG}, + {Event::UITabPrev, 0, JoyAxis::X, JoyDir::NEG}, + {Event::UINavNext, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS}, + {Event::UITabNext, 0, JoyAxis::X, JoyDir::POS}, + {Event::UIUp, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG}, + {Event::UIDown, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS}, + + {Event::UINavPrev, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHat::LEFT}, + {Event::UINavNext, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHat::RIGHT}, + {Event::UIUp, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHat::UP}, + {Event::UIDown, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHat::DOWN}, }; diff --git a/src/common/PJoystickHandler.hxx b/src/common/PJoystickHandler.hxx index a300fdddf..6f48cbe76 100644 --- a/src/common/PJoystickHandler.hxx +++ b/src/common/PJoystickHandler.hxx @@ -41,7 +41,7 @@ using PhysicalJoystickPtr = shared_ptr; Essentially, this class is an extension of the EventHandler class, but handling only joystick-specific functionality. - @author Stephen Anthony + @author Stephen Anthony, Thomas Jentzsch */ class PhysicalJoystickHandler { @@ -69,32 +69,38 @@ class PhysicalJoystickHandler bool remove(const string& name); void mapStelladaptors(const string& saport); void setDefaultMapping(Event::Type type, EventMode mode); + + /** define mappings for current controllers */ + void defineControllerMappings(const string& controllerName, Controller::Jack port); + /** enable mappings for emulation mode */ + void enableEmulationMappings(); + 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); + bool addJoyMapping(Event::Type event, EventMode mode, int stick, + int button, JoyAxis axis, int value); + bool addJoyHatMapping(Event::Type event, EventMode mode, int stick, + int button, int hat, JoyHat hdir); /** Handle a physical joystick event. */ void handleAxisEvent(int stick, int axis, int value); void handleBtnEvent(int stick, int button, bool pressed); void handleHatEvent(int stick, int hat, int value); - Event::Type eventForAxis(int stick, int axis, int joyDir, EventMode mode) const { + Event::Type eventForAxis(EventMode mode, int stick, int axis, int value, int button) const { const PhysicalJoystickPtr j = joy(stick); - return (j && joyDir != int(JoyDir::NEG)) - ? j->axisTable[axis][(joyDir > int(JoyDir::NEG))][mode] : Event::NoType; + return j->joyMap.get(mode, button, JoyAxis(axis), convertAxisValue(value)); } - Event::Type eventForButton(int stick, int button, EventMode mode) const { + Event::Type eventForButton(EventMode mode, int stick, int button) const { const PhysicalJoystickPtr j = joy(stick); - return j ? j->btnTable[button][mode] : Event::NoType; + return j->joyMap.get(mode, button); } - Event::Type eventForHat(int stick, int hat, JoyHat hatDir, EventMode mode) const { + Event::Type eventForHat(EventMode mode, int stick, int hat, JoyHat hatDir, int button) const { const PhysicalJoystickPtr j = joy(stick); - return j ? j->hatTable[hat][int(hatDir)][mode] : Event::NoType; + return j->joyMap.get(mode, button, hat, hatDir); } /** Returns a list of pairs consisting of joystick name and associated ID. */ @@ -122,17 +128,56 @@ class PhysicalJoystickHandler } // Set default mapping for given joystick when no mappings already exist - void setStickDefaultMapping(int stick, Event::Type type, EventMode mode); + void setStickDefaultMapping(int stick, Event::Type type, EventMode mode, + bool updateDefaults = false); friend ostream& operator<<(ostream& os, const PhysicalJoystickHandler& jh); - // Static lookup tables for Stelladaptor/2600-daptor axis/button support - static const int NUM_JOY_BTN = 4; - static const int NUM_KEY_BTN = 12; + JoyDir convertAxisValue(int value) const { + return value == int(JoyDir::NONE) ? JoyDir::NONE : value > 0 ? JoyDir::POS : JoyDir::NEG; + } - static const Event::Type SA_Axis[NUM_PORTS][NUM_JOY_AXIS]; - static const Event::Type SA_Button[NUM_PORTS][NUM_JOY_BTN]; - static const Event::Type SA_Key[NUM_PORTS][NUM_KEY_BTN]; + // Structures used for action menu items + struct EventMapping { + Event::Type event; + int button; + JoyAxis axis = JoyAxis::NONE; + JoyDir adir = JoyDir::NONE; + int hat = JOY_CTRL_NONE; + JoyHat hdir = JoyHat::CENTER; + }; + using EventMappingArray = std::vector; + + void setDefaultAction(const PhysicalJoystickPtr& j, + EventMapping map, Event::Type event = Event::NoType, + EventMode mode = kEmulationMode, bool updateDefaults = false); + + /** returns the event's controller mode */ + EventMode getEventMode(const Event::Type event, const EventMode mode) const; + /** Checks event type. */ + bool isJoystickEvent(const Event::Type event) const; + bool isPaddleEvent(const Event::Type event) const; + bool isKeypadEvent(const Event::Type event) const; + bool isCommonEvent(const Event::Type event) const; + + void enableCommonMappings(); + + void enableMappings(const Event::EventSet events, EventMode mode); + void enableMapping(const Event::Type event, EventMode mode); + + private: + EventMode myLeftMode; + EventMode myRightMode; + + // Controller menu and common emulation mappings + static EventMappingArray DefaultMenuMapping; + // Controller specific mappings + static EventMappingArray DefaultLeftJoystickMapping; + static EventMappingArray DefaultRightJoystickMapping; + static EventMappingArray DefaultLeftPaddlesMapping; + static EventMappingArray DefaultRightPaddlesMapping; + static EventMappingArray DefaultLeftKeypadMapping; + static EventMappingArray DefaultRightKeypadMapping; }; #endif diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 317758caa..6b66e6451 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -26,7 +26,6 @@ #include "PNGLibrary.hxx" #include "PKeyboardHandler.hxx" - #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #endif @@ -94,7 +93,7 @@ void PhysicalKeyboardHandler::setDefaultKey(EventMapping map, Event::Type event, } else if (eraseAll || map.event == event) { - myKeyMap.eraseEvent(map.event, mode); + //myKeyMap.eraseEvent(map.event, mode); myKeyMap.add(map.event, mode, map.key, map.mod); } } @@ -107,6 +106,12 @@ void PhysicalKeyboardHandler::setDefaultKey(EventMapping map, Event::Type event, void PhysicalKeyboardHandler::setDefaultMapping(Event::Type event, EventMode mode, bool updateDefaults) { + if (!updateDefaults) + { + myKeyMap.eraseEvent(event, mode); + myKeyMap.eraseEvent(event, getEventMode(event, mode)); + } + switch(mode) { case kEmulationMode: @@ -186,7 +191,6 @@ void PhysicalKeyboardHandler::enableEmulationMappings() // see below break; - default: enableMappings(RightJoystickEvents, kJoystickMode); break; @@ -226,7 +230,7 @@ void PhysicalKeyboardHandler::enableCommonMappings() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PhysicalKeyboardHandler::enableMappings(const EventSet events, EventMode mode) +void PhysicalKeyboardHandler::enableMappings(const Event::EventSet events, EventMode mode) { for (const auto& event : events) enableMapping(event, mode); @@ -236,7 +240,7 @@ void PhysicalKeyboardHandler::enableMappings(const EventSet events, EventMode mo void PhysicalKeyboardHandler::enableMapping(const Event::Type event, EventMode mode) { // copy from controller mode into emulation mode - std::vector mappings = myKeyMap.getEventMapping(event, mode); + KeyMap::MappingArray mappings = myKeyMap.getEventMapping(event, mode); for (const auto& mapping : mappings) myKeyMap.add(event, kEmulationMode, mapping.key, mapping.mod); @@ -387,46 +391,6 @@ void PhysicalKeyboardHandler::handleEvent(StellaKey key, StellaMod mod, bool pre } } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -EventSet PhysicalKeyboardHandler::LeftJoystickEvents = { - Event::JoystickZeroUp, Event::JoystickZeroDown, Event::JoystickZeroLeft, Event::JoystickZeroRight, - Event::JoystickZeroFire, Event::JoystickZeroFire5, Event::JoystickZeroFire9, -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -EventSet PhysicalKeyboardHandler::RightJoystickEvents = { - Event::JoystickOneUp, Event::JoystickOneDown, Event::JoystickOneLeft, Event::JoystickOneRight, - Event::JoystickOneFire, Event::JoystickOneFire5, Event::JoystickOneFire9 -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -EventSet PhysicalKeyboardHandler::LeftPaddlesEvents = { - Event::PaddleZeroDecrease, Event::PaddleZeroIncrease, Event::PaddleZeroAnalog, Event::PaddleZeroFire, - Event::PaddleOneDecrease, Event::PaddleOneIncrease, Event::PaddleOneAnalog, Event::PaddleOneFire, -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -EventSet PhysicalKeyboardHandler::RightPaddlesEvents = { - Event::PaddleTwoDecrease, Event::PaddleTwoIncrease, Event::PaddleTwoAnalog, Event::PaddleTwoFire, - Event::PaddleThreeDecrease, Event::PaddleThreeIncrease, Event::PaddleThreeAnalog, Event::PaddleThreeFire, -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -EventSet PhysicalKeyboardHandler::LeftKeypadEvents = { - Event::KeyboardZero1, Event::KeyboardZero2, Event::KeyboardZero3, - Event::KeyboardZero4, Event::KeyboardZero5, Event::KeyboardZero6, - Event::KeyboardZero7, Event::KeyboardZero8, Event::KeyboardZero9, - Event::KeyboardZeroStar, Event::KeyboardZero0, Event::KeyboardZeroPound, -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -EventSet PhysicalKeyboardHandler::RightKeypadEvents = { - Event::KeyboardOne1, Event::KeyboardOne2, Event::KeyboardOne3, - Event::KeyboardOne4, Event::KeyboardOne5, Event::KeyboardOne6, - Event::KeyboardOne7, Event::KeyboardOne8, Event::KeyboardOne9, - Event::KeyboardOneStar, Event::KeyboardOne0, Event::KeyboardOnePound, -}; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommonMapping = { {Event::ConsoleSelect, KBDK_F1}, @@ -544,6 +508,7 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultMenuM {Event::UIPgDown, KBDK_PAGEDOWN}, {Event::UISelect, KBDK_RETURN}, + {Event::UISelect, KBDK_KP_ENTER}, {Event::UICancel, KBDK_ESCAPE}, {Event::UINavPrev, KBDK_TAB, KBDM_SHIFT}, @@ -579,11 +544,17 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultJoyst {Event::JoystickZeroDown, KBDK_DOWN}, {Event::JoystickZeroLeft, KBDK_LEFT}, {Event::JoystickZeroRight, KBDK_RIGHT}, + {Event::JoystickZeroUp, KBDK_KP_8}, + {Event::JoystickZeroDown, KBDK_KP_2}, + {Event::JoystickZeroLeft, KBDK_KP_4}, + {Event::JoystickZeroRight, KBDK_KP_6}, {Event::JoystickZeroFire, KBDK_SPACE}, {Event::JoystickZeroFire, KBDK_LCTRL}, + {Event::JoystickZeroFire, KBDK_KP_5}, {Event::JoystickZeroFire5, KBDK_4}, + {Event::JoystickZeroFire5, KBDK_KP_9}, {Event::JoystickZeroFire9, KBDK_5}, - + {Event::JoystickZeroFire9, KBDK_KP_3}, {Event::JoystickOneUp, KBDK_Y}, {Event::JoystickOneDown, KBDK_H}, {Event::JoystickOneLeft, KBDK_G}, @@ -641,7 +612,6 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultKeypa {Event::KeyboardOnePound, KBDK_SLASH}, }; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::CompuMateMapping = { {Event::CompuMateShift, KBDK_LSHIFT}, diff --git a/src/common/PKeyboardHandler.hxx b/src/common/PKeyboardHandler.hxx index ffe869d21..fa7f135b2 100644 --- a/src/common/PKeyboardHandler.hxx +++ b/src/common/PKeyboardHandler.hxx @@ -19,7 +19,6 @@ #define PHYSICAL_KEYBOARD_HANDLER_HXX #include -#include class OSystem; class EventHandler; @@ -29,8 +28,6 @@ class EventHandler; #include "EventHandlerConstants.hxx" #include "KeyMap.hxx" -using EventSet = std::set; - /** This class handles all physical keyboard-related operations in Stella. @@ -40,7 +37,7 @@ using EventSet = std::set; Essentially, this class is an extension of the EventHandler class, but handling only keyboard-specific functionality. - @author Stephen Anthony + @author Stephen Anthony, Thomas Jentzsch */ class PhysicalKeyboardHandler { @@ -103,7 +100,7 @@ class PhysicalKeyboardHandler void enableCommonMappings(); - void enableMappings(const EventSet events, EventMode mode); + void enableMappings(const Event::EventSet events, EventMode mode); void enableMapping(const Event::Type event, EventMode mode); OSystem& myOSystem; @@ -130,16 +127,10 @@ class PhysicalKeyboardHandler uInt8 myAltKeyCounter; #endif - // Hold controller related events - static EventSet LeftJoystickEvents; - static EventSet RightJoystickEvents; - static EventSet LeftPaddlesEvents; - static EventSet RightPaddlesEvents; - static EventSet LeftKeypadEvents; - static EventSet RightKeypadEvents; - + // Controller menu and common emulation mappings static EventMappingArray DefaultMenuMapping; static EventMappingArray DefaultCommonMapping; + // Controller specific mappings static EventMappingArray DefaultJoystickMapping; static EventMappingArray DefaultPaddleMapping; static EventMappingArray DefaultKeypadMapping; diff --git a/src/common/PhysicalJoystick.cxx b/src/common/PhysicalJoystick.cxx index f4e84a002..f861adf00 100644 --- a/src/common/PhysicalJoystick.cxx +++ b/src/common/PhysicalJoystick.cxx @@ -31,20 +31,16 @@ PhysicalJoystick::PhysicalJoystick() numAxes(0), numButtons(0), numHats(0), - axisTable(nullptr), - btnTable(nullptr), - hatTable(nullptr), - axisLastValue(nullptr) + axisLastValue(nullptr), + buttonLast(nullptr) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PhysicalJoystick::~PhysicalJoystick() { - delete[] axisTable; - delete[] btnTable; - delete[] hatTable; delete[] axisLastValue; + delete[] buttonLast; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -59,109 +55,66 @@ void PhysicalJoystick::initialize(int index, const string& desc, numAxes = axes; numButtons = buttons; numHats = hats; - if(numAxes) - axisTable = new Event::Type[numAxes][NUM_JOY_DIRS][kNumModes]; - if(numButtons) - btnTable = new Event::Type[numButtons][kNumModes]; - if(numHats) - hatTable = new Event::Type[numHats][NUM_JOY_HAT_DIRS][kNumModes]; axisLastValue = new int[numAxes]; + buttonLast = new int[numButtons]; - // Erase the joystick axis mapping array and last axis value + // Erase the last button + for (int b = 0; b < numButtons; ++b) + buttonLast[b] = JOY_CTRL_NONE; + + // Erase the last axis value for(int a = 0; a < numAxes; ++a) - { axisLastValue[a] = 0; - for(int m = 0; m < kNumModes; ++m) - for (int d = 0; d < NUM_JOY_DIRS; ++d) - axisTable[a][d][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 mappings + eraseMap(kJoystickMode); + eraseMap(kPaddlesMode); + eraseMap(kKeypadMode); + eraseMap(kMenuMode); - // Erase the joystick hat mapping array - for(int h = 0; h < numHats; ++h) - for(int m = 0; m < kNumModes; ++m) - for (int d = 0; d < NUM_JOY_HAT_DIRS; ++d) - hatTable[h][d][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 d = 0; d < NUM_JOY_DIRS; ++d) - joybuf << " " << axisTable[a][d][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 d = 0; d < NUM_JOY_HAT_DIRS; ++d) - joybuf << " " << hatTable[h][d][m]; + // '$'['|'(':'