Index: ps/trunk/source/gui/ObjectTypes/CInput.cpp =================================================================== --- ps/trunk/source/gui/ObjectTypes/CInput.cpp +++ ps/trunk/source/gui/ObjectTypes/CInput.cpp @@ -231,9 +231,9 @@ // TODO: there are probably other keys that we could ignore, but recognizing "non-glyph" keys isn't that trivial. // Further, don't input text if modifiers other than shift are pressed (the user is presumably trying to perform a hotkey). if (keyCode == SDLK_ESCAPE || - g_keys[SDLK_LCTRL] || g_keys[SDLK_RCTRL] || - g_keys[SDLK_LALT] || g_keys[SDLK_RALT] || - g_keys[SDLK_LGUI] || g_keys[SDLK_RGUI]) + g_scancodes[SDL_SCANCODE_LCTRL] || g_scancodes[SDL_SCANCODE_LCTRL] || + g_scancodes[SDL_SCANCODE_LALT] || g_scancodes[SDL_SCANCODE_RALT] || + g_scancodes[SDL_SCANCODE_LGUI] || g_scancodes[SDL_SCANCODE_RGUI]) return IN_PASS; if (m_ComposingText) @@ -369,7 +369,7 @@ void CInput::ManuallyImmutableHandleKeyDownEvent(const SDL_Keycode keyCode) { - bool shiftKeyPressed = g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT]; + bool shiftKeyPressed = g_scancodes[SDL_SCANCODE_LSHIFT] || g_scancodes[SDL_SCANCODE_RSHIFT]; switch (keyCode) { @@ -609,7 +609,7 @@ InReaction CInput::ManuallyHandleHotkeyEvent(const SDL_Event_* ev) { - bool shiftKeyPressed = g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT]; + bool shiftKeyPressed = g_scancodes[SDL_SCANCODE_LSHIFT] || g_scancodes[SDL_SCANCODE_RSHIFT]; std::string hotkey = static_cast(ev->ev.user.data1); @@ -962,7 +962,7 @@ // instance, if we press between a and b, the point // should of course be placed accordingly. Other // special cases are handled like the input box norms. - if (g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT]) + if (g_scancodes[SDL_SCANCODE_LSHIFT] || g_scancodes[SDL_SCANCODE_RSHIFT]) m_iBufferPos = GetMouseHoveringTextPosition(); else m_iBufferPos = m_iBufferPos_Tail = GetMouseHoveringTextPosition(); Index: ps/trunk/source/ps/CConsole.cpp =================================================================== --- ps/trunk/source/ps/CConsole.cpp +++ ps/trunk/source/ps/CConsole.cpp @@ -360,7 +360,7 @@ } else { - if (g_keys[SDLK_RCTRL] || g_keys[SDLK_LCTRL]) + if (g_scancodes[SDL_SCANCODE_LCTRL] || g_scancodes[SDL_SCANCODE_LCTRL]) { // Make Ctrl-Delete delete up to end of line m_szBuffer[m_iBufferPos] = '\0'; @@ -379,7 +379,7 @@ return; case SDLK_HOME: - if (g_keys[SDLK_RCTRL] || g_keys[SDLK_LCTRL]) + if (g_scancodes[SDL_SCANCODE_LCTRL] || g_scancodes[SDL_SCANCODE_LCTRL]) { std::lock_guard lock(m_Mutex); // needed for safe access to m_deqMsgHistory @@ -393,7 +393,7 @@ return; case SDLK_END: - if (g_keys[SDLK_RCTRL] || g_keys[SDLK_LCTRL]) + if (g_scancodes[SDL_SCANCODE_LCTRL] || g_scancodes[SDL_SCANCODE_LCTRL]) { m_iMsgHistPos = 1; } Index: ps/trunk/source/ps/Globals.h =================================================================== --- ps/trunk/source/ps/Globals.h +++ ps/trunk/source/ps/Globals.h @@ -22,7 +22,7 @@ #include "lib/frequency_filter.h" #include "ps/KeyName.h" -#include +#include // thin abstraction layer on top of SDL. // game code should use it instead of SDL_GetMouseState etc. because @@ -40,11 +40,11 @@ extern bool g_mouse_active; /** - * g_keys: Key states, indexed by SDLK* constants. If an entry is true, + * g_scancodes: Key states, indexed by SDL_Scancode constants. If an entry is true, * it represents a pressed key. * Updated by GlobalsInputHandler in response to key press/release events. */ -extern std::map g_keys; +extern std::unordered_map g_scancodes; /** * g_mouse_buttons: Mouse buttons states, indexed by SDL_BUTTON_* constants. Index: ps/trunk/source/ps/Globals.cpp =================================================================== --- ps/trunk/source/ps/Globals.cpp +++ ps/trunk/source/ps/Globals.cpp @@ -25,7 +25,8 @@ bool g_app_minimized = false; bool g_app_has_focus = true; -std::map g_keys; +std::unordered_map g_scancodes; + int g_mouse_x = 50, g_mouse_y = 50; bool g_mouse_active = true; @@ -85,7 +86,7 @@ case SDL_KEYDOWN: case SDL_KEYUP: - g_keys[ev->ev.key.keysym.sym] = (ev->ev.type == SDL_KEYDOWN); + g_scancodes[ev->ev.key.keysym.scancode] = (ev->ev.type == SDL_KEYDOWN); return IN_PASS; default: Index: ps/trunk/source/ps/Hotkey.h =================================================================== --- ps/trunk/source/ps/Hotkey.h +++ ps/trunk/source/ps/Hotkey.h @@ -52,17 +52,14 @@ struct SKey { SDL_Scancode_ code; // scancode or MOUSE_ or UNIFIED_ value - bool negated; // whether the key must be pressed (false) or unpressed (true) - - bool operator<(const SKey& o) const { return code < o.code && negated < o.negated; } - bool operator==(const SKey& o) const { return code == o.code && negated == o.negated; } + bool operator<(const SKey& o) const { return code < o.code; } + bool operator==(const SKey& o) const { return code == o.code; } }; // Hotkey data associated with an externally-specified 'primary' keycode struct SHotkeyMapping { CStr name; // name of the hotkey - bool negated; // whether the primary key must be pressed (false) or unpressed (true) std::vector requires; // list of non-primary keys that must also be active }; Index: ps/trunk/source/ps/Hotkey.cpp =================================================================== --- ps/trunk/source/ps/Hotkey.cpp +++ ps/trunk/source/ps/Hotkey.cpp @@ -50,7 +50,6 @@ // Unused hotkeys must still be registered in the map to appear in the hotkey editor. SHotkeyMapping unusedCode; unusedCode.name = hotkeyName; - unusedCode.negated = false; g_HotkeyMap[UNUSED_HOTKEY_CODE].push_back(unusedCode); continue; } @@ -73,7 +72,7 @@ continue; } - SKey key = { scancode, false }; + SKey key = { scancode }; keyCombination.push_back(key); } @@ -83,7 +82,6 @@ SHotkeyMapping bindCode; bindCode.name = hotkeyName; - bindCode.negated = itKey->negated; for (itKey2 = keyCombination.begin(); itKey2 != keyCombination.end(); ++itKey2) if (itKey != itKey2) // Push any auxiliary keys @@ -98,25 +96,6 @@ void LoadHotkeys() { LoadConfigBindings(); - - // Set up the state of the hotkeys given no key is down. - // i.e. find those hotkeys triggered by all negations. - - for (const std::pair& p : g_HotkeyMap) - for (const SHotkeyMapping& hotkey : p.second) - { - if (!hotkey.negated) - continue; - - bool allNegated = true; - - for (const SKey& k : hotkey.requires) - if (!k.negated) - allNegated = false; - - if (allNegated) - g_HotkeyStatus[hotkey.name] = true; - } } void UnloadHotkeys() @@ -125,19 +104,19 @@ g_HotkeyStatus.clear(); } -bool isNegated(const SKey& key) +bool isPressed(const SKey& key) { // Normal keycodes are below EXTRA_KEYS_BASE - if ((int)key.code < EXTRA_KEYS_BASE && g_keys[key.code] == key.negated) - return false; + if ((int)key.code < EXTRA_KEYS_BASE) + return g_scancodes[key.code]; + // Mouse 'keycodes' are after the modifier keys - else if ((int)key.code < MOUSE_LAST && (int)key.code > MOUSE_BASE && g_mouse_buttons[key.code - MOUSE_BASE] == key.negated) - return false; + else if ((int)key.code < MOUSE_LAST && (int)key.code > MOUSE_BASE) + return g_mouse_buttons[key.code - MOUSE_BASE]; + // Modifier keycodes are between the normal keys and the mouse 'keys' - else if ((int)key.code < UNIFIED_LAST && (int)key.code > SDL_NUM_SCANCODES && unified[key.code - UNIFIED_SHIFT] == key.negated) - return false; - else - return true; + else if ((int)key.code < UNIFIED_LAST && (int)key.code > SDL_NUM_SCANCODES) + return unified[key.code - UNIFIED_SHIFT]; } InReaction HotkeyStateChange(const SDL_Event_* ev) @@ -256,23 +235,17 @@ bool typeKeyDown = ( ev->ev.type == SDL_KEYDOWN ) || ( ev->ev.type == SDL_MOUSEBUTTONDOWN ) || (ev->ev.type == SDL_MOUSEWHEEL); - // -- KEYDOWN SECTION -- - - std::vector closestMapNames; + std::vector pressedHotkeys; + std::vector releasedHotkeys; size_t closestMapMatch = 0; for (const SHotkeyMapping& hotkey : g_HotkeyMap[scancode]) { - // If a key has been pressed, and this event triggers on its release, skip it. - // Similarly, if the key's been released and the event triggers on a keypress, skip it. - if (hotkey.negated == typeKeyDown) - continue; - // Check for no unpermitted keys bool accept = true; for (const SKey& k : hotkey.requires) { - accept = isNegated(k); + accept = isPressed(k); if (!accept) break; } @@ -286,23 +259,26 @@ if (hotkey.requires.size() + 1 > closestMapMatch) { // Throw away the old less-precise matches - closestMapNames.clear(); + pressedHotkeys.clear(); + releasedHotkeys.clear(); closestMapMatch = hotkey.requires.size() + 1; } - - closestMapNames.push_back(hotkey.name.c_str()); + if (typeKeyDown) + pressedHotkeys.push_back(hotkey.name.c_str()); + else + releasedHotkeys.push_back(hotkey.name.c_str()); } } } - for (size_t i = 0; i < closestMapNames.size(); ++i) + for (const char* hotkeyName : pressedHotkeys) { - // Send a KeyPress event when a key is pressed initially and on mouseButton and mouseWheel events. + // Send a KeyPress event when a hotkey is pressed initially and on mouseButton and mouseWheel events. if (ev->ev.type != SDL_KEYDOWN || ev->ev.key.repeat == 0) { SDL_Event_ hotkeyPressNotification; hotkeyPressNotification.ev.type = SDL_HOTKEYPRESS; - hotkeyPressNotification.ev.user.data1 = const_cast(closestMapNames[i]); + hotkeyPressNotification.ev.user.data1 = const_cast(hotkeyName); in_push_priority_event(&hotkeyPressNotification); } @@ -311,37 +287,16 @@ // On linux, modifier keys (shift, alt, ctrl) are not repeated, see https://github.com/SFML/SFML/issues/122. SDL_Event_ hotkeyDownNotification; hotkeyDownNotification.ev.type = SDL_HOTKEYDOWN; - hotkeyDownNotification.ev.user.data1 = const_cast(closestMapNames[i]); + hotkeyDownNotification.ev.user.data1 = const_cast(hotkeyName); in_push_priority_event(&hotkeyDownNotification); } - // -- KEYUP SECTION -- - - for (const SHotkeyMapping& hotkey : g_HotkeyMap[scancode]) + for (const char* hotkeyName : releasedHotkeys) { - // If it's a keydown event, won't cause HotKeyUps in anything that doesn't - // use this key negated => skip them - // If it's a keyup event, won't cause HotKeyUps in anything that does use - // this key negated => skip them too. - if (hotkey.negated != typeKeyDown) - continue; - - // Check for no unpermitted keys - bool accept = true; - for (const SKey& k : hotkey.requires) - { - accept = isNegated(k); - if (!accept) - break; - } - - if (accept) - { - SDL_Event_ hotkeyNotification; - hotkeyNotification.ev.type = SDL_HOTKEYUP; - hotkeyNotification.ev.user.data1 = const_cast(hotkey.name.c_str()); - in_push_priority_event(&hotkeyNotification); - } + SDL_Event_ hotkeyNotification; + hotkeyNotification.ev.type = SDL_HOTKEYUP; + hotkeyNotification.ev.user.data1 = const_cast(hotkeyName); + in_push_priority_event(&hotkeyNotification); } return IN_PASS; Index: ps/trunk/source/ps/scripting/JSInterface_Hotkey.cpp =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_Hotkey.cpp +++ ps/trunk/source/ps/scripting/JSInterface_Hotkey.cpp @@ -145,7 +145,7 @@ std::set codes; for (const std::string& key : keys) - codes.insert(SKey{ FindScancode(key), false }); + codes.insert(SKey{ FindScancode(key) }); std::vector conflicts; // This isn't very efficient, but we shouldn't iterate too many hotkeys