From aab739a31c3311969b940ae20860b8dadabed946 Mon Sep 17 00:00:00 2001 From: Souryo Date: Sun, 17 Sep 2017 10:25:20 -0400 Subject: [PATCH] Shortcuts: Improved shortcut key handling --- Core/EmulationSettings.cpp | 2 +- Core/EmulationSettings.h | 55 +++++++++++++++++++++++++++++++------ Core/ShortcutKeyHandler.cpp | 46 +++++++++++++++++++++++-------- Core/ShortcutKeyHandler.h | 3 ++ 4 files changed, 85 insertions(+), 21 deletions(-) diff --git a/Core/EmulationSettings.cpp b/Core/EmulationSettings.cpp index a686b05e..990f31bc 100644 --- a/Core/EmulationSettings.cpp +++ b/Core/EmulationSettings.cpp @@ -58,7 +58,7 @@ bool EmulationSettings::_autoSaveNotify = false; SimpleLock EmulationSettings::_shortcutLock; std::unordered_map EmulationSettings::_emulatorKeys[2]; -std::unordered_map EmulationSettings::_shortcutKeyUsage; +std::unordered_map> EmulationSettings::_shortcutSupersets[2]; RamPowerOnState EmulationSettings::_ramPowerOnState = RamPowerOnState::AllZeros; diff --git a/Core/EmulationSettings.h b/Core/EmulationSettings.h index 616d789e..7eca929c 100644 --- a/Core/EmulationSettings.h +++ b/Core/EmulationSettings.h @@ -356,6 +356,38 @@ struct KeyCombination uint32_t Key1; uint32_t Key2; uint32_t Key3; + + vector GetKeys() + { + vector result; + if(Key1) { + result.push_back(Key1); + } + if(Key2) { + result.push_back(Key2); + } + if(Key3) { + result.push_back(Key3); + } + return result; + } + + bool IsSubsetOf(KeyCombination keyCombination) + { + vector myKeys = GetKeys(); + vector otherKeys = keyCombination.GetKeys(); + + if(otherKeys.size() > myKeys.size()) { + for(int i = 0; i < myKeys.size(); i++) { + if(std::find(otherKeys.begin(), otherKeys.end(), myKeys[i]) == otherKeys.end()) { + //Current key combination contains a key not found in the other combination, so it's not a subset + return false; + } + } + return true; + } + return false; + } }; enum class Language @@ -488,7 +520,7 @@ private: static bool _autoSaveNotify; static std::unordered_map _emulatorKeys[2]; - static std::unordered_map _shortcutKeyUsage; + static std::unordered_map> _shortcutSupersets[2]; static RamPowerOnState _ramPowerOnState; @@ -1060,17 +1092,24 @@ public: auto lock = _shortcutLock.AcquireSafe(); _emulatorKeys[0].clear(); _emulatorKeys[1].clear(); - _shortcutKeyUsage.clear(); + _shortcutSupersets[0].clear(); + _shortcutSupersets[1].clear(); } static void SetShortcutKey(EmulatorShortcut shortcut, KeyCombination keyCombination, int keySetIndex) { auto lock = _shortcutLock.AcquireSafe(); - _emulatorKeys[keySetIndex][(int)shortcut] = keyCombination; + _emulatorKeys[keySetIndex][(uint32_t)shortcut] = keyCombination; - _shortcutKeyUsage[keyCombination.Key1]++; - _shortcutKeyUsage[keyCombination.Key2]++; - _shortcutKeyUsage[keyCombination.Key3]++; + for(int i = 0; i < 2; i++) { + for(std::pair &kvp : _emulatorKeys[i]) { + if(keyCombination.IsSubsetOf(kvp.second)) { + _shortcutSupersets[keySetIndex][(uint32_t)shortcut].push_back(kvp.second); + } else if(kvp.second.IsSubsetOf(keyCombination)) { + _shortcutSupersets[i][kvp.first].push_back(keyCombination); + } + } + } } static KeyCombination GetShortcutKey(EmulatorShortcut shortcut, int keySetIndex) @@ -1083,10 +1122,10 @@ public: return {}; } - static int GetKeyUsage(int keyCode) + static vector GetShortcutSupersets(EmulatorShortcut shortcut, int keySetIndex) { auto lock = _shortcutLock.AcquireSafe(); - return _shortcutKeyUsage[keyCode]; + return _shortcutSupersets[keySetIndex][(uint32_t)shortcut]; } static bool NeedControllerUpdate() diff --git a/Core/ShortcutKeyHandler.cpp b/Core/ShortcutKeyHandler.cpp index 4dcaed56..cce0c579 100644 --- a/Core/ShortcutKeyHandler.cpp +++ b/Core/ShortcutKeyHandler.cpp @@ -28,23 +28,27 @@ ShortcutKeyHandler::~ShortcutKeyHandler() bool ShortcutKeyHandler::IsKeyPressed(EmulatorShortcut shortcut) { - KeyCombination comb = EmulationSettings::GetShortcutKey(shortcut, _keySetIndex); + KeyCombination keyComb = EmulationSettings::GetShortcutKey(shortcut, _keySetIndex); + vector supersets = EmulationSettings::GetShortcutSupersets(shortcut, _keySetIndex); + for(KeyCombination &superset : supersets) { + if(IsKeyPressed(superset)) { + //A superset is pressed, ignore this subset + return false; + } + } + //No supersets are pressed, check if all matching keys are pressed + return IsKeyPressed(keyComb); +} + +bool ShortcutKeyHandler::IsKeyPressed(KeyCombination comb) +{ int keyCount = (comb.Key1 ? 1 : 0) + (comb.Key2 ? 1 : 0) + (comb.Key3 ? 1 : 0); if(keyCount == 0 || _pressedKeys.empty()) { return false; } - if(_pressedKeys.size() != keyCount) { - //Only allow shortcuts that use as many keys as the number of keys pressed, unless there are no conflicts with other shortcuts - //e.g: Needed to prevent Shift-F1 from triggering a shortcut for F1 - if(EmulationSettings::GetKeyUsage(comb.Key1) > 1 || (comb.Key2 && EmulationSettings::GetKeyUsage(comb.Key2) > 1) || (comb.Key3 && EmulationSettings::GetKeyUsage(comb.Key3) > 1)) { - //Conflicts found, do not activate shortcut when the number of keys is not exactly right - return false; - } - } - return ControlManager::IsKeyPressed(comb.Key1) && (comb.Key2 == 0 || ControlManager::IsKeyPressed(comb.Key2)) && (comb.Key3 == 0 || ControlManager::IsKeyPressed(comb.Key3)); @@ -53,9 +57,10 @@ bool ShortcutKeyHandler::IsKeyPressed(EmulatorShortcut shortcut) bool ShortcutKeyHandler::DetectKeyPress(EmulatorShortcut shortcut) { if(IsKeyPressed(shortcut)) { + bool newlyPressed = _prevKeysDown[_keySetIndex].find((uint32_t)shortcut) == _prevKeysDown[_keySetIndex].end(); _keysDown[_keySetIndex].emplace((uint32_t)shortcut); - if(_prevKeysDown[_keySetIndex].find((uint32_t)shortcut) == _prevKeysDown[_keySetIndex].end()) { + if(newlyPressed && !_isKeyUp) { return true; } } @@ -137,7 +142,7 @@ void ShortcutKeyHandler::CheckMappedKeys() MessageManager::SendNotification(ConsoleNotificationType::ExecuteShortcut, (void*)EmulatorShortcut::ToggleAudio); } - if(IsKeyPressed(EmulatorShortcut::RunSingleFrame)) { + if(DetectKeyPress(EmulatorShortcut::RunSingleFrame)) { if(EmulationSettings::CheckFlag(EmulationFlags::Paused)) { EmulationSettings::ClearFlags(EmulationFlags::Paused); Console::Pause(); @@ -176,6 +181,21 @@ void ShortcutKeyHandler::ProcessKeys() ControlManager::RefreshKeyState(); _pressedKeys = ControlManager::GetPressedKeys(); + _isKeyUp = _pressedKeys.size() < _lastPressedKeys.size(); + + if(_pressedKeys.size() == _lastPressedKeys.size()) { + bool noChange = true; + for(int i = 0; i < _pressedKeys.size(); i++) { + if(_pressedKeys[i] != _lastPressedKeys[i]) { + noChange = false; + break; + } + } + if(noChange) { + //Same keys as before, nothing to do + return; + } + } for(int i = 0; i < 2; i++) { _keysDown[i].clear(); @@ -183,4 +203,6 @@ void ShortcutKeyHandler::ProcessKeys() CheckMappedKeys(); _prevKeysDown[i] = _keysDown[i]; } + + _lastPressedKeys = _pressedKeys; } \ No newline at end of file diff --git a/Core/ShortcutKeyHandler.h b/Core/ShortcutKeyHandler.h index 96332b68..4aff92ca 100644 --- a/Core/ShortcutKeyHandler.h +++ b/Core/ShortcutKeyHandler.h @@ -14,6 +14,8 @@ private: int _keySetIndex; vector _pressedKeys; + vector _lastPressedKeys; + bool _isKeyUp; std::unordered_set _keysDown[2]; std::unordered_set _prevKeysDown[2]; @@ -21,6 +23,7 @@ private: void CheckMappedKeys(); bool IsKeyPressed(EmulatorShortcut key); + bool IsKeyPressed(KeyCombination comb); bool DetectKeyPress(EmulatorShortcut key); bool DetectKeyRelease(EmulatorShortcut key);