[Input] Remove transitional key, mod, joy triplet

Originally, UserInput was built around the key, mod, joy triplet values
to maintain compatibility with other parts of the code base that made
use of these values. Since the UserInput class was introduced, all use
cases have been transitioned off these values in favor of treating the
UserInput as an abstract input.

UserInput is now a simple wrapper around either a KeyboardInput or a
JoyInput structure that only contain data pertinent to their input type.

This concludes the transition to the UserInput type.

Bug: #745
This commit is contained in:
Fabrice de Gans 2024-04-23 13:09:44 -07:00 committed by Fabrice de Gans
parent 72c4f33d63
commit 62294702e4
13 changed files with 403 additions and 358 deletions

View File

@ -2,6 +2,7 @@
#include "wx/opts.h"
#include "wx/strutils.h"
#include "wx/wxlogdebug.h"
namespace config {

View File

@ -1,4 +1,5 @@
#include "wx/config/shortcuts.h"
#include "wx/config/user-input.h"
#include <wx/xrc/xmlres.h>
@ -11,86 +12,86 @@ namespace internal {
const std::unordered_map<int, UserInput>& DefaultShortcuts() {
static const std::unordered_map<int, UserInput> 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;
}

View File

@ -40,7 +40,7 @@ std::vector<std::pair<int, wxString>> Shortcuts::GetConfiguration() const {
config.reserve(command_to_inputs_.size() + 1);
if (!disabled_defaults_.empty()) {
std::set<UserInput> noop_inputs;
std::unordered_set<UserInput> noop_inputs;
for (const auto& iter : disabled_defaults_) {
noop_inputs.insert(iter.first);
}
@ -48,7 +48,7 @@ std::vector<std::pair<int, wxString>> Shortcuts::GetConfiguration() const {
}
for (const auto& iter : command_to_inputs_) {
std::set<UserInput> inputs;
std::unordered_set<UserInput> inputs;
for (const auto& input : iter.second) {
if (internal::DefaultShortcutForCommand(iter.first) != input) {
// Not a default input.

View File

@ -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<wxKeyCode>(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<int, wxString> 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<wxKeyCode>(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<wxString, UserInput> 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<wxKeyCode>(key), static_cast<wxKeyModifier>(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<wxKeyCode>(key),
static_cast<wxKeyModifier>(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<int>(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> UserInput::FromConfigString(const wxString& string) {
std::set<UserInput> user_inputs;
std::unordered_set<UserInput> UserInput::FromConfigString(const wxString& string) {
std::unordered_set<UserInput> user_inputs;
if (string.empty()) {
return user_inputs;
@ -328,7 +318,7 @@ std::set<UserInput> UserInput::FromConfigString(const wxString& string) {
}
// static
wxString UserInput::SpanToConfigString(const std::set<UserInput>& user_inputs) {
wxString UserInput::SpanToConfigString(const std::unordered_set<UserInput>& 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<JoyControl>(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.

View File

@ -1,17 +1,53 @@
#ifndef VBAM_WX_CONFIG_USER_INPUT_H_
#define VBAM_WX_CONFIG_USER_INPUT_H_
#include <cassert>
#include <cstdint>
#include <set>
#include <unordered_set>
#include <variant.hpp>
#include <wx/event.h>
#include <wx/log.h>
#include <wx/string.h>
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<wxKeyCode>(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<config::JoyId>;
};
// 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<UserInput> FromConfigString(const wxString& string);
static std::unordered_set<UserInput> 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<UserInput>& user_inputs);
// TODO: Replace std::unordered_set with std::span when the code base uses C++20.
static wxString SpanToConfigString(const std::unordered_set<UserInput>& 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<KeyboardInput>(input_);
};
const JoyInput& joy_input() const {
assert(is_joystick());
return nonstd::get<JoyInput>(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<JoyControl>(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<wxKeyCode>(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<nonstd::monostate, JoyInput, KeyboardInput> input_;
};
} // namespace config
// Specializations for hash functions for all of the above classes.
template <>
struct std::hash<config::JoyId> {
std::size_t operator()(config::JoyId const& joy_id) const noexcept {
return std::hash<int>{}(joy_id.sdl_index_);
}
};
template <>
struct std::hash<config::JoyInput> {
std::size_t operator()(config::JoyInput const& joy_input) const noexcept {
const std::size_t hash1 = std::hash<config::JoyId>{}(joy_input.joy());
const std::size_t hash2 = std::hash<int>{}(static_cast<int>(joy_input.control()));
const std::size_t hash3 = std::hash<int>{}(joy_input.control_index());
return hash1 ^ hash2 ^ hash3;
}
};
template <>
struct std::hash<config::KeyboardInput> {
std::size_t operator()(config::KeyboardInput const& keyboard_input) const noexcept {
const std::size_t hash1 = std::hash<int>{}(keyboard_input.key());
const std::size_t hash2 = std::hash<int>{}(keyboard_input.mod());
return hash1 ^ hash2;
}
};
template <>
struct std::hash<config::UserInput> {
std::size_t operator()(config::UserInput const& user_input) const noexcept {
const std::size_t device_hash = std::hash<int>{}(static_cast<int>(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<config::JoyInput>{}(user_input.joy_input());
case config::UserInput::Device::Keyboard:
return device_hash ^
std::hash<config::KeyboardInput>{}(user_input.keyboard_input());
}
// Unreachable.
assert(false);
return 0;
}
};
#endif // VBAM_WX_CONFIG_USER_INPUT_H_

View File

@ -107,68 +107,68 @@ uint32_t LoadUnsignedOption(wxConfigBase* cfg,
opts_t gopts;
const std::map<config::GameControl, std::set<config::UserInput>> kDefaultBindings = {
const std::map<config::GameControl, std::unordered_set<config::UserInput>> 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<config::GameControl, std::set<config::UserInput>> 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<config::UserInput> saved_config =
std::unordered_set<config::UserInput> saved_config =
config::UserInput::FromConfigString(cfg->Read(option_name, ""));
if (saved_config != iter.second) {
game_bindings_changed = true;

View File

@ -14,7 +14,7 @@
class wxFileHistory;
// Default joystick bindings.
extern const std::map<config::GameControl, std::set<config::UserInput>>
extern const std::map<config::GameControl, std::unordered_set<config::UserInput>>
kDefaultBindings;
extern struct opts_t {
@ -36,7 +36,7 @@ extern struct opts_t {
int rewind_interval = 0;
/// Joypad
std::map<config::GameControl, std::set<config::UserInput>>
std::map<config::GameControl, std::unordered_set<config::UserInput>>
game_control_bindings;
int autofire_rate = 1;

View File

@ -208,8 +208,7 @@ std::vector<UserInputEvent> 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<UserInputEvent> 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<UserInputEvent> 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<UserInputEvent> 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));
}
}

View File

@ -46,8 +46,9 @@ void UserInputCtrl::SetMultiKey(bool multikey) {
Clear();
}
void UserInputCtrl::SetInputs(const std::set<config::UserInput>& inputs) {
inputs_ = inputs;
void UserInputCtrl::SetInputs(const std::unordered_set<config::UserInput>& 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;
}

View File

@ -1,7 +1,7 @@
#ifndef VBAM_WX_WIDGETS_USER_INPUT_CTRL_H_
#define VBAM_WX_WIDGETS_USER_INPUT_CTRL_H_
#include <set>
#include <unordered_set>
#include <wx/longlong.h>
#include <wx/string.h>
@ -46,7 +46,7 @@ public:
void SetMultiKey(bool multikey);
// Sets this control inputs.
void SetInputs(const std::set<config::UserInput>& inputs);
void SetInputs(const std::unordered_set<config::UserInput>& 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<config::UserInput>& inputs() const { return inputs_; }
const std::unordered_set<config::UserInput>& 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<config::UserInput> inputs_;
std::unordered_set<config::UserInput> inputs_;
};
// A validator for the UserInputCtrl. This validator is used to transfer the

View File

@ -3,7 +3,6 @@
#include <vector>
#include <wx/event.h>
#include <wx/timer.h>
#include <wx/window.h>
#include "wx/config/user-input.h"
@ -162,7 +161,7 @@ void UserInputEventSender::OnKeyDown(wxKeyEvent& event) {
}
const wxKeyModifier active_mods = GetModifiersFromSet(active_mods_);
std::vector<config::UserInput> new_inputs;
std::vector<config::KeyboardInput> 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<config::UserInput> released_inputs;
std::vector<config::KeyboardInput> 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));
}

View File

@ -50,7 +50,7 @@ private:
std::unordered_set<wxKeyCode> active_keys_;
std::unordered_set<wxKeyModifier> active_mods_;
std::set<config::UserInput> active_mod_inputs_;
std::unordered_set<config::KeyboardInput> active_mod_inputs_;
// The wxWindow this object is attached to.
// Must outlive this object.

View File

@ -2,6 +2,7 @@
#define VBAM_WX_WXLOGDEBUG_H_
#include <wx/log.h>
#include <wx/datetime.h>
// make wxLogDebug work on non-debug builds of Wx, and make it use the console
// on Windows