diff --git a/src/wx/config/game-control.cpp b/src/wx/config/game-control.cpp index 86f6122c..efd1e022 100644 --- a/src/wx/config/game-control.cpp +++ b/src/wx/config/game-control.cpp @@ -2,6 +2,7 @@ #include "wx/opts.h" #include "wx/strutils.h" +#include "wx/wxlogdebug.h" namespace config { diff --git a/src/wx/config/internal/shortcuts-internal.cpp b/src/wx/config/internal/shortcuts-internal.cpp index d77d0f82..83e8ba7a 100644 --- a/src/wx/config/internal/shortcuts-internal.cpp +++ b/src/wx/config/internal/shortcuts-internal.cpp @@ -1,4 +1,5 @@ #include "wx/config/shortcuts.h" +#include "wx/config/user-input.h" #include @@ -11,86 +12,86 @@ namespace internal { const std::unordered_map& DefaultShortcuts() { static const std::unordered_map kDefaultShortcuts = { - {XRCID("CheatsList"), UserInput('C', wxMOD_CMD)}, - {XRCID("NextFrame"), UserInput('N', wxMOD_CMD)}, + {XRCID("CheatsList"), KeyboardInput('C', wxMOD_CMD)}, + {XRCID("NextFrame"), KeyboardInput('N', wxMOD_CMD)}, // this was annoying people A LOT #334 - //{wxID_EXIT, UserInput(WXK_ESCAPE, wxMOD_NONE)}, + //{wxID_EXIT, KeyboardInput(WXK_ESCAPE, wxMOD_NONE)}, // this was annoying people #298 - //{wxID_EXIT, UserInput('X', wxMOD_CMD)}, + //{wxID_EXIT, KeyboardInput('X', wxMOD_CMD)}, - {wxID_EXIT, UserInput('Q', wxMOD_CMD)}, - {wxID_CLOSE, UserInput('W', wxMOD_CMD)}, + {wxID_EXIT, KeyboardInput('Q', wxMOD_CMD)}, + {wxID_CLOSE, KeyboardInput('W', wxMOD_CMD)}, // load most recent is more commonly used than load state - // {XRCID("Load"), UserInput('L', wxMOD_CMD)}, - {XRCID("LoadGameRecent"), UserInput('L', wxMOD_CMD)}, - {XRCID("LoadGame01"), UserInput(WXK_F1, wxMOD_NONE)}, - {XRCID("LoadGame02"), UserInput(WXK_F2, wxMOD_NONE)}, - {XRCID("LoadGame03"), UserInput(WXK_F3, wxMOD_NONE)}, - {XRCID("LoadGame04"), UserInput(WXK_F4, wxMOD_NONE)}, - {XRCID("LoadGame05"), UserInput(WXK_F5, wxMOD_NONE)}, - {XRCID("LoadGame06"), UserInput(WXK_F6, wxMOD_NONE)}, - {XRCID("LoadGame07"), UserInput(WXK_F7, wxMOD_NONE)}, - {XRCID("LoadGame08"), UserInput(WXK_F8, wxMOD_NONE)}, - {XRCID("LoadGame09"), UserInput(WXK_F9, wxMOD_NONE)}, - {XRCID("LoadGame10"), UserInput(WXK_F10, wxMOD_NONE)}, - {XRCID("Pause"), UserInput(WXK_PAUSE, wxMOD_NONE)}, - {XRCID("Pause"), UserInput('P', wxMOD_CMD)}, - {XRCID("Reset"), UserInput('R', wxMOD_CMD)}, + // {XRCID("Load"), KeyboardInput('L', wxMOD_CMD)}, + {XRCID("LoadGameRecent"), KeyboardInput('L', wxMOD_CMD)}, + {XRCID("LoadGame01"), KeyboardInput(WXK_F1, wxMOD_NONE)}, + {XRCID("LoadGame02"), KeyboardInput(WXK_F2, wxMOD_NONE)}, + {XRCID("LoadGame03"), KeyboardInput(WXK_F3, wxMOD_NONE)}, + {XRCID("LoadGame04"), KeyboardInput(WXK_F4, wxMOD_NONE)}, + {XRCID("LoadGame05"), KeyboardInput(WXK_F5, wxMOD_NONE)}, + {XRCID("LoadGame06"), KeyboardInput(WXK_F6, wxMOD_NONE)}, + {XRCID("LoadGame07"), KeyboardInput(WXK_F7, wxMOD_NONE)}, + {XRCID("LoadGame08"), KeyboardInput(WXK_F8, wxMOD_NONE)}, + {XRCID("LoadGame09"), KeyboardInput(WXK_F9, wxMOD_NONE)}, + {XRCID("LoadGame10"), KeyboardInput(WXK_F10, wxMOD_NONE)}, + {XRCID("Pause"), KeyboardInput(WXK_PAUSE, wxMOD_NONE)}, + {XRCID("Pause"), KeyboardInput('P', wxMOD_CMD)}, + {XRCID("Reset"), KeyboardInput('R', wxMOD_CMD)}, // add shortcuts for original size multiplier #415 - {XRCID("SetSize1x"), UserInput('1', wxMOD_NONE)}, - {XRCID("SetSize2x"), UserInput('2', wxMOD_NONE)}, - {XRCID("SetSize3x"), UserInput('3', wxMOD_NONE)}, - {XRCID("SetSize4x"), UserInput('4', wxMOD_NONE)}, - {XRCID("SetSize5x"), UserInput('5', wxMOD_NONE)}, - {XRCID("SetSize6x"), UserInput('6', wxMOD_NONE)}, + {XRCID("SetSize1x"), KeyboardInput('1', wxMOD_NONE)}, + {XRCID("SetSize2x"), KeyboardInput('2', wxMOD_NONE)}, + {XRCID("SetSize3x"), KeyboardInput('3', wxMOD_NONE)}, + {XRCID("SetSize4x"), KeyboardInput('4', wxMOD_NONE)}, + {XRCID("SetSize5x"), KeyboardInput('5', wxMOD_NONE)}, + {XRCID("SetSize6x"), KeyboardInput('6', wxMOD_NONE)}, // save oldest is more commonly used than save other - // {XRCID("Save"), UserInput('S', wxMOD_CMD)}, - {XRCID("SaveGameOldest"), UserInput('S', wxMOD_CMD)}, - {XRCID("SaveGame01"), UserInput(WXK_F1, wxMOD_SHIFT)}, - {XRCID("SaveGame02"), UserInput(WXK_F2, wxMOD_SHIFT)}, - {XRCID("SaveGame03"), UserInput(WXK_F3, wxMOD_SHIFT)}, - {XRCID("SaveGame04"), UserInput(WXK_F4, wxMOD_SHIFT)}, - {XRCID("SaveGame05"), UserInput(WXK_F5, wxMOD_SHIFT)}, - {XRCID("SaveGame06"), UserInput(WXK_F6, wxMOD_SHIFT)}, - {XRCID("SaveGame07"), UserInput(WXK_F7, wxMOD_SHIFT)}, - {XRCID("SaveGame08"), UserInput(WXK_F8, wxMOD_SHIFT)}, - {XRCID("SaveGame09"), UserInput(WXK_F9, wxMOD_SHIFT)}, - {XRCID("SaveGame10"), UserInput(WXK_F10, wxMOD_SHIFT)}, + // {XRCID("Save"), KeyboardInput('S', wxMOD_CMD)}, + {XRCID("SaveGameOldest"), KeyboardInput('S', wxMOD_CMD)}, + {XRCID("SaveGame01"), KeyboardInput(WXK_F1, wxMOD_SHIFT)}, + {XRCID("SaveGame02"), KeyboardInput(WXK_F2, wxMOD_SHIFT)}, + {XRCID("SaveGame03"), KeyboardInput(WXK_F3, wxMOD_SHIFT)}, + {XRCID("SaveGame04"), KeyboardInput(WXK_F4, wxMOD_SHIFT)}, + {XRCID("SaveGame05"), KeyboardInput(WXK_F5, wxMOD_SHIFT)}, + {XRCID("SaveGame06"), KeyboardInput(WXK_F6, wxMOD_SHIFT)}, + {XRCID("SaveGame07"), KeyboardInput(WXK_F7, wxMOD_SHIFT)}, + {XRCID("SaveGame08"), KeyboardInput(WXK_F8, wxMOD_SHIFT)}, + {XRCID("SaveGame09"), KeyboardInput(WXK_F9, wxMOD_SHIFT)}, + {XRCID("SaveGame10"), KeyboardInput(WXK_F10, wxMOD_SHIFT)}, // I prefer the SDL ESC key binding - // {XRCID("ToggleFullscreen"), UserInput(WXK_ESCAPE, wxMOD_NONE)}, + // {XRCID("ToggleFullscreen"), KeyboardInput(WXK_ESCAPE, wxMOD_NONE)}, // alt-enter is more standard anyway - {XRCID("ToggleFullscreen"), UserInput(WXK_RETURN, wxMOD_ALT)}, - {XRCID("JoypadAutofireA"), UserInput('1', wxMOD_ALT)}, - {XRCID("JoypadAutofireB"), UserInput('2', wxMOD_ALT)}, - {XRCID("JoypadAutofireL"), UserInput('3', wxMOD_ALT)}, - {XRCID("JoypadAutofireR"), UserInput('4', wxMOD_ALT)}, - {XRCID("VideoLayersBG0"), UserInput('1', wxMOD_CMD)}, - {XRCID("VideoLayersBG1"), UserInput('2', wxMOD_CMD)}, - {XRCID("VideoLayersBG2"), UserInput('3', wxMOD_CMD)}, - {XRCID("VideoLayersBG3"), UserInput('4', wxMOD_CMD)}, - {XRCID("VideoLayersOBJ"), UserInput('5', wxMOD_CMD)}, - {XRCID("VideoLayersWIN0"), UserInput('6', wxMOD_CMD)}, - {XRCID("VideoLayersWIN1"), UserInput('7', wxMOD_CMD)}, - {XRCID("VideoLayersOBJWIN"), UserInput('8', wxMOD_CMD)}, - {XRCID("Rewind"), UserInput('B', wxMOD_CMD)}, + {XRCID("ToggleFullscreen"), KeyboardInput(WXK_RETURN, wxMOD_ALT)}, + {XRCID("JoypadAutofireA"), KeyboardInput('1', wxMOD_ALT)}, + {XRCID("JoypadAutofireB"), KeyboardInput('2', wxMOD_ALT)}, + {XRCID("JoypadAutofireL"), KeyboardInput('3', wxMOD_ALT)}, + {XRCID("JoypadAutofireR"), KeyboardInput('4', wxMOD_ALT)}, + {XRCID("VideoLayersBG0"), KeyboardInput('1', wxMOD_CMD)}, + {XRCID("VideoLayersBG1"), KeyboardInput('2', wxMOD_CMD)}, + {XRCID("VideoLayersBG2"), KeyboardInput('3', wxMOD_CMD)}, + {XRCID("VideoLayersBG3"), KeyboardInput('4', wxMOD_CMD)}, + {XRCID("VideoLayersOBJ"), KeyboardInput('5', wxMOD_CMD)}, + {XRCID("VideoLayersWIN0"), KeyboardInput('6', wxMOD_CMD)}, + {XRCID("VideoLayersWIN1"), KeyboardInput('7', wxMOD_CMD)}, + {XRCID("VideoLayersOBJWIN"), KeyboardInput('8', wxMOD_CMD)}, + {XRCID("Rewind"), KeyboardInput('B', wxMOD_CMD)}, // following are not in standard menus // FILExx are filled in when recent menu is filled - {wxID_FILE1, UserInput(WXK_F1, wxMOD_CMD)}, - {wxID_FILE2, UserInput(WXK_F2, wxMOD_CMD)}, - {wxID_FILE3, UserInput(WXK_F3, wxMOD_CMD)}, - {wxID_FILE4, UserInput(WXK_F4, wxMOD_CMD)}, - {wxID_FILE5, UserInput(WXK_F5, wxMOD_CMD)}, - {wxID_FILE6, UserInput(WXK_F6, wxMOD_CMD)}, - {wxID_FILE7, UserInput(WXK_F7, wxMOD_CMD)}, - {wxID_FILE8, UserInput(WXK_F8, wxMOD_CMD)}, - {wxID_FILE9, UserInput(WXK_F9, wxMOD_CMD)}, - {wxID_FILE10, UserInput(WXK_F10, wxMOD_CMD)}, - {XRCID("VideoLayersReset"), UserInput('0', wxMOD_CMD)}, - {XRCID("ChangeFilter"), UserInput('G', wxMOD_CMD)}, - {XRCID("ChangeIFB"), UserInput('I', wxMOD_CMD)}, - {XRCID("IncreaseVolume"), UserInput(WXK_NUMPAD_ADD, wxMOD_NONE)}, - {XRCID("DecreaseVolume"), UserInput(WXK_NUMPAD_SUBTRACT, wxMOD_NONE)}, - {XRCID("ToggleSound"), UserInput(WXK_NUMPAD_ENTER, wxMOD_NONE)}, + {wxID_FILE1, KeyboardInput(WXK_F1, wxMOD_CMD)}, + {wxID_FILE2, KeyboardInput(WXK_F2, wxMOD_CMD)}, + {wxID_FILE3, KeyboardInput(WXK_F3, wxMOD_CMD)}, + {wxID_FILE4, KeyboardInput(WXK_F4, wxMOD_CMD)}, + {wxID_FILE5, KeyboardInput(WXK_F5, wxMOD_CMD)}, + {wxID_FILE6, KeyboardInput(WXK_F6, wxMOD_CMD)}, + {wxID_FILE7, KeyboardInput(WXK_F7, wxMOD_CMD)}, + {wxID_FILE8, KeyboardInput(WXK_F8, wxMOD_CMD)}, + {wxID_FILE9, KeyboardInput(WXK_F9, wxMOD_CMD)}, + {wxID_FILE10, KeyboardInput(WXK_F10, wxMOD_CMD)}, + {XRCID("VideoLayersReset"), KeyboardInput('0', wxMOD_CMD)}, + {XRCID("ChangeFilter"), KeyboardInput('G', wxMOD_CMD)}, + {XRCID("ChangeIFB"), KeyboardInput('I', wxMOD_CMD)}, + {XRCID("IncreaseVolume"), KeyboardInput(WXK_NUMPAD_ADD, wxMOD_NONE)}, + {XRCID("DecreaseVolume"), KeyboardInput(WXK_NUMPAD_SUBTRACT, wxMOD_NONE)}, + {XRCID("ToggleSound"), KeyboardInput(WXK_NUMPAD_ENTER, wxMOD_NONE)}, }; return kDefaultShortcuts; } diff --git a/src/wx/config/shortcuts.cpp b/src/wx/config/shortcuts.cpp index f83af6d7..bebe5adf 100644 --- a/src/wx/config/shortcuts.cpp +++ b/src/wx/config/shortcuts.cpp @@ -40,7 +40,7 @@ std::vector> Shortcuts::GetConfiguration() const { config.reserve(command_to_inputs_.size() + 1); if (!disabled_defaults_.empty()) { - std::set noop_inputs; + std::unordered_set noop_inputs; for (const auto& iter : disabled_defaults_) { noop_inputs.insert(iter.first); } @@ -48,7 +48,7 @@ std::vector> Shortcuts::GetConfiguration() const { } for (const auto& iter : command_to_inputs_) { - std::set inputs; + std::unordered_set inputs; for (const auto& input : iter.second) { if (internal::DefaultShortcutForCommand(iter.first) != input) { // Not a default input. diff --git a/src/wx/config/user-input.cpp b/src/wx/config/user-input.cpp index 84c3c023..c9278112 100644 --- a/src/wx/config/user-input.cpp +++ b/src/wx/config/user-input.cpp @@ -109,52 +109,6 @@ wxString ModToLocalizedString(int mod) { return config_string; } -wxString KeyboardInputToConfigString(int mod, int key) { - // Handle the modifier case separately. - if (KeyIsModifier(key)) { - return wxString::Format("%d:%d", key, mod); - } - - // Custom overrides. - const auto iter = kKeyCodeOverrides.find(static_cast(key)); - if (iter != kKeyCodeOverrides.end()) { - return ModToConfigString(mod) + iter->second.config_name; - } - - const wxString accel_string = wxAcceleratorEntry(mod, key).ToRawString().MakeUpper(); - if (!accel_string.IsAscii()) { - // Unicode handling. - return wxString::Format("%d:%d", key, mod); - } - return accel_string; -} - -wxString KeyboardInputToLocalizedString(int mod, int key) { - static const std::map kStandaloneModifiers = { - {WXK_ALT, _("Alt")}, - {WXK_SHIFT, _("Shift")}, -#ifdef __WXMAC__ - {WXK_RAW_CONTROL, _("Ctrl")}, - {WXK_COMMAND, _("Cmd")}, -#else - {WXK_CONTROL, _("Ctrl")}, -#endif - }; - - const auto iter = kStandaloneModifiers.find(key); - if (iter != kStandaloneModifiers.end()) { - return iter->second; - } - - // Custom overrides. - const auto iter2 = kKeyCodeOverrides.find(static_cast(key)); - if (iter2 != kKeyCodeOverrides.end()) { - return ModToLocalizedString(mod) + iter2->second.display_name; - } - - return wxAcceleratorEntry(mod, key).ToString(); -} - int StringToInt(const wxString& string) { int ret = 0; for (const auto& c : string) { @@ -178,14 +132,14 @@ UserInput StringToUserInput(const wxString& string) { // Standalone modifiers do not get parsed properly by wxWidgets. static const std::map kStandaloneModifiers = { - {"ALT", UserInput(WXK_ALT, wxMOD_ALT)}, - {"SHIFT", UserInput(WXK_SHIFT, wxMOD_SHIFT)}, - {"RAWCTRL", UserInput(WXK_RAW_CONTROL, wxMOD_RAW_CONTROL)}, - {"RAW_CTRL", UserInput(WXK_RAW_CONTROL, wxMOD_RAW_CONTROL)}, - {"RAWCONTROL", UserInput(WXK_RAW_CONTROL, wxMOD_RAW_CONTROL)}, - {"RAW_CONTROL", UserInput(WXK_RAW_CONTROL, wxMOD_RAW_CONTROL)}, - {"CTRL", UserInput(WXK_CONTROL, wxMOD_CONTROL)}, - {"CONTROL", UserInput(WXK_CONTROL, wxMOD_CONTROL)}, + {"ALT", KeyboardInput(WXK_ALT, wxMOD_ALT)}, + {"SHIFT", KeyboardInput(WXK_SHIFT, wxMOD_SHIFT)}, + {"RAWCTRL", KeyboardInput(WXK_RAW_CONTROL, wxMOD_RAW_CONTROL)}, + {"RAW_CTRL", KeyboardInput(WXK_RAW_CONTROL, wxMOD_RAW_CONTROL)}, + {"RAWCONTROL", KeyboardInput(WXK_RAW_CONTROL, wxMOD_RAW_CONTROL)}, + {"RAW_CONTROL", KeyboardInput(WXK_RAW_CONTROL, wxMOD_RAW_CONTROL)}, + {"CTRL", KeyboardInput(WXK_CONTROL, wxMOD_CONTROL)}, + {"CONTROL", KeyboardInput(WXK_CONTROL, wxMOD_CONTROL)}, }; if (string.empty()) { @@ -197,30 +151,31 @@ UserInput StringToUserInput(const wxString& string) { size_t start, length; kJoyRegex.GetMatch(&start, &length, 1); const int joy = StringToInt(string.Mid(start, length)); + const JoyId joy_id(joy - 1); const wxString remainder = string.Mid(start + length + 1); if (kAxisRegex.Matches(remainder)) { kAxisRegex.GetMatch(&start, &length, 1); const int key = StringToInt(remainder.Mid(start, length)); const JoyControl control = remainder[start + length] == '+' ? JoyControl::AxisPlus : JoyControl::AxisMinus; - return UserInput(key, control, JoyId(joy - 1)); + return JoyInput(joy_id, control, key); } if (kButtonRegex.Matches(remainder)) { kButtonRegex.GetMatch(&start, &length, 1); const int key = StringToInt(remainder.Mid(start, length)); - return UserInput(key, JoyControl::Button, JoyId(joy - 1)); + return JoyInput(joy_id, JoyControl::Button, key); } if (kHatRegex.Matches(remainder)) { kHatRegex.GetMatch(&start, &length, 1); const int key = StringToInt(remainder.Mid(start, length)); if (kHatRegex.GetMatch(remainder, 3).Length()) { - return UserInput(key, JoyControl::HatNorth, JoyId(joy - 1)); + return JoyInput(joy_id, JoyControl::HatNorth, key); } else if (kHatRegex.GetMatch(remainder, 4).Length()) { - return UserInput(key, JoyControl::HatSouth, JoyId(joy - 1)); + return JoyInput(joy_id, JoyControl::HatSouth, key); } else if (kHatRegex.GetMatch(remainder, 5).Length()) { - return UserInput(key, JoyControl::HatEast, JoyId(joy - 1)); + return JoyInput(joy_id, JoyControl::HatEast, key); } else if (kHatRegex.GetMatch(remainder, 6).Length()) { - return UserInput(key, JoyControl::HatWest, JoyId(joy - 1)); + return JoyInput(joy_id, JoyControl::HatWest, key); } } @@ -230,11 +185,13 @@ UserInput StringToUserInput(const wxString& string) { // Not a joystick. + // Non-ASCII keyboard input are treated as a pair of integers "key:mod". const auto pair = strutils::split(string, ":"); - long mod, key; + long mod = 0; + long key = 0; if (pair.size() == 2 && pair[0].ToLong(&key) && pair[1].ToLong(&mod)) { // Pair of integers, likely a unicode input. - return UserInput(key, mod); + return KeyboardInput(static_cast(key), static_cast(mod)); } wxString upper(string); @@ -257,7 +214,8 @@ UserInput StringToUserInput(const wxString& string) { if (key < WXK_START && wxIslower(key)) { key = wxToupper(key); } - return UserInput(key, accel.GetFlags()); + return KeyboardInput(static_cast(key), + static_cast(accel.GetFlags())); } // Invalid. @@ -272,45 +230,77 @@ JoyId JoyId::Invalid() { return JoyId(kInvalidSdlIndex); } -wxString JoyId::ToString() { +wxString JoyId::ToString() const { return wxString::Format("Joy%d", sdl_index_ + 1); } -bool JoyId::operator==(const JoyId& other) const { - return sdl_index_ == other.sdl_index_; -} -bool JoyId::operator!=(const JoyId& other) const { - return !(*this == other); -} -bool JoyId::operator<(const JoyId& other) const { - return sdl_index_ < other.sdl_index_; -} -bool JoyId::operator<=(const JoyId& other) const { - return !(*this > other); -} -bool JoyId::operator>(const JoyId& other) const { - return other < *this; -} -bool JoyId::operator>=(const JoyId& other) const { - return !(*this < other); +wxString JoyInput::ToString() const { + const wxString joy_string = joy_.ToString(); + switch (control_) { + case JoyControl::AxisPlus: + return wxString::Format("%s-Axis%d+", joy_string, control_index_); + case JoyControl::AxisMinus: + return wxString::Format("%s-Axis%d-", joy_string, control_index_); + case JoyControl::Button: + return wxString::Format("%s-Button%d", joy_string, control_index_); + case JoyControl::HatNorth: + return wxString::Format("%s-Hat%dN", joy_string, control_index_); + case JoyControl::HatSouth: + return wxString::Format("%s-Hat%dS", joy_string, control_index_); + case JoyControl::HatWest: + return wxString::Format("%s-Hat%dW", joy_string, control_index_); + case JoyControl::HatEast: + return wxString::Format("%s-Hat%dE", joy_string, control_index_); + } + + // Unreachable. + assert(false); + return wxEmptyString; } -JoyId::JoyId(int sdl_index) : sdl_index_(sdl_index) {} +wxString KeyboardInput::ToConfigString() const { + // Handle the modifier case separately. + if (KeyIsModifier(key_)) { + return wxString::Format("%d:%d", key_, mod_); + } -UserInput::UserInput(uint8_t control_index, JoyControl control, JoyId joystick) - : UserInput(Device::Joystick, - static_cast(control), - control_index, - joystick.sdl_index_ + 1) {} + // Custom overrides. + const auto iter = kKeyCodeOverrides.find(key_); + if (iter != kKeyCodeOverrides.end()) { + return ModToConfigString(mod_) + iter->second.config_name; + } -UserInput::UserInput(wxKeyCode key, wxKeyModifier mod) - : UserInput(Device::Keyboard, mod, key, 0) {} + const wxString accel_string = wxAcceleratorEntry(mod_, key_).ToRawString().MakeUpper(); + if (!accel_string.IsAscii()) { + // Unicode handling. + return wxString::Format("%d:%d", key_, mod_); + } + return accel_string; +} -UserInput::UserInput(char c, wxKeyModifier mod) : UserInput(Device::Keyboard, mod, c, 0) {} +wxString KeyboardInput::ToLocalizedString() const { + // Handle the modifier case separately. + if (KeyIsModifier(key_)) { + return ModToLocalizedString(mod_) + _("Key"); + } + + // Custom overrides. + const auto iter = kKeyCodeOverrides.find(key_); + if (iter != kKeyCodeOverrides.end()) { + return ModToLocalizedString(mod_) + iter->second.display_name; + } + + const wxString accel_string = wxAcceleratorEntry(mod_, key_).ToRawString().MakeUpper(); + if (!accel_string.IsAscii()) { + // Unicode handling. + return wxString::Format("%d:%d", key_, mod_); + } + return accel_string; +} // static -std::set UserInput::FromConfigString(const wxString& string) { - std::set user_inputs; +std::unordered_set UserInput::FromConfigString(const wxString& string) { + std::unordered_set user_inputs; if (string.empty()) { return user_inputs; @@ -328,7 +318,7 @@ std::set UserInput::FromConfigString(const wxString& string) { } // static -wxString UserInput::SpanToConfigString(const std::set& user_inputs) { +wxString UserInput::SpanToConfigString(const std::unordered_set& user_inputs) { wxString config_string; if (user_inputs.empty()) { return config_string; @@ -344,34 +334,9 @@ wxString UserInput::ToConfigString() const { case Device::Invalid: return wxEmptyString; case Device::Keyboard: - return KeyboardInputToConfigString(mod_, key_); + return keyboard_input().ToConfigString(); case Device::Joystick: - wxString key; - switch (static_cast(mod_)) { - case JoyControl::AxisPlus: - key = wxString::Format(("Axis%d+"), key_); - break; - case JoyControl::AxisMinus: - key = wxString::Format(("Axis%d-"), key_); - break; - case JoyControl::Button: - key = wxString::Format(("Button%d"), key_); - break; - case JoyControl::HatNorth: - key = wxString::Format(("Hat%dN"), key_); - break; - case JoyControl::HatSouth: - key = wxString::Format(("Hat%dS"), key_); - break; - case JoyControl::HatWest: - key = wxString::Format(("Hat%dW"), key_); - break; - case JoyControl::HatEast: - key = wxString::Format(("Hat%dE"), key_); - break; - } - - return wxString::Format("Joy%d-%s", joy_, key); + return joy_input().ToString(); } // Unreachable. @@ -384,10 +349,9 @@ wxString UserInput::ToLocalizedString() const { case Device::Invalid: return wxEmptyString; case Device::Keyboard: - return KeyboardInputToLocalizedString(mod_, key_); + return keyboard_input().ToLocalizedString(); case Device::Joystick: - // Same as Config string. - return ToConfigString(); + return joy_input().ToString(); } // Unreachable. diff --git a/src/wx/config/user-input.h b/src/wx/config/user-input.h index 284d1566..41fa2c79 100644 --- a/src/wx/config/user-input.h +++ b/src/wx/config/user-input.h @@ -1,17 +1,53 @@ #ifndef VBAM_WX_CONFIG_USER_INPUT_H_ #define VBAM_WX_CONFIG_USER_INPUT_H_ +#include #include -#include +#include + +#include -#include -#include #include namespace config { -// Forward declaration. -class UserInput; +// Abstract representation of a keyboard input. This class is used to represent +// a key press or release event. It is used in the configuration system to +// represent a key binding. +class KeyboardInput final { +public: + constexpr explicit KeyboardInput(wxKeyCode key, wxKeyModifier mod = wxMOD_NONE) + : key_(key), mod_(mod) {} + constexpr explicit KeyboardInput(char c, wxKeyModifier mod = wxMOD_NONE) + : key_(static_cast(c)), mod_(mod) {} + + ~KeyboardInput() = default; + + constexpr wxKeyCode key() const { return key_; } + constexpr wxKeyModifier mod() const { return mod_; } + + wxString ToConfigString() const; + wxString ToLocalizedString() const; + + bool operator==(const KeyboardInput& other) const { + return key_ == other.key_ && mod_ == other.mod_; + } + bool operator!=(const KeyboardInput& other) const { return !(*this == other); } + bool operator<(const KeyboardInput& other) const { + if (key_ == other.key_) { + return mod_ < other.mod_; + } else { + return key_ < other.key_; + } + } + bool operator<=(const KeyboardInput& other) const { return *this < other || *this == other; } + bool operator>(const KeyboardInput& other) const { return !(*this <= other); } + bool operator>=(const KeyboardInput& other) const { return !(*this < other); } + +private: + const wxKeyCode key_; + const wxKeyModifier mod_; +}; // One of the possible joystick controls. enum class JoyControl { @@ -27,146 +63,192 @@ enum class JoyControl { // Abstraction for a single joystick. In the current implementation, this // encapsulates an `sdl_index_`. -class JoyId { +class JoyId final { public: static JoyId Invalid(); - explicit JoyId(int sdl_index); - virtual ~JoyId() = default; + constexpr explicit JoyId(int sdl_index) : sdl_index_(sdl_index){}; + ~JoyId() = default; - wxString ToString(); + wxString ToString() const; - bool operator==(const JoyId& other) const; - bool operator!=(const JoyId& other) const; - bool operator<(const JoyId& other) const; - bool operator<=(const JoyId& other) const; - bool operator>(const JoyId& other) const; - bool operator>=(const JoyId& other) const; + constexpr bool operator==(const JoyId& other) const { return sdl_index_ == other.sdl_index_; } + constexpr bool operator!=(const JoyId& other) const { return sdl_index_ != other.sdl_index_; } + constexpr bool operator<(const JoyId& other) const { return sdl_index_ < other.sdl_index_; } + constexpr bool operator<=(const JoyId& other) const { return sdl_index_ <= other.sdl_index_; } + constexpr bool operator>(const JoyId& other) const { return sdl_index_ > other.sdl_index_; } + constexpr bool operator>=(const JoyId& other) const { return sdl_index_ >= other.sdl_index_; } private: JoyId() = delete; - int sdl_index_; + const int sdl_index_; - friend class UserInput; + friend struct std::hash; +}; + +// Abstraction for a joystick input. This class is used to represent a joystick +// control press or release event. It is used in the configuration system to +// represent a joystick binding. +class JoyInput final { +public: + constexpr JoyInput(JoyId joy, JoyControl control, uint8_t control_index) + : joy_(joy), control_(control), control_index_(control_index) {} + ~JoyInput() = default; + + constexpr JoyId joy() const { return joy_; } + constexpr JoyControl control() const { return control_; } + constexpr uint8_t control_index() const { return control_index_; } + + wxString ToString() const; + + constexpr bool operator==(const JoyInput& other) const { + return joy_ == other.joy_ && control_ == other.control_ && + control_index_ == other.control_index_; + } + constexpr bool operator!=(const JoyInput& other) const { return !(*this == other); } + constexpr bool operator<(const JoyInput& other) const { + if (joy_ == other.joy_) { + if (control_ == other.control_) { + return control_index_ < other.control_index_; + } else { + return control_ < other.control_; + } + } else { + return joy_ < other.joy_; + } + } + constexpr bool operator<=(const JoyInput& other) const { + return *this < other || *this == other; + } + constexpr bool operator>(const JoyInput& other) const { return !(*this <= other); } + constexpr bool operator>=(const JoyInput& other) const { return !(*this < other); } + +private: + const JoyId joy_; + const JoyControl control_; + const uint8_t control_index_; }; // Abstraction for a user input, which can come from a keyboard or a joystick. -// This class implements comparison operators so it can be used in sets and as -// a key in maps. -// -// TODO: Right now, this class is implemented as a thin wrapper around the key, -// mod and joy user input representation used in many places in the code base. -// This is to ease a transition away from the key, mod, joy triplet, which -// UserInput will eventually replace. +// TODO: Most of these methods should be constexpr but nonstd::variant is not. class UserInput { public: // The device type for a user control. enum class Device { Invalid = 0, Keyboard, Joystick, Last = Joystick }; // Constructor from a configuration string. Returns empty set on failure. - static std::set FromConfigString(const wxString& string); + static std::unordered_set FromConfigString(const wxString& string); // Converts a set of UserInput into a configuration string. This // recomputes the configuration string every time and should not be used // for comparison purposes. - // TODO: Replace std::set with std::span when the code base uses C++20. - static wxString SpanToConfigString(const std::set& user_inputs); + // TODO: Replace std::unordered_set with std::span when the code base uses C++20. + static wxString SpanToConfigString(const std::unordered_set& user_inputs); // Invalid UserInput, mainly used for comparison. - UserInput() : UserInput(Device::Invalid, 0, 0, 0) {} + UserInput() : device_(Device::Invalid), input_(nonstd::monostate{}) {} - // Constructor for a joystick input. - UserInput(uint8_t control_index, JoyControl control, JoyId joystick); - - // Constructors for a keyboard input. - UserInput(wxKeyCode key, wxKeyModifier mod = wxMOD_NONE); - UserInput(char c, wxKeyModifier mod = wxMOD_NONE); - - // TODO: Remove this once all uses have been removed. - explicit UserInput(int key, int mod = 0, int joy = 0) - : UserInput(joy == 0 ? Device::Keyboard : Device::Joystick, - mod, - key, - joy) {} + // Constructors for joystick and keyboard inputs. This object can be + // implicitly constructed from JoyInput and KeyboardInput. + UserInput(JoyInput joy_input) : device_(Device::Joystick), input_(joy_input) {} + UserInput(KeyboardInput keyboard_input) + : device_(Device::Keyboard), input_(keyboard_input) {} Device device() const { return device_; } + const KeyboardInput& keyboard_input() const { + assert(is_keyboard()); + return nonstd::get(input_); + }; + + const JoyInput& joy_input() const { + assert(is_joystick()); + return nonstd::get(input_); + }; + + bool is_valid() const { return device_ != Device::Invalid; } + operator bool() const { return is_valid(); } + + bool is_keyboard() const { return device_ == Device::Keyboard; } + bool is_joystick() const { return device_ == Device::Joystick; } + // Converts to a configuration string for saving. wxString ToConfigString() const; // Converts to a localized string for display. wxString ToLocalizedString() const; - JoyId joystick() const { return joystick_; } - constexpr bool is_valid() const { return device_ != Device::Invalid; } - constexpr operator bool() const { return is_valid(); } - - bool is_joystick() const { return device_ == Device::Joystick; } - bool is_keyboard() const { return device_ == Device::Keyboard; } - - int key() const { return key_; } - int mod() const { return mod_; } - unsigned joy() const { return joy_; } - - JoyControl joy_control() const { - assert(is_joystick()); - return static_cast(mod_); + // Comparison operators. + bool operator==(const UserInput& other) const { + return device_ == other.device_ && input_ == other.input_; } - - wxKeyCode key_code() const { - assert(is_keyboard()); - return static_cast(key_); - } - - constexpr bool operator==(const UserInput& other) const { - return device_ == other.device_ && mod_ == other.mod_ && - key_ == other.key_ && joy_ == other.joy_; - } - constexpr bool operator!=(const UserInput& other) const { - return !(*this == other); - } - constexpr bool operator<(const UserInput& other) const { - if (device_ < other.device_) { + bool operator!=(const UserInput& other) const { return !(*this == other); } + bool operator<(const UserInput& other) const { + if (device_ == other.device_) { + return input_ < other.input_; + } else { return device_ < other.device_; } - if (joy_ != other.joy_) { - return joy_ < other.joy_; - } - if (key_ != other.key_) { - return key_ < other.key_; - } - if (mod_ != other.mod_) { - return mod_ < other.mod_; - } - return false; } - constexpr bool operator<=(const UserInput& other) const { - return !(*this > other); - } - constexpr bool operator>(const UserInput& other) const { - return other < *this; - } - constexpr bool operator>=(const UserInput& other) const { - return !(*this < other); + bool operator<=(const UserInput& other) const { + return *this < other || *this == other; } + bool operator>(const UserInput& other) const { return !(*this <= other); } + bool operator>=(const UserInput& other) const { return !(*this < other); } private: - UserInput(Device device, int mod, int key, unsigned joy) - : device_(device), - joystick_(joy == 0 ? JoyId::Invalid() - : JoyId(joy - 1)), - mod_(mod), - key_(key), - joy_(joy) {} - - Device device_; - JoyId joystick_; - int mod_; - int key_; - unsigned joy_; + const Device device_; + const nonstd::variant input_; }; } // namespace config +// Specializations for hash functions for all of the above classes. +template <> +struct std::hash { + std::size_t operator()(config::JoyId const& joy_id) const noexcept { + return std::hash{}(joy_id.sdl_index_); + } +}; + +template <> +struct std::hash { + std::size_t operator()(config::JoyInput const& joy_input) const noexcept { + const std::size_t hash1 = std::hash{}(joy_input.joy()); + const std::size_t hash2 = std::hash{}(static_cast(joy_input.control())); + const std::size_t hash3 = std::hash{}(joy_input.control_index()); + return hash1 ^ hash2 ^ hash3; + } +}; + +template <> +struct std::hash { + std::size_t operator()(config::KeyboardInput const& keyboard_input) const noexcept { + const std::size_t hash1 = std::hash{}(keyboard_input.key()); + const std::size_t hash2 = std::hash{}(keyboard_input.mod()); + return hash1 ^ hash2; + } +}; + +template <> +struct std::hash { + std::size_t operator()(config::UserInput const& user_input) const noexcept { + const std::size_t device_hash = std::hash{}(static_cast(user_input.device())); + switch (user_input.device()) { + case config::UserInput::Device::Invalid: + return device_hash; + case config::UserInput::Device::Joystick: + return device_hash ^ std::hash{}(user_input.joy_input()); + case config::UserInput::Device::Keyboard: + return device_hash ^ + std::hash{}(user_input.keyboard_input()); + } + + // Unreachable. + assert(false); + return 0; + } +}; + #endif // VBAM_WX_CONFIG_USER_INPUT_H_ diff --git a/src/wx/opts.cpp b/src/wx/opts.cpp index bca1beb9..fefa1f43 100644 --- a/src/wx/opts.cpp +++ b/src/wx/opts.cpp @@ -107,68 +107,68 @@ uint32_t LoadUnsignedOption(wxConfigBase* cfg, opts_t gopts; -const std::map> kDefaultBindings = { +const std::map> kDefaultBindings = { {config::GameControl(0, config::GameKey::Up), { - config::UserInput('W'), - config::UserInput(11, config::JoyControl::Button, config::JoyId(0)), - config::UserInput(1, config::JoyControl::AxisMinus, config::JoyId(0)), - config::UserInput(3, config::JoyControl::AxisMinus, config::JoyId(0)), + config::KeyboardInput('W'), + config::JoyInput(config::JoyId(0), config::JoyControl::Button, 11), + config::JoyInput(config::JoyId(0), config::JoyControl::AxisMinus, 1), + config::JoyInput(config::JoyId(0), config::JoyControl::AxisMinus, 3), }}, {config::GameControl(0, config::GameKey::Down), { - config::UserInput('S'), - config::UserInput(12, config::JoyControl::Button, config::JoyId(0)), - config::UserInput(1, config::JoyControl::AxisPlus, config::JoyId(0)), - config::UserInput(3, config::JoyControl::AxisPlus, config::JoyId(0)), + config::KeyboardInput('S'), + config::JoyInput(config::JoyId(0), config::JoyControl::Button, 12), + config::JoyInput(config::JoyId(0), config::JoyControl::AxisPlus, 1), + config::JoyInput(config::JoyId(0), config::JoyControl::AxisPlus, 3), }}, {config::GameControl(0, config::GameKey::Left), { - config::UserInput('A'), - config::UserInput(13, config::JoyControl::Button, config::JoyId(0)), - config::UserInput(0, config::JoyControl::AxisMinus, config::JoyId(0)), - config::UserInput(2, config::JoyControl::AxisMinus, config::JoyId(0)), + config::KeyboardInput('A'), + config::JoyInput(config::JoyId(0), config::JoyControl::Button, 13), + config::JoyInput(config::JoyId(0), config::JoyControl::AxisMinus, 0), + config::JoyInput(config::JoyId(0), config::JoyControl::AxisMinus, 2), }}, {config::GameControl(0, config::GameKey::Right), { - config::UserInput('D'), - config::UserInput(14, config::JoyControl::Button, config::JoyId(0)), - config::UserInput(0, config::JoyControl::AxisPlus, config::JoyId(0)), - config::UserInput(2, config::JoyControl::AxisPlus, config::JoyId(0)), + config::KeyboardInput('D'), + config::JoyInput(config::JoyId(0), config::JoyControl::Button, 14), + config::JoyInput(config::JoyId(0), config::JoyControl::AxisPlus, 0), + config::JoyInput(config::JoyId(0), config::JoyControl::AxisPlus, 2), }}, {config::GameControl(0, config::GameKey::A), { - config::UserInput('L'), - config::UserInput(0, config::JoyControl::Button, config::JoyId(0)), + config::KeyboardInput('L'), + config::JoyInput(config::JoyId(0), config::JoyControl::Button, 0), }}, {config::GameControl(0, config::GameKey::B), { - config::UserInput('K'), - config::UserInput(1, config::JoyControl::Button, config::JoyId(0)), + config::KeyboardInput('K'), + config::JoyInput(config::JoyId(0), config::JoyControl::Button, 1), }}, {config::GameControl(0, config::GameKey::L), { - config::UserInput('I'), - config::UserInput(2, config::JoyControl::Button, config::JoyId(0)), - config::UserInput(9, config::JoyControl::Button, config::JoyId(0)), - config::UserInput(4, config::JoyControl::AxisPlus, config::JoyId(0)), + config::KeyboardInput('I'), + config::JoyInput(config::JoyId(0), config::JoyControl::Button, 2), + config::JoyInput(config::JoyId(0), config::JoyControl::Button, 9), + config::JoyInput(config::JoyId(0), config::JoyControl::AxisPlus, 4), }}, {config::GameControl(0, config::GameKey::R), { - config::UserInput('O'), - config::UserInput(3, config::JoyControl::Button, config::JoyId(0)), - config::UserInput(10, config::JoyControl::Button, config::JoyId(0)), - config::UserInput(5, config::JoyControl::AxisPlus, config::JoyId(0)), + config::KeyboardInput('O'), + config::JoyInput(config::JoyId(0), config::JoyControl::Button, 3), + config::JoyInput(config::JoyId(0), config::JoyControl::Button, 10), + config::JoyInput(config::JoyId(0), config::JoyControl::AxisPlus, 5), }}, {config::GameControl(0, config::GameKey::Select), { - config::UserInput(WXK_BACK), - config::UserInput(4, config::JoyControl::Button, config::JoyId(0)), + config::KeyboardInput(WXK_BACK), + config::JoyInput(config::JoyId(0), config::JoyControl::Button, 4), }}, {config::GameControl(0, config::GameKey::Start), { - config::UserInput(WXK_RETURN), - config::UserInput(6, config::JoyControl::Button, config::JoyId(0)), + config::KeyboardInput(WXK_RETURN), + config::JoyInput(config::JoyId(0), config::JoyControl::Button, 6), }}, {config::GameControl(0, config::GameKey::MotionUp), {}}, {config::GameControl(0, config::GameKey::MotionDown), {}}, @@ -180,7 +180,7 @@ const std::map> kDefaultBinding {config::GameControl(0, config::GameKey::AutoB), {}}, {config::GameControl(0, config::GameKey::Speed), { - config::UserInput(WXK_SPACE), + config::KeyboardInput(WXK_SPACE), }}, {config::GameControl(0, config::GameKey::Capture), {}}, {config::GameControl(0, config::GameKey::Gameshark), {}}, @@ -562,14 +562,11 @@ void update_opts() { void update_joypad_opts() { wxConfigBase* cfg = wxConfigBase::Get(); - // For joypad, compare the UserInput sets. Since UserInput guarantees a - // certain ordering, it is possible that the user control in the panel shows - // a different ordering than the one that will be eventually saved, but this - // is nothing to worry about. + // For joypad, compare the UserInput sets. bool game_bindings_changed = false; for (const auto &iter : gopts.game_control_bindings) { wxString option_name = iter.first.ToString(); - std::set saved_config = + std::unordered_set saved_config = config::UserInput::FromConfigString(cfg->Read(option_name, "")); if (saved_config != iter.second) { game_bindings_changed = true; diff --git a/src/wx/opts.h b/src/wx/opts.h index 7688e36b..a538c0c0 100644 --- a/src/wx/opts.h +++ b/src/wx/opts.h @@ -14,7 +14,7 @@ class wxFileHistory; // Default joystick bindings. -extern const std::map> +extern const std::map> kDefaultBindings; extern struct opts_t { @@ -36,7 +36,7 @@ extern struct opts_t { int rewind_interval = 0; /// Joypad - std::map> + std::map> game_control_bindings; int autofire_rate = 1; diff --git a/src/wx/widgets/sdl-poller.cpp b/src/wx/widgets/sdl-poller.cpp index f85ff350..9f7031d9 100644 --- a/src/wx/widgets/sdl-poller.cpp +++ b/src/wx/widgets/sdl-poller.cpp @@ -208,8 +208,7 @@ std::vector JoyState::ProcessAxisEvent(const uint8_t index, if (previous_status != JoyAxisStatus::Neutral) { // Send the "unpressed" event. events.push_back(UserInputEvent( - config::UserInput(index, AxisStatusToJoyControl(previous_status), wx_joystick_), - false)); + config::JoyInput(wx_joystick_, AxisStatusToJoyControl(previous_status), index), false)); } // We already sent the "unpressed" event so nothing more to do. @@ -219,7 +218,7 @@ std::vector JoyState::ProcessAxisEvent(const uint8_t index, // Send the "pressed" event. events.push_back(UserInputEvent( - config::UserInput(index, AxisStatusToJoyControl(status), wx_joystick_), true)); + config::JoyInput(wx_joystick_, AxisStatusToJoyControl(status), index), true)); return events; } @@ -238,7 +237,7 @@ std::vector JoyState::ProcessButtonEvent(const uint8_t index, co // Send the event. events.push_back( - UserInputEvent(config::UserInput(index, config::JoyControl::Button, wx_joystick_), status)); + UserInputEvent(config::JoyInput(wx_joystick_, config::JoyControl::Button, index), status)); return events; } @@ -264,12 +263,12 @@ std::vector JoyState::ProcessHatEvent(const uint8_t index, const if (old_control_pressed && !new_control_pressed) { // Send the "unpressed" event. events.push_back(UserInputEvent( - config::UserInput(index, HatStatusToJoyControl(bit), wx_joystick_), false)); + config::JoyInput(wx_joystick_, HatStatusToJoyControl(bit), index), false)); } if (!old_control_pressed && new_control_pressed) { // Send the "pressed" event. events.push_back(UserInputEvent( - config::UserInput(index, HatStatusToJoyControl(bit), wx_joystick_), true)); + config::JoyInput(wx_joystick_, HatStatusToJoyControl(bit), index), true)); } } diff --git a/src/wx/widgets/user-input-ctrl.cpp b/src/wx/widgets/user-input-ctrl.cpp index 9af57691..e4007e1e 100644 --- a/src/wx/widgets/user-input-ctrl.cpp +++ b/src/wx/widgets/user-input-ctrl.cpp @@ -46,8 +46,9 @@ void UserInputCtrl::SetMultiKey(bool multikey) { Clear(); } -void UserInputCtrl::SetInputs(const std::set& inputs) { - inputs_ = inputs; +void UserInputCtrl::SetInputs(const std::unordered_set& inputs) { + inputs_.clear(); + inputs_.insert(inputs.begin(), inputs.end()); UpdateText(); } @@ -126,7 +127,7 @@ bool UserInputCtrlValidator::TransferFromWindow() { UserInputCtrl* control = wxDynamicCast(GetWindow(), UserInputCtrl); assert(control); - gopts.game_control_bindings[game_control_] = control->inputs(); + gopts.game_control_bindings.insert({game_control_, control->inputs()}); return true; } diff --git a/src/wx/widgets/user-input-ctrl.h b/src/wx/widgets/user-input-ctrl.h index aa046845..813751a1 100644 --- a/src/wx/widgets/user-input-ctrl.h +++ b/src/wx/widgets/user-input-ctrl.h @@ -1,7 +1,7 @@ #ifndef VBAM_WX_WIDGETS_USER_INPUT_CTRL_H_ #define VBAM_WX_WIDGETS_USER_INPUT_CTRL_H_ -#include +#include #include #include @@ -46,7 +46,7 @@ public: void SetMultiKey(bool multikey); // Sets this control inputs. - void SetInputs(const std::set& inputs); + void SetInputs(const std::unordered_set& inputs); // Helper method to return the single input for no multikey UserInputCtrls. // Asserts if `is_multikey_` is true. @@ -54,7 +54,7 @@ public: config::UserInput SingleInput() const; // Returns the inputs set in this control. - const std::set& inputs() const { return inputs_; } + const std::unordered_set& inputs() const { return inputs_; } // Clears the inputs set in this control. void Clear() override; @@ -78,7 +78,7 @@ private: // subsequent events until the control is focused again. bool is_navigating_away_ = false; - std::set inputs_; + std::unordered_set inputs_; }; // A validator for the UserInputCtrl. This validator is used to transfer the diff --git a/src/wx/widgets/user-input-event.cpp b/src/wx/widgets/user-input-event.cpp index ebc1b6ca..db739f79 100644 --- a/src/wx/widgets/user-input-event.cpp +++ b/src/wx/widgets/user-input-event.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include "wx/config/user-input.h" @@ -162,7 +161,7 @@ void UserInputEventSender::OnKeyDown(wxKeyEvent& event) { } const wxKeyModifier active_mods = GetModifiersFromSet(active_mods_); - std::vector new_inputs; + std::vector new_inputs; if (key_pressed == WXK_NONE) { // A new standalone modifier was pressed, send the event. new_inputs.emplace_back(KeyFromModifier(mod_pressed), mod_pressed); @@ -179,7 +178,7 @@ void UserInputEventSender::OnKeyDown(wxKeyEvent& event) { } } - for (const config::UserInput& input : new_inputs) { + for (const config::KeyboardInput& input : new_inputs) { wxQueueEvent(window_, new UserInputEvent(input, true)); } } @@ -221,7 +220,7 @@ void UserInputEventSender::OnKeyUp(wxKeyEvent& event) { return; } - std::vector released_inputs; + std::vector released_inputs; if (key_released == WXK_NONE) { // A standalone modifier was released, send it. released_inputs.emplace_back(KeyFromModifier(mod_released), mod_released); @@ -232,7 +231,7 @@ void UserInputEventSender::OnKeyUp(wxKeyEvent& event) { released_inputs.emplace_back(key, wxMOD_NONE); } else { // Check if the key was pressed with the active modifiers. - const config::UserInput input_with_modifiers(key, previous_mods); + const config::KeyboardInput input_with_modifiers(key, previous_mods); auto iter = active_mod_inputs_.find(input_with_modifiers); if (iter == active_mod_inputs_.end()) { // The key press event was never sent, so do it now. @@ -252,7 +251,7 @@ void UserInputEventSender::OnKeyUp(wxKeyEvent& event) { // Also check for any key that were pressed with the previously active // modifiers and release them. for (const wxKeyCode active_key : active_keys_) { - const config::UserInput input(active_key, previous_mods); + const config::KeyboardInput input(active_key, previous_mods); auto iter = active_mod_inputs_.find(input); if (iter != active_mod_inputs_.end()) { active_mod_inputs_.erase(iter); @@ -261,7 +260,7 @@ void UserInputEventSender::OnKeyUp(wxKeyEvent& event) { } - for (const config::UserInput& input : released_inputs) { + for (const config::KeyboardInput& input : released_inputs) { active_mod_inputs_.erase(input); wxQueueEvent(window_, new UserInputEvent(input, false)); } diff --git a/src/wx/widgets/user-input-event.h b/src/wx/widgets/user-input-event.h index ef2e51cc..f916294a 100644 --- a/src/wx/widgets/user-input-event.h +++ b/src/wx/widgets/user-input-event.h @@ -50,7 +50,7 @@ private: std::unordered_set active_keys_; std::unordered_set active_mods_; - std::set active_mod_inputs_; + std::unordered_set active_mod_inputs_; // The wxWindow this object is attached to. // Must outlive this object. diff --git a/src/wx/wxlogdebug.h b/src/wx/wxlogdebug.h index e905a536..bd0e006d 100644 --- a/src/wx/wxlogdebug.h +++ b/src/wx/wxlogdebug.h @@ -2,6 +2,7 @@ #define VBAM_WX_WXLOGDEBUG_H_ #include +#include // make wxLogDebug work on non-debug builds of Wx, and make it use the console // on Windows