Shortcuts: Improved shortcut key handling
This commit is contained in:
parent
05236c4d1a
commit
aab739a31c
4 changed files with 85 additions and 21 deletions
|
@ -58,7 +58,7 @@ bool EmulationSettings::_autoSaveNotify = false;
|
|||
|
||||
SimpleLock EmulationSettings::_shortcutLock;
|
||||
std::unordered_map<uint32_t, KeyCombination> EmulationSettings::_emulatorKeys[2];
|
||||
std::unordered_map<uint32_t, uint32_t> EmulationSettings::_shortcutKeyUsage;
|
||||
std::unordered_map<uint32_t, vector<KeyCombination>> EmulationSettings::_shortcutSupersets[2];
|
||||
|
||||
RamPowerOnState EmulationSettings::_ramPowerOnState = RamPowerOnState::AllZeros;
|
||||
|
||||
|
|
|
@ -356,6 +356,38 @@ struct KeyCombination
|
|||
uint32_t Key1;
|
||||
uint32_t Key2;
|
||||
uint32_t Key3;
|
||||
|
||||
vector<uint32_t> GetKeys()
|
||||
{
|
||||
vector<uint32_t> 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<uint32_t> myKeys = GetKeys();
|
||||
vector<uint32_t> 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<uint32_t, KeyCombination> _emulatorKeys[2];
|
||||
static std::unordered_map<uint32_t, uint32_t> _shortcutKeyUsage;
|
||||
static std::unordered_map<uint32_t, vector<KeyCombination>> _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<const uint32_t, KeyCombination> &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<KeyCombination> GetShortcutSupersets(EmulatorShortcut shortcut, int keySetIndex)
|
||||
{
|
||||
auto lock = _shortcutLock.AcquireSafe();
|
||||
return _shortcutKeyUsage[keyCode];
|
||||
return _shortcutSupersets[keySetIndex][(uint32_t)shortcut];
|
||||
}
|
||||
|
||||
static bool NeedControllerUpdate()
|
||||
|
|
|
@ -28,23 +28,27 @@ ShortcutKeyHandler::~ShortcutKeyHandler()
|
|||
|
||||
bool ShortcutKeyHandler::IsKeyPressed(EmulatorShortcut shortcut)
|
||||
{
|
||||
KeyCombination comb = EmulationSettings::GetShortcutKey(shortcut, _keySetIndex);
|
||||
KeyCombination keyComb = EmulationSettings::GetShortcutKey(shortcut, _keySetIndex);
|
||||
vector<KeyCombination> 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;
|
||||
}
|
|
@ -14,6 +14,8 @@ private:
|
|||
|
||||
int _keySetIndex;
|
||||
vector<uint32_t> _pressedKeys;
|
||||
vector<uint32_t> _lastPressedKeys;
|
||||
bool _isKeyUp;
|
||||
|
||||
std::unordered_set<uint32_t> _keysDown[2];
|
||||
std::unordered_set<uint32_t> _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);
|
||||
|
|
Loading…
Add table
Reference in a new issue