From 529c1fe7de0eaad0682a58665b5a68045310ca3b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 21 Jun 2019 10:35:45 +0200 Subject: [PATCH] refactor into two separate maps for stick and hats --- src/common/ControllerMap.hxx | 129 ------------ src/common/JoyHatMap.cxx | 200 +++++++++++++++++++ src/common/JoyHatMap.hxx | 109 ++++++++++ src/common/{ControllerMap.cxx => JoyMap.cxx} | 93 ++++----- src/common/JoyMap.hxx | 121 +++++++++++ src/common/PJoystickHandler.cxx | 17 +- src/common/PJoystickHandler.hxx | 12 +- src/common/PhysicalJoystick.hxx | 6 + src/common/module.mk | 3 +- src/windows/Stella.vcxproj | 6 +- src/windows/Stella.vcxproj.filters | 10 +- 11 files changed, 509 insertions(+), 197 deletions(-) delete mode 100644 src/common/ControllerMap.hxx create mode 100644 src/common/JoyHatMap.cxx create mode 100644 src/common/JoyHatMap.hxx rename src/common/{ControllerMap.cxx => JoyMap.cxx} (57%) create mode 100644 src/common/JoyMap.hxx diff --git a/src/common/ControllerMap.hxx b/src/common/ControllerMap.hxx deleted file mode 100644 index 1afe6011a..000000000 --- a/src/common/ControllerMap.hxx +++ /dev/null @@ -1,129 +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-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 ControllerMap -{ - public: - - struct ControllerMapping - { - EventMode mode; - int stick; // stick number - 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) - - ControllerMapping() - : mode(EventMode(0)), stick(0), button(0), - axis(JoyAxis(0)), adir(JoyDir(0)), hat(0), hdir(JoyHat(0)) { } - ControllerMapping(const ControllerMapping& m) - : mode(m.mode), stick(m.stick), button(m.button), - axis(m.axis), adir(m.adir), hat(m.hat), hdir(m.hdir) { } - explicit ControllerMapping(EventMode c_mode, int c_stick, int c_button, - JoyAxis c_axis, JoyDir c_adir, int c_hat, JoyHat c_hdir) - : mode(c_mode), stick(c_stick), button(c_button), - axis(c_axis), adir(c_adir), hat(c_hat), hdir(c_hdir) { } - - bool operator==(const ControllerMapping& other) const - { - return (mode == other.mode - && stick == other.stick - && button == other.button - && axis == other.axis - && adir == other.adir - && hat == other.hat - && hdir == other.hdir - ); - } - }; - using ControllerMappingArray = std::vector; - - ControllerMap(); - virtual ~ControllerMap() = default; - - /** Add new mapping for given event */ - void add(const Event::Type event, const ControllerMapping& mapping); - void add(const Event::Type event, const EventMode mode, const int stick, const int button, - const JoyAxis axis, const JoyDir adir, const int hat, const JoyHat hdir); - - /** Erase mapping */ - void erase(const ControllerMapping& mapping); - void erase(const EventMode mode, const int stick, const int button, - const JoyAxis axis, const JoyDir adir, const int hat, const JoyHat hdir); - - /** Get event for mapping */ - Event::Type get(const ControllerMapping& mapping) const; - Event::Type get(const EventMode mode, const int stick, const int button, - const JoyAxis axis, const JoyDir adir, const int hat, const JoyHat hdir) const; - - /** Check if a mapping exists */ - bool check(const ControllerMapping& mapping) const; - bool check(const EventMode mode, const int stick, const int button, - const JoyAxis axis, const JoyDir adir, const int hat, const JoyHat hdir) const; - - /** Get mapping description */ - string getDesc(const Event::Type event, const ControllerMapping& mapping) const; - string getDesc(const Event::Type event, const EventMode mode, const int stick, const int button, - const JoyAxis axis, const JoyDir adir, const int hat, const JoyHat hdir) const; - - /** Get the mapping description(s) for given event and mode */ - string getEventMappingDesc(const Event::Type event, const EventMode mode) const; - - ControllerMappingArray 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: - struct ControllerHash { - size_t operator()(const ControllerMapping& m)const { - return std::hash()((uInt64(m.mode)) // 3 bit - ^ ((uInt64(m.stick)) << 3) // 2 bits - ^ ((uInt64(m.button)) << 5) // 2 bits - ^ ((uInt64(m.axis)) << 7) // 1 bit - ^ ((uInt64(m.adir)) << 8) // 1 bit - ^ ((uInt64(m.hat)) << 9) // 1 bit - ^ ((uInt64(m.hdir)) << 10)); // 2 bits - } - }; - - std::unordered_map myMap; -}; - -#endif diff --git a/src/common/JoyHatMap.cxx b/src/common/JoyHatMap.cxx new file mode 100644 index 000000000..ea6480dc9 --- /dev/null +++ b/src/common/JoyHatMap.cxx @@ -0,0 +1,200 @@ +//============================================================================ +// +// 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 "JoyHatMap.hxx" + +// TODOs +// - two maps per controller (joydirs, hatdirs) +// - both maps combined with buttons +// - directions can work alone and with a button combination +// - buttons can work without a direction (mapped in joydir) + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +JoyHatMap::JoyHatMap(void) +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoyHatMap::add(const Event::Type event, const JoyHatMapping& mapping) +{ + myMap[mapping] = event; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoyHatMap::add(const Event::Type event, const EventMode mode, const int hat, const JoyHat hdir) +{ + add(event, JoyHatMapping(mode, hat, hdir)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoyHatMap::erase(const JoyHatMapping& mapping) +{ + myMap.erase(mapping); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoyHatMap::erase(const EventMode mode, const int hat, const JoyHat hdir) +{ + erase(JoyHatMapping(mode, hat, hdir)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Event::Type JoyHatMap::get(const JoyHatMapping& mapping) const +{ + auto find = myMap.find(mapping); + if (find != myMap.end()) + return find->second; + + return Event::Type::NoType; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Event::Type JoyHatMap::get(const EventMode mode, const int hat, const JoyHat hdir) const +{ + return get(JoyHatMapping(mode, hat, hdir)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool JoyHatMap::check(const JoyHatMapping & mapping) const +{ + auto find = myMap.find(mapping); + + return (find != myMap.end()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool JoyHatMap::check(const EventMode mode, const int hat, const JoyHat hdir) const +{ + return check(JoyHatMapping(mode, hat, hdir)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string JoyHatMap::getDesc(const Event::Type event, const JoyHatMapping & mapping) const +{ + ostringstream buf; + + //buf << "J" << mapping.stick; + + // hat description + if (mapping.hat != 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 JoyHatMap::getDesc(const Event::Type event, const EventMode mode, const int hat, const JoyHat hdir) const +{ + return getDesc(event, JoyHatMapping(mode, hat, hdir)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string JoyHatMap::getEventMappingDesc(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 << getDesc(event, item.first); + } + } + return buf.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +JoyHatMap::JoyHatMappingArray JoyHatMap::getEventMapping(const Event::Type event, const EventMode mode) const +{ + JoyHatMappingArray map; + + for (auto item : myMap) + if (item.second == event && item.first.mode == mode) + map.push_back(item.first); + + return map; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string JoyHatMap::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.stick*/ << "," << + item.first.hat << "," << int(item.first.hdir); + } + } + return buf.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int JoyHatMap::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, stick, hat, hdir, i = 0; + + while (buf >> event && buf >> stick && buf >> hat && buf >> hdir && ++i) + add(Event::Type(event), EventMode(mode), hat, JoyHat(hdir)); + + return i; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void JoyHatMap::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 JoyHatMap::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/JoyHatMap.hxx b/src/common/JoyHatMap.hxx new file mode 100644 index 000000000..bbee81baa --- /dev/null +++ b/src/common/JoyHatMap.hxx @@ -0,0 +1,109 @@ +//============================================================================ +// +// 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 JOYHATMAP_HXX +#define JOYHATMAP_HXX + +#include +#include "Event.hxx" +#include "EventHandlerConstants.hxx" + +/** + This class handles controller mappings in Stella. + + @author Thomas Jentzsch +*/ +class JoyHatMap +{ +public: + + struct JoyHatMapping + { + EventMode mode; + int hat; // hat number + JoyHat hdir; // hat direction (left/right/up/down) + + JoyHatMapping() + : mode(EventMode(0)), hat(0), hdir(JoyHat(0)) { } + JoyHatMapping(const JoyHatMapping& m) + : mode(m.mode), hat(m.hat), hdir(m.hdir) { } + explicit JoyHatMapping(EventMode c_mode, int c_hat, JoyHat c_hdir) + : mode(c_mode), hat(c_hat), hdir(c_hdir) { } + + bool operator==(const JoyHatMapping& other) const + { + return (mode == other.mode + && hat == other.hat + && hdir == other.hdir + ); + } + }; + using JoyHatMappingArray = std::vector; + + JoyHatMap(); + virtual ~JoyHatMap() = default; + + /** Add new mapping for given event */ + void add(const Event::Type event, const JoyHatMapping& mapping); + void add(const Event::Type event, const EventMode mode, const int hat, const JoyHat hdir); + + /** Erase mapping */ + void erase(const JoyHatMapping& mapping); + void erase(const EventMode mode, const int hat, const JoyHat hdir); + + /** Get event for mapping */ + Event::Type get(const JoyHatMapping& mapping) const; + Event::Type get(const EventMode mode, const int hat, const JoyHat hdir) const; + + /** Check if a mapping exists */ + bool check(const JoyHatMapping& mapping) const; + bool check(const EventMode mode, const int hat, const JoyHat hdir) const; + + /** Get mapping description */ + string getDesc(const Event::Type event, const JoyHatMapping& mapping) const; + string getDesc(const Event::Type event, const EventMode mode, const int hat, const JoyHat hdir) const; + + /** Get the mapping description(s) for given event and mode */ + string getEventMappingDesc(const Event::Type event, const EventMode mode) const; + + JoyHatMappingArray 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: + struct JoyHatHash { + size_t operator()(const JoyHatMapping& m)const { + return std::hash()((uInt64(m.mode)) // 3 bit + ^ ((uInt64(m.hat)) << 3) // 1 bit + ^ ((uInt64(m.hdir)) << 4) // 2 bits + ); + } + }; + + std::unordered_map myMap; +}; + +#endif diff --git a/src/common/ControllerMap.cxx b/src/common/JoyMap.cxx similarity index 57% rename from src/common/ControllerMap.cxx rename to src/common/JoyMap.cxx index fca8511d4..48754aa98 100644 --- a/src/common/ControllerMap.cxx +++ b/src/common/JoyMap.cxx @@ -15,41 +15,47 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "ControllerMap.hxx" +#include "JoyMap.hxx" + +// TODOs +// - two maps per controller (joydirs, hatdirs) +// - both maps combined with buttons +// - directions can work alone and with a button combination +// - buttons can work without a direction (mapped in joydir) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -ControllerMap::ControllerMap(void) +JoyMap::JoyMap(void) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ControllerMap::add(const Event::Type event, const ControllerMapping& mapping) +void JoyMap::add(const Event::Type event, const JoyMapping& mapping) { myMap[mapping] = event; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ControllerMap::add(const Event::Type event, const EventMode mode, const int stick, const int button, - const JoyAxis axis, const JoyDir adir, const int hat, const JoyHat hdir) +void JoyMap::add(const Event::Type event, const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir) { - add(event, ControllerMapping(mode, stick, button, axis, adir, hat, hdir)); + add(event, JoyMapping(mode, button, axis, adir)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ControllerMap::erase(const ControllerMapping& mapping) +void JoyMap::erase(const JoyMapping& mapping) { myMap.erase(mapping); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ControllerMap::erase(const EventMode mode, const int stick, const int button, - const JoyAxis axis, const JoyDir adir, const int hat, const JoyHat hdir) +void JoyMap::erase(const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir) { - erase(ControllerMapping(mode, stick, button, axis, adir, hat, hdir)); + erase(JoyMapping(mode, button, axis, adir)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Event::Type ControllerMap::get(const ControllerMapping& mapping) const +Event::Type JoyMap::get(const JoyMapping& mapping) const { auto find = myMap.find(mapping); if (find != myMap.end()) @@ -59,14 +65,14 @@ Event::Type ControllerMap::get(const ControllerMapping& mapping) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Event::Type ControllerMap::get(const EventMode mode, const int stick, const int button, - const JoyAxis axis, const JoyDir adir, const int hat, const JoyHat hdir) const +Event::Type JoyMap::get(const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir) const { - return get(ControllerMapping(mode, stick, button, axis, adir, hat, hdir)); + return get(JoyMapping(mode, button, axis, adir)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ControllerMap::check(const ControllerMapping & mapping) const +bool JoyMap::check(const JoyMapping & mapping) const { auto find = myMap.find(mapping); @@ -74,18 +80,18 @@ bool ControllerMap::check(const ControllerMapping & mapping) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ControllerMap::check(const EventMode mode, const int stick, const int button, - const JoyAxis axis, const JoyDir adir, const int hat, const JoyHat hdir) const +bool JoyMap::check(const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir) const { - return check(ControllerMapping(mode, stick, button, axis, adir, hat, hdir)); + return check(JoyMapping(mode, button, axis, adir)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string ControllerMap::getDesc(const Event::Type event, const ControllerMapping& mapping) const +string JoyMap::getDesc(const Event::Type event, const JoyMapping& mapping) const { ostringstream buf; - buf << "J" << mapping.stick; + //buf << "J" << mapping.stick; // button description if (mapping.button != CTRL_NONE) @@ -94,7 +100,7 @@ string ControllerMap::getDesc(const Event::Type event, const ControllerMapping& // axis description if (int(mapping.axis) != CTRL_NONE) { - buf << "/A" << mapping.hat; + buf << "/A"; switch (mapping.axis) { case JoyAxis::X: buf << "X"; break; @@ -110,33 +116,18 @@ string ControllerMap::getDesc(const Event::Type event, const ControllerMapping& buf << "+"; } - // hat description - if (mapping.hat != 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 ControllerMap::getDesc(const Event::Type event, const EventMode mode, const int stick, const int button, - const JoyAxis axis, const JoyDir adir, const int hat, const JoyHat hdir) const +string JoyMap::getDesc(const Event::Type event, const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir) const { - return getDesc(event, ControllerMapping(mode, stick, button, axis, adir, hat, hdir)); + return getDesc(event, JoyMapping(mode, button, axis, adir)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string ControllerMap::getEventMappingDesc(const Event::Type event, const EventMode mode) const +string JoyMap::getEventMappingDesc(const Event::Type event, const EventMode mode) const { ostringstream buf; @@ -153,9 +144,9 @@ string ControllerMap::getEventMappingDesc(const Event::Type event, const EventMo } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -ControllerMap::ControllerMappingArray ControllerMap::getEventMapping(const Event::Type event, const EventMode mode) const +JoyMap::JoyMappingArray JoyMap::getEventMapping(const Event::Type event, const EventMode mode) const { - ControllerMappingArray map; + JoyMappingArray map; for (auto item : myMap) if (item.second == event && item.first.mode == mode) @@ -165,7 +156,7 @@ ControllerMap::ControllerMappingArray ControllerMap::getEventMapping(const Event } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string ControllerMap::saveMapping(const EventMode mode) const +string JoyMap::saveMapping(const EventMode mode) const { ostringstream buf; @@ -175,15 +166,15 @@ string ControllerMap::saveMapping(const EventMode mode) const { if (buf.str() != "") buf << "|"; - buf << item.second << ":" << item.first.stick << "," << item.first.button << "," - << int(item.first.axis) << "," << int(item.first.adir) << "," << item.first.hat << "," << int(item.first.hdir); + buf << item.second << ":" /*<< item.first.stick*/ << "," << item.first.button << "," + << int(item.first.axis) << "," << int(item.first.adir); } } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int ControllerMap::loadMapping(string& list, const EventMode mode) +int JoyMap::loadMapping(string& list, const EventMode mode) { // Since istringstream swallows whitespace, we have to make the // delimiters be spaces @@ -191,17 +182,17 @@ int ControllerMap::loadMapping(string& list, const EventMode mode) std::replace(list.begin(), list.end(), ':', ' '); std::replace(list.begin(), list.end(), ',', ' '); istringstream buf(list); - int event, stick, button, axis, adir, hat, hdir, i = 0; + int event, stick, button, axis, adir, i = 0; while (buf >> event && buf >> stick && buf >> button - && buf >> axis && buf >> adir && buf >> hat && buf >> hdir && ++i) - add(Event::Type(event), EventMode(mode), stick, button, JoyAxis(axis), JoyDir(adir), hat, JoyHat(hdir)); + && buf >> axis && buf >> adir && ++i) + add(Event::Type(event), EventMode(mode), button, JoyAxis(axis), JoyDir(adir)); return i; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ControllerMap::eraseMode(const EventMode mode) +void JoyMap::eraseMode(const EventMode mode) { for (auto item = myMap.begin(); item != myMap.end();) if (item->first.mode == mode) { @@ -212,7 +203,7 @@ void ControllerMap::eraseMode(const EventMode mode) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ControllerMap::eraseEvent(const Event::Type event, const EventMode mode) +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) { diff --git a/src/common/JoyMap.hxx b/src/common/JoyMap.hxx new file mode 100644 index 000000000..ebd145d6d --- /dev/null +++ b/src/common/JoyMap.hxx @@ -0,0 +1,121 @@ +//============================================================================ +// +// 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) + + JoyMapping() + : mode(EventMode(0)), button(0), + axis(JoyAxis(0)), adir(JoyDir(0)) { } + JoyMapping(const JoyMapping& m) + : mode(m.mode), button(m.button), + axis(m.axis), adir(m.adir) { } + 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) { } + + bool operator==(const JoyMapping& other) const + { + return (mode == other.mode + && button == other.button + && axis == other.axis + && adir == other.adir + ); + } + }; + 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); + + /** Erase mapping */ + void erase(const JoyMapping& mapping); + void erase(const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir); + + /** Get event for mapping */ + Event::Type get(const JoyMapping& mapping) const; + Event::Type get(const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir) 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; + + /** Get mapping description */ + string getDesc(const Event::Type event, const JoyMapping& mapping) const; + string getDesc(const Event::Type event, const EventMode mode, const int button, + const JoyAxis axis, const JoyDir adir) const; + + /** Get the mapping description(s) for given event and mode */ + string getEventMappingDesc(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: + 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 + ); + } + }; + + std::unordered_map myMap; +}; + +#endif diff --git a/src/common/PJoystickHandler.cxx b/src/common/PJoystickHandler.cxx index fb8f1e18c..d38746203 100644 --- a/src/common/PJoystickHandler.cxx +++ b/src/common/PJoystickHandler.cxx @@ -480,7 +480,7 @@ bool PhysicalJoystickHandler::addAxisMapping(Event::Type event, EventMode mode, 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; + j->axisTable[axis][int(value > 0 ? JoyDir::POS : JoyDir::NEG)][mode] = event; } return true; } @@ -522,13 +522,22 @@ bool PhysicalJoystickHandler::addHatMapping(Event::Type event, EventMode mode, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PhysicalJoystickHandler::addMapping(Event::Type event, EventMode mode, int stick, - int button, JoyAxis axis, JoyDir adir, int hat, JoyHat hdir) +void PhysicalJoystickHandler::addJoyMapping(Event::Type event, EventMode mode, int stick, + int button, JoyAxis axis, JoyDir adir) { - myControllerMap.add(event, mode, stick, button, axis, adir, hat, hdir); + const PhysicalJoystickPtr j = joy(stick); + j->joyMap.add(event, mode, button, axis, adir); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PhysicalJoystickHandler::addJoyHatMapping(Event::Type event, EventMode mode, int stick, + int hat, JoyHat hdir) +{ + const PhysicalJoystickPtr j = joy(stick); + + j->joyHatMap.add(event, mode, hat, hdir); +} // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PhysicalJoystickHandler::handleAxisEvent(int stick, int axis, int value) diff --git a/src/common/PJoystickHandler.hxx b/src/common/PJoystickHandler.hxx index b8bc447a6..f24c85dc3 100644 --- a/src/common/PJoystickHandler.hxx +++ b/src/common/PJoystickHandler.hxx @@ -28,7 +28,6 @@ class Event; #include "EventHandlerConstants.hxx" #include "PhysicalJoystick.hxx" #include "Variant.hxx" -#include "ControllerMap.hxx" using PhysicalJoystickPtr = shared_ptr; @@ -80,10 +79,10 @@ class PhysicalJoystickHandler bool addHatMapping(Event::Type event, EventMode mode, int stick, int hat, JoyHat value); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void addMapping(Event::Type event, EventMode mode, int stick, - int button, JoyAxis axis, JoyDir adir, int hat, JoyHat hdir); - - + void addJoyMapping(Event::Type event, EventMode mode, int stick, + int button, JoyAxis axis, JoyDir adir); + void addJoyHatMapping(Event::Type event, EventMode mode, int stick, + int hat, JoyHat hdir); /** Handle a physical joystick event. */ void handleAxisEvent(int stick, int axis, int value); @@ -140,9 +139,6 @@ class PhysicalJoystickHandler 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]; - - // Hashmap of controller events - ControllerMap myControllerMap; }; #endif diff --git a/src/common/PhysicalJoystick.hxx b/src/common/PhysicalJoystick.hxx index dd7872d30..94a7b1e76 100644 --- a/src/common/PhysicalJoystick.hxx +++ b/src/common/PhysicalJoystick.hxx @@ -20,6 +20,8 @@ #include "Event.hxx" #include "EventHandlerConstants.hxx" +#include "JoyMap.hxx" +#include "JoyHatMap.hxx" /** An abstraction of a physical (real) joystick in Stella. @@ -70,6 +72,10 @@ class PhysicalJoystick Event::Type (*hatTable)[NUM_JOY_HAT_DIRS][kNumModes]; int* axisLastValue; + // Hashmaps of controller events + JoyMap joyMap; + JoyHatMap joyHatMap; + private: void getValues(const string& list, IntArray& map) const; diff --git a/src/common/module.mk b/src/common/module.mk index 9c9f5c08a..e61dc12fc 100644 --- a/src/common/module.mk +++ b/src/common/module.mk @@ -6,7 +6,8 @@ MODULE_OBJS := \ src/common/FBSurfaceSDL2.o \ src/common/FrameBufferSDL2.o \ src/common/FSNodeZIP.o \ - src/common/ControllerMap.o \ + src/common/JoyMap.o \ + src/common/JoyHatMap.o \ src/common/KeyMap.o \ src/common/Logger.o \ src/common/main.o \ diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index a57bcf2c5..378b7b4f2 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -376,7 +376,8 @@ - + + @@ -1074,7 +1075,8 @@ - + + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index bde453361..f713f1dd2 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -978,7 +978,10 @@ Source Files\gui - + + Source Files + + Source Files @@ -2003,7 +2006,10 @@ Header Files - + + Header Files + + Header Files