Shortcuts: Improved shortcut key handling

This commit is contained in:
Souryo 2017-09-17 10:25:20 -04:00
parent 05236c4d1a
commit aab739a31c
4 changed files with 85 additions and 21 deletions

View file

@ -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;

View file

@ -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()

View file

@ -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;
}

View file

@ -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);