Refactor game controls bindings
This introduces abstractions for a game key (`wxGameKey`), a game control (`wxGameControl`) and a common global handler for in-game user input processing (`wxGameControlState`). User configuration is changed from a vector to a map of `wxGameControl` to a set of `wxUserInput`, which simplifies input configuration updates. User input processing for in-game controls is now unified between keyboard and joypad input, and is much faster in general since access to game control state is now always logarithmic rather than linear. This comes at the expense of slightly slower user input configuration updates. However, in the worst case scenario, this is still done in O(log(n)). This removes all uses of `wxJoyKeyBinding`. However, some uses of the key, mod, joy triplets remain and will be cleaned up in follow-up PRs. Issue: #745
This commit is contained in:
parent
3f2d3c139d
commit
51473a7c53
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-24 21:24+0000\n"
|
||||
"POT-Creation-Date: 2022-07-23 17:25-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -21,51 +21,51 @@ msgstr ""
|
|||
msgid "visualboyadvance-m"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:442
|
||||
#: wxvbam.cpp:446
|
||||
msgid "Could not create main window"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:513
|
||||
#: wxvbam.cpp:517
|
||||
msgid "Save built-in XRC file and exit"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:516
|
||||
#: wxvbam.cpp:520
|
||||
msgid "Save built-in vba-over.ini and exit"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:519
|
||||
#: wxvbam.cpp:523
|
||||
msgid "Print configuration path and exit"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:522
|
||||
#: wxvbam.cpp:526
|
||||
msgid "Start in full-screen mode"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:525
|
||||
#: wxvbam.cpp:529
|
||||
msgid "Set a configuration file"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:529
|
||||
#: wxvbam.cpp:533
|
||||
msgid "Delete shared link state first, if it exists"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:536
|
||||
#: wxvbam.cpp:540
|
||||
msgid "List all settable options and exit"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:539
|
||||
#: wxvbam.cpp:543
|
||||
msgid "ROM file"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:541
|
||||
#: wxvbam.cpp:545
|
||||
msgid "<config>=<value>"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:572
|
||||
#: wxvbam.cpp:576
|
||||
msgid "Configuration/build error: can't find built-in xrc"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:580
|
||||
#: wxvbam.cpp:584
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Wrote built-in configuration to %s.\n"
|
||||
|
@ -74,11 +74,11 @@ msgid ""
|
|||
"built-in:"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:595
|
||||
#: wxvbam.cpp:599
|
||||
msgid "Configuration is read from, in order:"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:609
|
||||
#: wxvbam.cpp:613
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Wrote built-in override file to %s\n"
|
||||
|
@ -86,13 +86,13 @@ msgid ""
|
|||
"from search path:"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:615
|
||||
#: wxvbam.cpp:619
|
||||
msgid ""
|
||||
"\n"
|
||||
"\tbuilt-in"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:626
|
||||
#: wxvbam.cpp:630
|
||||
msgid ""
|
||||
"Options set from the command line are saved if any configuration changes are "
|
||||
"made in the user interface.\n"
|
||||
|
@ -101,155 +101,155 @@ msgid ""
|
|||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:647
|
||||
#: wxvbam.cpp:651
|
||||
msgid ""
|
||||
"The commands available for the Keyboard/* option are:\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:659
|
||||
#: wxvbam.cpp:663
|
||||
msgid "Configuration file not found."
|
||||
msgstr ""
|
||||
|
||||
#: wxvbam.cpp:692
|
||||
#: wxvbam.cpp:696
|
||||
msgid "Bad configuration option or multiple ROM files given:\n"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:80
|
||||
#: guiinit.cpp:83
|
||||
msgid "Start!"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:99 xrc/NetLink.xrc:99
|
||||
#: guiinit.cpp:102 xrc/NetLink.xrc:99
|
||||
msgid "Connect"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:116
|
||||
#: guiinit.cpp:119
|
||||
msgid "You must enter a valid host name"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:117
|
||||
#: guiinit.cpp:120
|
||||
msgid "Host name invalid"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:135
|
||||
msgid "Waiting for clients..."
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:136
|
||||
#, c-format
|
||||
msgid "Server IP address is: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:138
|
||||
msgid "Waiting for connection..."
|
||||
msgid "Waiting for clients..."
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:139
|
||||
#, c-format
|
||||
msgid "Server IP address is: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:141
|
||||
msgid "Waiting for connection..."
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:142
|
||||
#, c-format
|
||||
msgid "Connecting to %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:172
|
||||
#: guiinit.cpp:175
|
||||
msgid ""
|
||||
"Error occurred.\n"
|
||||
"Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:239 guiinit.cpp:292
|
||||
#: guiinit.cpp:242 guiinit.cpp:295
|
||||
msgid "Select cheat file"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:240
|
||||
#: guiinit.cpp:243
|
||||
msgid "VBA cheat lists (*.clt)|*.clt|CHT cheat lists (*.cht)|*.cht"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:259 panel.cpp:447
|
||||
#: guiinit.cpp:262 panel.cpp:447
|
||||
msgid "Loaded cheats"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:293
|
||||
#: guiinit.cpp:296
|
||||
msgid "VBA cheat lists (*.clt)|*.clt"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:311
|
||||
#: guiinit.cpp:314
|
||||
msgid "Saved cheats"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:342 guiinit.cpp:361
|
||||
#: guiinit.cpp:345 guiinit.cpp:364
|
||||
msgid "Restore old values?"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:343 guiinit.cpp:362
|
||||
#: guiinit.cpp:346 guiinit.cpp:365
|
||||
msgid "Removing cheats"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:753 xrc/JoyPanel.xrc:364
|
||||
#: guiinit.cpp:756 xrc/JoyPanel.xrc:364
|
||||
msgid "GameShark"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:754 cmdevents.cpp:675
|
||||
#: guiinit.cpp:757 cmdevents.cpp:675
|
||||
msgid "GameGenie"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:756
|
||||
#: guiinit.cpp:759
|
||||
msgid "Generic Code"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:757
|
||||
#: guiinit.cpp:760
|
||||
msgid "GameShark Advance"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:758
|
||||
#: guiinit.cpp:761
|
||||
msgid "CodeBreaker Advance"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:759
|
||||
#: guiinit.cpp:762
|
||||
msgid "Flashcart CHT"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:827 guiinit.cpp:1082
|
||||
#: guiinit.cpp:830 guiinit.cpp:1085
|
||||
msgid "Number cannot be empty"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:865
|
||||
#: guiinit.cpp:868
|
||||
#, c-format
|
||||
msgid "Search produced %d results. Please refine better"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:877
|
||||
#: guiinit.cpp:880
|
||||
msgid "Search produced no results"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:1040
|
||||
#: guiinit.cpp:1043
|
||||
msgid "8-bit "
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:1044
|
||||
#: guiinit.cpp:1047
|
||||
msgid "16-bit "
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:1048
|
||||
#: guiinit.cpp:1051
|
||||
msgid "32-bit "
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:1054
|
||||
#: guiinit.cpp:1057
|
||||
msgid "signed decimal"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:1058
|
||||
#: guiinit.cpp:1061
|
||||
msgid "unsigned decimal"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:1062
|
||||
#: guiinit.cpp:1065
|
||||
msgid "unsigned hexadecimal"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:1540
|
||||
#: guiinit.cpp:1543
|
||||
#, c-format
|
||||
msgid "%d frames = %.2f ms"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:1552
|
||||
#: guiinit.cpp:1555
|
||||
msgid "Default device"
|
||||
msgstr ""
|
||||
|
||||
|
@ -294,62 +294,62 @@ msgstr ""
|
|||
msgid "Confirm"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:2739
|
||||
#: guiinit.cpp:2740
|
||||
msgid "Main icon not found"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:2749
|
||||
#: guiinit.cpp:2750
|
||||
msgid "Browse"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:2763
|
||||
#: guiinit.cpp:2764
|
||||
msgid "Main display panel not found"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:2928
|
||||
#: guiinit.cpp:2929
|
||||
#, c-format
|
||||
msgid "Duplicate menu accelerator: %s for %s and %s; keeping first"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:2942
|
||||
#: guiinit.cpp:2943
|
||||
#, c-format
|
||||
msgid "Menu accelerator %s for %s overrides default for %s ; keeping menu"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:3081
|
||||
#: guiinit.cpp:3082
|
||||
#, c-format
|
||||
msgid "Invalid menu item %s; removing"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:3289
|
||||
#: guiinit.cpp:3290
|
||||
msgid "Code"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:3298
|
||||
#: guiinit.cpp:3299
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:3372 xrc/CheatAdd.xrc:31
|
||||
#: guiinit.cpp:3373 xrc/CheatAdd.xrc:31
|
||||
msgid "Address"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:3373
|
||||
#: guiinit.cpp:3374
|
||||
msgid "Old Value"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:3374
|
||||
#: guiinit.cpp:3375
|
||||
msgid "New Value"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:3895
|
||||
#: guiinit.cpp:3898
|
||||
msgid "Menu commands"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:3918
|
||||
#: guiinit.cpp:3921
|
||||
msgid "Other commands"
|
||||
msgstr ""
|
||||
|
||||
#: guiinit.cpp:4029
|
||||
#: guiinit.cpp:4032
|
||||
msgid "JoyBus host invalid; disabling"
|
||||
msgstr ""
|
||||
|
||||
|
@ -729,7 +729,7 @@ msgstr ""
|
|||
msgid "Error saving snapshot file %s"
|
||||
msgstr ""
|
||||
|
||||
#: cmdevents.cpp:1182 sys.cpp:449
|
||||
#: cmdevents.cpp:1182 sys.cpp:450
|
||||
#, c-format
|
||||
msgid "Wrote snapshot %s"
|
||||
msgstr ""
|
||||
|
@ -855,102 +855,102 @@ msgstr ""
|
|||
msgid "Network is not supported in local mode."
|
||||
msgstr ""
|
||||
|
||||
#: opts.cpp:566 opts.cpp:869
|
||||
#: opts.cpp:648 opts.cpp:950
|
||||
#, c-format
|
||||
msgid "Invalid value %s for option %s; valid values are %s%s%s"
|
||||
msgstr ""
|
||||
|
||||
#: opts.cpp:583 opts.cpp:881
|
||||
#: opts.cpp:665 opts.cpp:962
|
||||
#, c-format
|
||||
msgid "Invalid value %d for option %s; valid values are %d - %d"
|
||||
msgstr ""
|
||||
|
||||
#: opts.cpp:590 opts.cpp:599 opts.cpp:889 opts.cpp:897
|
||||
#: opts.cpp:672 opts.cpp:681 opts.cpp:970 opts.cpp:978
|
||||
#, c-format
|
||||
msgid "Invalid value %f for option %s; valid values are %f - %f"
|
||||
msgstr ""
|
||||
|
||||
#: opts.cpp:659 opts.cpp:680 opts.cpp:965 opts.cpp:991
|
||||
#: opts.cpp:738 opts.cpp:759 opts.cpp:1046
|
||||
#, c-format
|
||||
msgid "Invalid key binding %s for %s"
|
||||
msgstr ""
|
||||
|
||||
#: opts.cpp:852
|
||||
#: opts.cpp:933
|
||||
#, c-format
|
||||
msgid "Invalid flag option %s - %s ignored"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:124 sys.cpp:180
|
||||
#: sys.cpp:125 sys.cpp:181
|
||||
msgid "No game in progress to record"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:137
|
||||
#: sys.cpp:138
|
||||
#, c-format
|
||||
msgid "Cannot open output file %s"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:144 sys.cpp:164 sys.cpp:310
|
||||
#: sys.cpp:145 sys.cpp:165 sys.cpp:311
|
||||
msgid "Error writing game recording"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:185
|
||||
#: sys.cpp:186
|
||||
msgid "Cannot play game recording while recording"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:198
|
||||
#: sys.cpp:199
|
||||
#, c-format
|
||||
msgid "Cannot open recording file %s"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:205 sys.cpp:215
|
||||
#: sys.cpp:206 sys.cpp:216
|
||||
msgid "Error reading game recording"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:321
|
||||
#: sys.cpp:322
|
||||
msgid "Playback ended"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:340
|
||||
#: sys.cpp:341
|
||||
#, c-format
|
||||
msgid "%d%%(%d, %d fps)"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:348
|
||||
#: sys.cpp:349
|
||||
#, c-format
|
||||
msgid "%d%%"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:767 xrc/GBPrinter.xrc:65
|
||||
#: sys.cpp:769 xrc/GBPrinter.xrc:65
|
||||
msgid "&Discard"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:801
|
||||
#: sys.cpp:803
|
||||
msgid "Image files (*.bmp;*.jpg;*.png)|*.bmp;*.jpg;*.png|"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:810
|
||||
#: sys.cpp:812
|
||||
msgid "Save printer image to"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:824 sys.cpp:1007
|
||||
#: sys.cpp:826 sys.cpp:1009
|
||||
#, c-format
|
||||
msgid "Wrote printer output to %s"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:829 sys.cpp:900
|
||||
#: sys.cpp:831 sys.cpp:902
|
||||
msgid "&Close"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:895
|
||||
#: sys.cpp:897
|
||||
msgid "Printed"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:1197
|
||||
#: sys.cpp:1199
|
||||
#, c-format
|
||||
msgid "Error opening pseudo tty: %s"
|
||||
msgstr ""
|
||||
|
||||
#: sys.cpp:1296
|
||||
#: sys.cpp:1298
|
||||
#, c-format
|
||||
msgid "Error setting up server socket (%d)"
|
||||
msgstr ""
|
||||
|
@ -1046,70 +1046,70 @@ msgstr ""
|
|||
msgid "Error writing rewind state"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2290
|
||||
#: panel.cpp:2198
|
||||
msgid "Failed to set glXSwapIntervalEXT"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2299
|
||||
#: panel.cpp:2207
|
||||
msgid "Failed to set glXSwapIntervalSGI"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2308
|
||||
#: panel.cpp:2216
|
||||
msgid "Failed to set glXSwapIntervalMESA"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2314
|
||||
#: panel.cpp:2222
|
||||
msgid "No support for wglGetExtensionsStringEXT"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2317
|
||||
#: panel.cpp:2225
|
||||
msgid "No support for WGL_EXT_swap_control"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2326
|
||||
#: panel.cpp:2234
|
||||
msgid "Failed to set wglSwapIntervalEXT"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2332
|
||||
#: panel.cpp:2240
|
||||
msgid "No VSYNC available on this platform"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2428
|
||||
#: panel.cpp:2336
|
||||
msgid "memory allocation error"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2431
|
||||
#: panel.cpp:2339
|
||||
msgid "error initializing codec"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2434
|
||||
#: panel.cpp:2342
|
||||
msgid "error writing to output file"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2437
|
||||
#: panel.cpp:2345
|
||||
msgid "can't guess output format from file name"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2442
|
||||
#: panel.cpp:2350
|
||||
msgid "programming error; aborting!"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2454 panel.cpp:2483
|
||||
#: panel.cpp:2362 panel.cpp:2391
|
||||
#, c-format
|
||||
msgid "Unable to begin recording to %s (%s)"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2511
|
||||
#: panel.cpp:2419
|
||||
#, c-format
|
||||
msgid "Error in audio/video recording (%s); aborting"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2517
|
||||
#: panel.cpp:2425
|
||||
#, c-format
|
||||
msgid "Error in audio recording (%s); aborting"
|
||||
msgstr ""
|
||||
|
||||
#: panel.cpp:2527
|
||||
#: panel.cpp:2435
|
||||
#, c-format
|
||||
msgid "Error in video recording (%s); aborting"
|
||||
msgstr ""
|
||||
|
@ -1170,14 +1170,14 @@ msgstr ""
|
|||
msgid "CONTROL"
|
||||
msgstr ""
|
||||
|
||||
#: widgets/sdljoy.cpp:137
|
||||
#: widgets/sdljoy.cpp:177
|
||||
#, c-format
|
||||
msgid "Connected joystick %d: %s"
|
||||
msgid "Connected %s: %s"
|
||||
msgstr ""
|
||||
|
||||
#: widgets/sdljoy.cpp:152
|
||||
#: widgets/sdljoy.cpp:192
|
||||
#, c-format
|
||||
msgid "Disconnected joystick %d"
|
||||
msgid "Disconnected %s"
|
||||
msgstr ""
|
||||
|
||||
#: xaudio2.cpp:34
|
||||
|
|
|
@ -726,6 +726,7 @@ set(
|
|||
wayland.cpp
|
||||
strutils.cpp
|
||||
wxutil.cpp
|
||||
widgets/gamecontrol.cpp
|
||||
widgets/keyedit.cpp
|
||||
widgets/joyedit.cpp
|
||||
widgets/userinput.cpp
|
||||
|
@ -759,6 +760,7 @@ set(
|
|||
wxhead.h
|
||||
wayland.h
|
||||
wxutil.h
|
||||
widgets/wx/gamecontrol.h
|
||||
widgets/wx/keyedit.h
|
||||
widgets/wx/joyedit.h
|
||||
widgets/wx/sdljoy.h
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#include <wx/txtstrm.h>
|
||||
#include <wx/wfstream.h>
|
||||
|
||||
#include "opts.h"
|
||||
#include "wx/gamecontrol.h"
|
||||
#include "wx/userinput.h"
|
||||
#include "../gba/CheatSearch.h"
|
||||
|
||||
#if defined(__WXGTK__)
|
||||
|
@ -1667,32 +1670,29 @@ public:
|
|||
bool clear = ev.GetId() == XRCID("Clear");
|
||||
|
||||
// For the individual clear buttons, we assume their name is
|
||||
// "Clear" + joynames[i]
|
||||
// "Clear" + control_name
|
||||
// ClearUp for Up; ClearR for R etc
|
||||
for (int i = 0; i < NUM_KEYS; ++i) {
|
||||
wxJoyKeyTextCtrl* tc = XRCCTRL_D(*p, joynames[i], wxJoyKeyTextCtrl);
|
||||
wxString singleClearButton("Clear" + joynames[i]);
|
||||
for (const wxGameKey& game_key : kAllGameKeys) {
|
||||
const wxString control_name = GameKeyToString(game_key);
|
||||
wxJoyKeyTextCtrl* tc = XRCCTRL_D(*p, control_name, wxJoyKeyTextCtrl);
|
||||
wxString singleClearButton("Clear" + control_name);
|
||||
if (ev.GetId() == XRCID(singleClearButton.c_str())) {
|
||||
tc->SetValue(wxEmptyString);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_KEYS; i++) {
|
||||
wxJoyKeyTextCtrl* tc = XRCCTRL_D(*p, joynames[i], wxJoyKeyTextCtrl);
|
||||
for (const wxGameKey& game_key : kAllGameKeys) {
|
||||
wxJoyKeyTextCtrl* tc =
|
||||
XRCCTRL_D(*p, GameKeyToString(game_key), wxJoyKeyTextCtrl);
|
||||
|
||||
if (clear)
|
||||
if (clear) {
|
||||
tc->SetValue(wxEmptyString);
|
||||
else {
|
||||
wxJoyKeyBinding_v a;
|
||||
|
||||
if (defkeys_keyboard[i].key)
|
||||
a.push_back(defkeys_keyboard[i]);
|
||||
|
||||
for (auto bind : defkeys_joystick[i])
|
||||
a.push_back(bind);
|
||||
|
||||
tc->SetValue(wxJoyKeyTextCtrl::ToString(a));
|
||||
} else {
|
||||
tc->SetValue(
|
||||
wxUserInput::SpanToString(
|
||||
kDefaultBindings.find(
|
||||
wxGameControl(0, game_key))->second));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3835,9 +3835,10 @@ bool MainFrame::BindControls()
|
|||
cb->SetValidator(wxBoolIntValidator(&gopts.default_stick, i + 1));
|
||||
wxWindow *prev = NULL, *prevp = NULL;
|
||||
|
||||
for (int j = 0; j < NUM_KEYS; j++) {
|
||||
wxJoyKeyTextCtrl* tc = XRCCTRL_D(*w, joynames[j], wxJoyKeyTextCtrl);
|
||||
CheckThrowXRCError(tc, joynames[j]);
|
||||
for (const wxGameKey& game_key : kAllGameKeys) {
|
||||
const wxString control_name = GameKeyToString(game_key);
|
||||
wxJoyKeyTextCtrl* tc = XRCCTRL_D(*w, control_name, wxJoyKeyTextCtrl);
|
||||
CheckThrowXRCError(tc, control_name);
|
||||
wxWindow* p = tc->GetParent();
|
||||
|
||||
if (p == prevp)
|
||||
|
@ -3845,7 +3846,7 @@ bool MainFrame::BindControls()
|
|||
|
||||
prev = tc;
|
||||
prevp = p;
|
||||
tc->SetValidator(wxJoyKeyValidator(&gopts.joykey_bindings[i][j]));
|
||||
tc->SetValidator(wxJoyKeyValidator(wxGameControl(i, game_key)));
|
||||
}
|
||||
|
||||
JoyPadConfigHandler[i].p = w;
|
||||
|
@ -3855,8 +3856,9 @@ bool MainFrame::BindControls()
|
|||
w->Connect(XRCID("Clear"), wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(JoyPadConfig_t::JoypadConfigButtons),
|
||||
NULL, &JoyPadConfigHandler[i]);
|
||||
for (int j = 0; j < NUM_KEYS; ++j) {
|
||||
w->Connect(XRCID(wxString("Clear" + joynames[j]).c_str()),
|
||||
for (const wxGameKey& game_key : kAllGameKeys) {
|
||||
const wxString control_name = GameKeyToString(game_key);
|
||||
w->Connect(XRCID(wxString("Clear" + control_name).c_str()),
|
||||
wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(JoyPadConfig_t::JoypadConfigButtons),
|
||||
NULL, &JoyPadConfigHandler[i]);
|
||||
|
|
279
src/wx/opts.cpp
279
src/wx/opts.cpp
|
@ -1,7 +1,11 @@
|
|||
#include "wxvbam.h"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <wx/log.h>
|
||||
#include <wx/display.h>
|
||||
|
||||
#include "wx/gamecontrol.h"
|
||||
#include "wx/userinput.h"
|
||||
#include "wxvbam.h"
|
||||
#include "strutils.h"
|
||||
|
||||
/*
|
||||
|
@ -13,7 +17,7 @@
|
|||
-p/--profile=hz
|
||||
*/
|
||||
|
||||
#define WJKB newWxJoyKeyBinding
|
||||
#define WJKB wxUserInput::FromLegacyKeyModJoy
|
||||
|
||||
/* not sure how well other compilers support field-init syntax */
|
||||
#define STROPT(c, n, d, v) \
|
||||
|
@ -131,40 +135,138 @@ const wxAcceleratorEntryUnicode default_accels[] = {
|
|||
};
|
||||
const int num_def_accels = sizeof(default_accels) / sizeof(default_accels[0]);
|
||||
|
||||
// Note: this must match GUI widget names or GUI won't work
|
||||
// This table's order determines tab order as well
|
||||
const wxString joynames[NUM_KEYS] = {
|
||||
wxT("Up"), wxT("Down"), wxT("Left"), wxT("Right"),
|
||||
wxT("A"), wxT("B"), wxT("L"), wxT("R"),
|
||||
wxT("Select"), wxT("Start"),
|
||||
wxT("MotionUp"), wxT("MotionDown"), wxT("MotionLeft"), wxT("MotionRight"),
|
||||
wxT("MotionIn"), wxT("MotionOut"), wxT("AutoA"), wxT("AutoB"),
|
||||
wxT("Speed"), wxT("Capture"), wxT("GS")
|
||||
};
|
||||
const std::map<wxGameControl, std::set<wxUserInput>> kDefaultBindings = {
|
||||
{ wxGameControl(0, wxGameKey::Up), {
|
||||
WJKB(wxT('W')),
|
||||
WJKB(11, WXJB_BUTTON, 1),
|
||||
WJKB(1, WXJB_AXIS_MINUS, 1),
|
||||
WJKB(3, WXJB_AXIS_MINUS, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Down), {
|
||||
WJKB(wxT('S')),
|
||||
WJKB(12, WXJB_BUTTON, 1),
|
||||
WJKB(1, WXJB_AXIS_PLUS, 1),
|
||||
WJKB(3, WXJB_AXIS_PLUS, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Left), {
|
||||
WJKB(wxT('A')),
|
||||
WJKB(13, WXJB_BUTTON, 1),
|
||||
WJKB(0, WXJB_AXIS_MINUS, 1),
|
||||
WJKB(2, WXJB_AXIS_MINUS, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Right), {
|
||||
WJKB(wxT('D')),
|
||||
WJKB(14, WXJB_BUTTON, 1),
|
||||
WJKB(0, WXJB_AXIS_PLUS, 1),
|
||||
WJKB(2, WXJB_AXIS_PLUS, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::A), {
|
||||
WJKB(wxT('L')),
|
||||
WJKB(0, WXJB_BUTTON, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::B), {
|
||||
WJKB(wxT('K')),
|
||||
WJKB(1, WXJB_BUTTON, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::L), {
|
||||
WJKB(wxT('I')),
|
||||
WJKB(2, WXJB_BUTTON, 1),
|
||||
WJKB(9, WXJB_BUTTON, 1),
|
||||
WJKB(4, WXJB_AXIS_PLUS, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::R), {
|
||||
WJKB(wxT('O')),
|
||||
WJKB(3, WXJB_BUTTON, 1),
|
||||
WJKB(10, WXJB_BUTTON, 1),
|
||||
WJKB(5, WXJB_AXIS_PLUS, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Select), {
|
||||
WJKB(WXK_BACK),
|
||||
WJKB(4, WXJB_BUTTON, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Start), {
|
||||
WJKB(WXK_RETURN),
|
||||
WJKB(6, WXJB_BUTTON, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::MotionUp), {}},
|
||||
{ wxGameControl(0, wxGameKey::MotionDown), {}},
|
||||
{ wxGameControl(0, wxGameKey::MotionLeft), {}},
|
||||
{ wxGameControl(0, wxGameKey::MotionRight), {}},
|
||||
{ wxGameControl(0, wxGameKey::MotionIn), {}},
|
||||
{ wxGameControl(0, wxGameKey::MotionOut), {}},
|
||||
{ wxGameControl(0, wxGameKey::AutoA), {}},
|
||||
{ wxGameControl(0, wxGameKey::AutoB), {}},
|
||||
{ wxGameControl(0, wxGameKey::Speed), {
|
||||
WJKB(WXK_SPACE),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Capture), {}},
|
||||
{ wxGameControl(0, wxGameKey::Gameshark), {}},
|
||||
|
||||
wxJoyKeyBinding defkeys_keyboard[NUM_KEYS] = {
|
||||
WJKB(wxT('W')), WJKB(wxT('S')), WJKB(wxT('A')), WJKB(wxT('D')),
|
||||
WJKB(wxT('L')), WJKB(wxT('K')), WJKB(wxT('I')), WJKB(wxT('O')),
|
||||
WJKB(WXK_BACK), WJKB(WXK_RETURN),
|
||||
WJKB(0), WJKB(0), WJKB(0), WJKB(0),
|
||||
WJKB(0), WJKB(0), WJKB(0), WJKB(0),
|
||||
WJKB(WXK_SPACE), WJKB(0), WJKB(0)
|
||||
};
|
||||
{ wxGameControl(1, wxGameKey::Up), {}},
|
||||
{ wxGameControl(1, wxGameKey::Down), {}},
|
||||
{ wxGameControl(1, wxGameKey::Left), {}},
|
||||
{ wxGameControl(1, wxGameKey::Right), {}},
|
||||
{ wxGameControl(1, wxGameKey::A), {}},
|
||||
{ wxGameControl(1, wxGameKey::B), {}},
|
||||
{ wxGameControl(1, wxGameKey::L), {}},
|
||||
{ wxGameControl(1, wxGameKey::R), {}},
|
||||
{ wxGameControl(1, wxGameKey::Select), {}},
|
||||
{ wxGameControl(1, wxGameKey::Start), {}},
|
||||
{ wxGameControl(1, wxGameKey::MotionUp), {}},
|
||||
{ wxGameControl(1, wxGameKey::MotionDown), {}},
|
||||
{ wxGameControl(1, wxGameKey::MotionLeft), {}},
|
||||
{ wxGameControl(1, wxGameKey::MotionRight), {}},
|
||||
{ wxGameControl(1, wxGameKey::MotionIn), {}},
|
||||
{ wxGameControl(1, wxGameKey::MotionOut), {}},
|
||||
{ wxGameControl(1, wxGameKey::AutoA), {}},
|
||||
{ wxGameControl(1, wxGameKey::AutoB), {}},
|
||||
{ wxGameControl(1, wxGameKey::Speed), {}},
|
||||
{ wxGameControl(1, wxGameKey::Capture), {}},
|
||||
{ wxGameControl(1, wxGameKey::Gameshark), {}},
|
||||
|
||||
std::vector<std::vector<wxJoyKeyBinding>> defkeys_joystick = {
|
||||
{ WJKB(11, WXJB_BUTTON, 1), WJKB(1, WXJB_AXIS_MINUS, 1), WJKB(3, WXJB_AXIS_MINUS, 1) },
|
||||
{ WJKB(12, WXJB_BUTTON, 1), WJKB(1, WXJB_AXIS_PLUS, 1), WJKB(3, WXJB_AXIS_PLUS, 1) },
|
||||
{ WJKB(13, WXJB_BUTTON, 1), WJKB(0, WXJB_AXIS_MINUS, 1), WJKB(2, WXJB_AXIS_MINUS, 1) },
|
||||
{ WJKB(14, WXJB_BUTTON, 1), WJKB(0, WXJB_AXIS_PLUS, 1), WJKB(2, WXJB_AXIS_PLUS, 1) },
|
||||
{ WJKB(0, WXJB_BUTTON, 1) },
|
||||
{ WJKB(1, WXJB_BUTTON, 1) },
|
||||
{ WJKB(2, WXJB_BUTTON, 1), WJKB( 9, WXJB_BUTTON, 1), WJKB(4, WXJB_AXIS_PLUS, 1) },
|
||||
{ WJKB(3, WXJB_BUTTON, 1), WJKB(10, WXJB_BUTTON, 1), WJKB(5, WXJB_AXIS_PLUS, 1) },
|
||||
{ WJKB(4, WXJB_BUTTON, 1) },
|
||||
{ WJKB(6, WXJB_BUTTON, 1) },
|
||||
{}, {}, {}, {},
|
||||
{}, {}, {}, {},
|
||||
{}, {}, {}
|
||||
{ wxGameControl(2, wxGameKey::Up), {}},
|
||||
{ wxGameControl(2, wxGameKey::Down), {}},
|
||||
{ wxGameControl(2, wxGameKey::Left), {}},
|
||||
{ wxGameControl(2, wxGameKey::Right), {}},
|
||||
{ wxGameControl(2, wxGameKey::A), {}},
|
||||
{ wxGameControl(2, wxGameKey::B), {}},
|
||||
{ wxGameControl(2, wxGameKey::L), {}},
|
||||
{ wxGameControl(2, wxGameKey::R), {}},
|
||||
{ wxGameControl(2, wxGameKey::Select), {}},
|
||||
{ wxGameControl(2, wxGameKey::Start), {}},
|
||||
{ wxGameControl(2, wxGameKey::MotionUp), {}},
|
||||
{ wxGameControl(2, wxGameKey::MotionDown), {}},
|
||||
{ wxGameControl(2, wxGameKey::MotionLeft), {}},
|
||||
{ wxGameControl(2, wxGameKey::MotionRight), {}},
|
||||
{ wxGameControl(2, wxGameKey::MotionIn), {}},
|
||||
{ wxGameControl(2, wxGameKey::MotionOut), {}},
|
||||
{ wxGameControl(2, wxGameKey::AutoA), {}},
|
||||
{ wxGameControl(2, wxGameKey::AutoB), {}},
|
||||
{ wxGameControl(2, wxGameKey::Speed), {}},
|
||||
{ wxGameControl(2, wxGameKey::Capture), {}},
|
||||
{ wxGameControl(2, wxGameKey::Gameshark), {}},
|
||||
|
||||
{ wxGameControl(3, wxGameKey::Up), {}},
|
||||
{ wxGameControl(3, wxGameKey::Down), {}},
|
||||
{ wxGameControl(3, wxGameKey::Left), {}},
|
||||
{ wxGameControl(3, wxGameKey::Right), {}},
|
||||
{ wxGameControl(3, wxGameKey::A), {}},
|
||||
{ wxGameControl(3, wxGameKey::B), {}},
|
||||
{ wxGameControl(3, wxGameKey::L), {}},
|
||||
{ wxGameControl(3, wxGameKey::R), {}},
|
||||
{ wxGameControl(3, wxGameKey::Select), {}},
|
||||
{ wxGameControl(3, wxGameKey::Start), {}},
|
||||
{ wxGameControl(3, wxGameKey::MotionUp), {}},
|
||||
{ wxGameControl(3, wxGameKey::MotionDown), {}},
|
||||
{ wxGameControl(3, wxGameKey::MotionLeft), {}},
|
||||
{ wxGameControl(3, wxGameKey::MotionRight), {}},
|
||||
{ wxGameControl(3, wxGameKey::MotionIn), {}},
|
||||
{ wxGameControl(3, wxGameKey::MotionOut), {}},
|
||||
{ wxGameControl(3, wxGameKey::AutoA), {}},
|
||||
{ wxGameControl(3, wxGameKey::AutoB), {}},
|
||||
{ wxGameControl(3, wxGameKey::Speed), {}},
|
||||
{ wxGameControl(3, wxGameKey::Capture), {}},
|
||||
{ wxGameControl(3, wxGameKey::Gameshark), {}},
|
||||
};
|
||||
|
||||
wxAcceleratorEntry_v sys_accels;
|
||||
|
@ -385,19 +487,6 @@ bool opt_lt(const opt_desc& opt1, const opt_desc& opt2)
|
|||
return wxStrcmp(opt1.opt, opt2.opt) < 0;
|
||||
}
|
||||
|
||||
// set default input keys
|
||||
void set_default_keys()
|
||||
{
|
||||
for (int i = 0; i < NUM_KEYS; i++) {
|
||||
gopts.joykey_bindings[0][i].clear();
|
||||
|
||||
if (defkeys_keyboard[i].key)
|
||||
gopts.joykey_bindings[0][i].push_back(defkeys_keyboard[i]);
|
||||
for (auto bind : defkeys_joystick[i])
|
||||
gopts.joykey_bindings[0][i].push_back(bind);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: simulate MakeInstanceFilename(vbam.ini) using subkeys (Slave%d/*)
|
||||
void load_opts()
|
||||
{
|
||||
|
@ -473,13 +562,7 @@ void load_opts()
|
|||
|
||||
for (cont = cfg->GetFirstEntry(e, key_idx); cont;
|
||||
cont = cfg->GetNextEntry(e, key_idx)) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_KEYS; i++)
|
||||
if (e == joynames[i])
|
||||
break;
|
||||
|
||||
if (i == NUM_KEYS) {
|
||||
if (!StringToGameKey(e)) {
|
||||
s.append(e);
|
||||
//wxLogWarning(_("Invalid option %s present; removing if possible"), s.c_str());
|
||||
item_del.push_back(s);
|
||||
|
@ -644,23 +727,20 @@ void load_opts()
|
|||
}
|
||||
}
|
||||
|
||||
// Initialize game control bindings to populate the configuration map.
|
||||
gopts.game_control_bindings.insert(kDefaultBindings.begin(), kDefaultBindings.end());
|
||||
|
||||
// joypad is special
|
||||
set_default_keys();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < NUM_KEYS; j++) {
|
||||
wxString optname;
|
||||
optname.Printf(wxT("Joypad/%d/%s"), i + 1, joynames[j].c_str());
|
||||
bool gotit = cfg->Read(optname, &s);
|
||||
|
||||
if (gotit) {
|
||||
gopts.joykey_bindings[i][j] = wxJoyKeyTextCtrl::FromString(s);
|
||||
|
||||
if (s.size() && !gopts.joykey_bindings[i][j].size())
|
||||
for (auto& iter : gopts.game_control_bindings) {
|
||||
const wxString optname = iter.first.ToString();
|
||||
if (cfg->Read(optname, &s)) {
|
||||
iter.second = wxUserInput::FromString(s);
|
||||
if (!s.empty() && iter.second.empty()) {
|
||||
wxLogWarning(_("Invalid key binding %s for %s"), s.c_str(), optname.c_str());
|
||||
} else {
|
||||
s = wxJoyKeyTextCtrl::ToString(gopts.joykey_bindings[i][j]);
|
||||
cfg->Write(optname, s);
|
||||
}
|
||||
} else {
|
||||
s = wxUserInput::SpanToString(iter.second);
|
||||
cfg->Write(optname, s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -758,21 +838,23 @@ void update_opts()
|
|||
}
|
||||
}
|
||||
|
||||
// for joypad, use ToString comparisons. It may trigger changes
|
||||
// even when there are none (e.g. multi-binding ordering changes)
|
||||
// not worth worrying about
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < NUM_KEYS; j++) {
|
||||
wxString s, o;
|
||||
wxString optname;
|
||||
optname.Printf(wxT("Joypad/%d/%s"), i + 1, joynames[j].c_str());
|
||||
s = wxJoyKeyTextCtrl::ToString(gopts.joykey_bindings[i][j], wxT(','), true);
|
||||
cfg->Read(optname, &o);
|
||||
|
||||
if (o != s)
|
||||
cfg->Write(optname, s);
|
||||
// For joypad, compare the wxUserInput sets. Since wxUserInput 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.
|
||||
bool game_bindings_changed = false;
|
||||
for (auto &iter : gopts.game_control_bindings) {
|
||||
wxString option_name = iter.first.ToString();
|
||||
std::set<wxUserInput> saved_config =
|
||||
wxUserInput::FromString(cfg->Read(option_name, ""));
|
||||
if (saved_config != iter.second) {
|
||||
game_bindings_changed = true;
|
||||
cfg->Write(option_name, wxUserInput::SpanToString(iter.second));
|
||||
}
|
||||
}
|
||||
if (game_bindings_changed) {
|
||||
wxGameControlState::Instance().OnGameBindingsChanged();
|
||||
}
|
||||
|
||||
// for keyboard, first remove any commands that aren't bound at all
|
||||
if (cfg->HasGroup(wxT("/Keyboard"))) {
|
||||
|
@ -968,33 +1050,20 @@ bool opt_set(const wxString& name, const wxString& val)
|
|||
}
|
||||
|
||||
return true;
|
||||
} else if (!wxStrncmp(name, wxT("Joypad"), wxStrlen(wxT("Joypad")))) {
|
||||
if (parts[1] < wxT('1') || parts[1] > wxT('4') || parts.size() < 3)
|
||||
return false;
|
||||
|
||||
int jno = parts[1][0] - wxT('1');
|
||||
int kno;
|
||||
|
||||
for (kno = 0; kno < NUM_KEYS; kno++)
|
||||
if (!wxStrcmp(joynames[kno], parts[2]))
|
||||
break;
|
||||
|
||||
if (kno == NUM_KEYS)
|
||||
return false;
|
||||
|
||||
if (val.empty())
|
||||
gopts.joykey_bindings[jno][kno].clear();
|
||||
else {
|
||||
auto b = wxJoyKeyTextCtrl::FromString(val);
|
||||
|
||||
if (!b.size())
|
||||
wxLogWarning(_("Invalid key binding %s for %s"), val.c_str(), name.c_str());
|
||||
else
|
||||
gopts.joykey_bindings[jno][kno] = b;
|
||||
}
|
||||
|
||||
const std::optional<wxGameControl> game_control =
|
||||
wxGameControl::FromString(name);
|
||||
if (game_control) {
|
||||
if (val.empty()) {
|
||||
gopts.game_control_bindings[game_control.value()].clear();
|
||||
} else {
|
||||
gopts.game_control_bindings[game_control.value()] =
|
||||
wxUserInput::FromString(val);
|
||||
}
|
||||
return true;
|
||||
} else
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
#ifndef WX_OPTS_H
|
||||
#define WX_OPTS_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#define NUM_KEYS 21
|
||||
extern const wxString joynames[NUM_KEYS];
|
||||
extern wxJoyKeyBinding defkeys_keyboard[NUM_KEYS]; // keyboard defaults
|
||||
#include <wx/string.h>
|
||||
#include <wx/vidmode.h>
|
||||
|
||||
extern std::vector<std::vector<wxJoyKeyBinding>> defkeys_joystick; // joystick defaults
|
||||
#include "wx/gamecontrol.h"
|
||||
#include "wx/keyedit.h"
|
||||
#include "wx/userinput.h"
|
||||
|
||||
// Forward declaration.
|
||||
class wxFileHistory;
|
||||
|
||||
// Default joystick bindings.
|
||||
extern const std::map<wxGameControl, std::set<wxUserInput>> kDefaultBindings;
|
||||
|
||||
extern struct opts_t {
|
||||
opts_t();
|
||||
|
@ -57,7 +64,7 @@ extern struct opts_t {
|
|||
int statusbar;
|
||||
|
||||
/// Joypad
|
||||
wxJoyKeyBinding_v joykey_bindings[4][NUM_KEYS];
|
||||
std::map<wxGameControl, std::set<wxUserInput>> game_control_bindings;
|
||||
int autofire_rate;
|
||||
int default_stick;
|
||||
|
||||
|
@ -122,8 +129,6 @@ extern const int num_opts;
|
|||
extern const wxAcceleratorEntryUnicode default_accels[];
|
||||
extern const int num_def_accels;
|
||||
|
||||
// call to setup default keys.
|
||||
void set_default_keys();
|
||||
// call to load config (once)
|
||||
// will write defaults for options not present and delete bad opts
|
||||
// will also initialize opts[] array translations
|
||||
|
|
115
src/wx/panel.cpp
115
src/wx/panel.cpp
|
@ -24,6 +24,7 @@
|
|||
#include "drawing.h"
|
||||
#include "filters.h"
|
||||
#include "wx/joyedit.h"
|
||||
#include "wx/gamecontrol.h"
|
||||
#include "wx/userinput.h"
|
||||
#include "wxvbam.h"
|
||||
#include "wxutil.h"
|
||||
|
@ -34,9 +35,6 @@
|
|||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// release all buttons currently pressed
|
||||
static void clear_input_press();
|
||||
|
||||
int emulating;
|
||||
|
||||
IMPLEMENT_DYNAMIC_CLASS(GameArea, wxPanel)
|
||||
|
@ -957,7 +955,7 @@ GameArea::~GameArea()
|
|||
|
||||
void GameArea::OnKillFocus(wxFocusEvent& ev)
|
||||
{
|
||||
clear_input_press();
|
||||
wxGameControlState::Instance().Reset();
|
||||
ev.Skip();
|
||||
}
|
||||
|
||||
|
@ -977,7 +975,7 @@ void GameArea::Pause()
|
|||
// when the game is paused like this, we should not allow any
|
||||
// input to remain pressed, because they could be released
|
||||
// outside of the game zone and we would not know about it.
|
||||
clear_input_press();
|
||||
wxGameControlState::Instance().Reset();
|
||||
|
||||
if (loaded != IMAGE_UNKNOWN)
|
||||
soundPause();
|
||||
|
@ -1208,99 +1206,12 @@ void GameArea::OnIdle(wxIdleEvent& event)
|
|||
}
|
||||
}
|
||||
|
||||
// Note: keys will get stuck if they are released while window has no focus
|
||||
// can't really do anything about it, except scan for pressed keys on
|
||||
// activate events. Maybe later.
|
||||
|
||||
static uint32_t bmask[NUM_KEYS] = {
|
||||
KEYM_UP, KEYM_DOWN, KEYM_LEFT, KEYM_RIGHT, KEYM_A, KEYM_B, KEYM_L, KEYM_R,
|
||||
KEYM_SELECT, KEYM_START, KEYM_MOTION_UP, KEYM_MOTION_DOWN, KEYM_MOTION_LEFT,
|
||||
KEYM_MOTION_RIGHT, KEYM_MOTION_IN, KEYM_MOTION_OUT, KEYM_AUTO_A, KEYM_AUTO_B, KEYM_SPEED, KEYM_CAPTURE,
|
||||
KEYM_GS
|
||||
};
|
||||
|
||||
static std::set<wxUserInput> keys_pressed;
|
||||
|
||||
static void clear_input_press()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
joypress[i] = 0;
|
||||
}
|
||||
keys_pressed.clear();
|
||||
}
|
||||
|
||||
struct game_key {
|
||||
int player;
|
||||
int key_num;
|
||||
int bind_num;
|
||||
wxJoyKeyBinding_v& b;
|
||||
};
|
||||
|
||||
// Populates |vec| with the game keys currently pressed.
|
||||
static void game_keys_pressed(int key, int mod, int joy, std::vector<game_key>* vec)
|
||||
{
|
||||
for (int player = 0; player < 4; player++)
|
||||
for (int key_num = 0; key_num < NUM_KEYS; key_num++) {
|
||||
wxJoyKeyBinding_v& b = gopts.joykey_bindings[player][key_num];
|
||||
|
||||
for (size_t bind_num = 0; bind_num < b.size(); bind_num++)
|
||||
if (b[bind_num].key == key && b[bind_num].mod == mod && b[bind_num].joy == joy)
|
||||
vec->push_back({player, key_num, (int)bind_num, b});
|
||||
}
|
||||
}
|
||||
|
||||
static bool process_user_input(bool down, const wxUserInput& user_input)
|
||||
{
|
||||
int key = user_input.key();
|
||||
int mod = user_input.mod();
|
||||
int joy = user_input.joy();
|
||||
|
||||
std::vector<game_key> game_keys;
|
||||
game_keys_pressed(key, mod, joy, &game_keys);
|
||||
const bool is_game_key = !game_keys.empty();
|
||||
|
||||
// check if key is already pressed
|
||||
auto iter = keys_pressed.find(user_input);
|
||||
if (iter != keys_pressed.end()) {
|
||||
// double press is noop
|
||||
if (down)
|
||||
return is_game_key;
|
||||
|
||||
// if released, forget it
|
||||
iter = keys_pressed.erase(iter);
|
||||
} else {
|
||||
// double release is noop
|
||||
if (!down)
|
||||
return is_game_key;
|
||||
|
||||
// otherwise remember it
|
||||
keys_pressed.emplace(user_input);
|
||||
}
|
||||
|
||||
for (auto&& game_key : game_keys) {
|
||||
if (down) {
|
||||
// press button
|
||||
joypress[game_key.player] |= bmask[game_key.key_num];
|
||||
}
|
||||
else {
|
||||
// only release if no others pressed
|
||||
size_t bind2;
|
||||
auto b = game_key.b;
|
||||
|
||||
for (bind2 = 0; bind2 < game_key.b.size(); bind2++) {
|
||||
if ((size_t)game_key.bind_num == bind2 || (b[bind2].key == key && b[bind2].mod == mod && b[bind2].joy == joy))
|
||||
continue;
|
||||
}
|
||||
if (bind2 == b.size()) {
|
||||
// release button
|
||||
joypress[game_key.player] &= ~bmask[game_key.key_num];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return is_game_key;
|
||||
return wxGameControlState::Instance().OnInputPressed(user_input);
|
||||
else
|
||||
return wxGameControlState::Instance().OnInputReleased(user_input);
|
||||
}
|
||||
|
||||
static void draw_black_background(wxWindow* win) {
|
||||
|
@ -1356,7 +1267,7 @@ static void process_keyboard_event(const wxKeyEvent& ev, bool down)
|
|||
break;
|
||||
}
|
||||
|
||||
if (process_user_input(down, wxUserInput::FromLegacyJoyKeyBinding({key, mod, 0}))) {
|
||||
if (process_user_input(down, wxUserInput::FromLegacyKeyModJoy(key, mod, 0))) {
|
||||
wxWakeUpIdle();
|
||||
};
|
||||
}
|
||||
|
@ -1403,17 +1314,17 @@ void GameArea::OnSDLJoy(wxJoyEvent& ev)
|
|||
// mutually exclusive key types unpress their opposite
|
||||
// TODO: Move creation of these "ghost" events to wxJoyPoller.
|
||||
if (mod == WXJB_AXIS_PLUS) {
|
||||
process_user_input(false, wxUserInput::FromLegacyJoyKeyBinding({key, WXJB_AXIS_MINUS, joy}));
|
||||
process_user_input(false, wxUserInput::FromLegacyKeyModJoy(key, WXJB_AXIS_MINUS, joy));
|
||||
process_user_input(ev.control_value() != 0, wxUserInput::FromJoyEvent(ev));
|
||||
} else if (mod == WXJB_AXIS_MINUS) {
|
||||
process_user_input(false, wxUserInput::FromLegacyJoyKeyBinding({key, WXJB_AXIS_PLUS, joy}));
|
||||
process_user_input(false, wxUserInput::FromLegacyKeyModJoy(key, WXJB_AXIS_PLUS, joy));
|
||||
process_user_input(ev.control_value() != 0, wxUserInput::FromJoyEvent(ev));
|
||||
} else if (mod >= WXJB_HAT_FIRST && mod <= WXJB_HAT_LAST) {
|
||||
int value = ev.control_value();
|
||||
process_user_input(value & SDL_HAT_UP, wxUserInput::FromLegacyJoyKeyBinding({key, WXJB_HAT_N, joy}));
|
||||
process_user_input(value & SDL_HAT_DOWN, wxUserInput::FromLegacyJoyKeyBinding({key, WXJB_HAT_S, joy}));
|
||||
process_user_input(value & SDL_HAT_RIGHT, wxUserInput::FromLegacyJoyKeyBinding({key, WXJB_HAT_E, joy}));
|
||||
process_user_input(value & SDL_HAT_LEFT, wxUserInput::FromLegacyJoyKeyBinding({key, WXJB_HAT_W, joy}));
|
||||
process_user_input(value & SDL_HAT_UP, wxUserInput::FromLegacyKeyModJoy(key, WXJB_HAT_N, joy));
|
||||
process_user_input(value & SDL_HAT_DOWN, wxUserInput::FromLegacyKeyModJoy(key, WXJB_HAT_S, joy));
|
||||
process_user_input(value & SDL_HAT_RIGHT, wxUserInput::FromLegacyKeyModJoy(key, WXJB_HAT_E, joy));
|
||||
process_user_input(value & SDL_HAT_LEFT, wxUserInput::FromLegacyKeyModJoy(key, WXJB_HAT_W, joy));
|
||||
} else {
|
||||
process_user_input(ev.control_value() != 0, wxUserInput::FromJoyEvent(ev));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "../common/SoundSDL.h"
|
||||
#include "wx/gamecontrol.h"
|
||||
#include "wxvbam.h"
|
||||
#include "SDL.h"
|
||||
#include <wx/ffile.h>
|
||||
|
@ -28,7 +29,7 @@ uint16_t systemGbPalette[24] = {
|
|||
int RGB_LOW_BITS_MASK;
|
||||
|
||||
// these are local, though.
|
||||
int joypress[4], autofire, autohold;
|
||||
int autofire, autohold;
|
||||
static int sensorx[4], sensory[4], sensorz[4];
|
||||
bool pause_next;
|
||||
bool turbo;
|
||||
|
@ -251,7 +252,7 @@ uint32_t systemReadJoypad(int joy)
|
|||
if (joy < 0 || joy > 3)
|
||||
joy = gopts.default_stick - 1;
|
||||
|
||||
uint32_t ret = joypress[joy];
|
||||
uint32_t ret = wxGameControlState::Instance().GetJoypad(joy);
|
||||
|
||||
if (turbo)
|
||||
ret |= KEYM_SPEED;
|
||||
|
@ -533,13 +534,14 @@ void systemUpdateSolarSensor()
|
|||
void systemUpdateMotionSensor()
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
const uint32_t joy_value = wxGameControlState::Instance().GetJoypad(i);
|
||||
if (!sensorx[i])
|
||||
sensorx[i] = 2047;
|
||||
|
||||
if (!sensory[i])
|
||||
sensory[i] = 2047;
|
||||
|
||||
if (joypress[i] & KEYM_MOTION_LEFT) {
|
||||
if (joy_value & KEYM_MOTION_LEFT) {
|
||||
sunBars--;
|
||||
|
||||
if (sunBars < 1)
|
||||
|
@ -552,7 +554,7 @@ void systemUpdateMotionSensor()
|
|||
|
||||
if (sensorx[i] < 2047)
|
||||
sensorx[i] = 2057;
|
||||
} else if (joypress[i] & KEYM_MOTION_RIGHT) {
|
||||
} else if (joy_value & KEYM_MOTION_RIGHT) {
|
||||
sunBars++;
|
||||
|
||||
if (sunBars > 100)
|
||||
|
@ -577,7 +579,7 @@ void systemUpdateMotionSensor()
|
|||
sensorx[i] = 2047;
|
||||
}
|
||||
|
||||
if (joypress[i] & KEYM_MOTION_UP) {
|
||||
if (joy_value & KEYM_MOTION_UP) {
|
||||
sensory[i] += 3;
|
||||
|
||||
if (sensory[i] > 2197)
|
||||
|
@ -585,7 +587,7 @@ void systemUpdateMotionSensor()
|
|||
|
||||
if (sensory[i] < 2047)
|
||||
sensory[i] = 2057;
|
||||
} else if (joypress[i] & KEYM_MOTION_DOWN) {
|
||||
} else if (joy_value & KEYM_MOTION_DOWN) {
|
||||
sensory[i] -= 3;
|
||||
|
||||
if (sensory[i] < 1897)
|
||||
|
@ -610,7 +612,7 @@ void systemUpdateMotionSensor()
|
|||
const int highZ = 1800;
|
||||
const int accelZ = 3;
|
||||
|
||||
if (joypress[i] & KEYM_MOTION_IN) {
|
||||
if (joy_value & KEYM_MOTION_IN) {
|
||||
sensorz[i] += accelZ;
|
||||
|
||||
if (sensorz[i] > highZ)
|
||||
|
@ -618,7 +620,7 @@ void systemUpdateMotionSensor()
|
|||
|
||||
if (sensorz[i] < centerZ)
|
||||
sensorz[i] = centerZ + (accelZ * 300);
|
||||
} else if (joypress[i] & KEYM_MOTION_OUT) {
|
||||
} else if (joy_value & KEYM_MOTION_OUT) {
|
||||
sensorz[i] -= accelZ;
|
||||
|
||||
if (sensorz[i] < lowZ)
|
||||
|
|
|
@ -0,0 +1,291 @@
|
|||
#include "wx/gamecontrol.h"
|
||||
|
||||
#include "../strutils.h"
|
||||
#include "opts.h"
|
||||
#include "wx/log.h"
|
||||
#include "wxlogdebug.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t kBitKeyA = (1 << 0);
|
||||
constexpr uint32_t kBitKeyB = (1 << 1);
|
||||
constexpr uint32_t kBitKeySelect = (1 << 2);
|
||||
constexpr uint32_t kBitKeyStart = (1 << 3);
|
||||
constexpr uint32_t kBitKeyRight = (1 << 4);
|
||||
constexpr uint32_t kBitKeyLeft = (1 << 5);
|
||||
constexpr uint32_t kBitKeyUp = (1 << 6);
|
||||
constexpr uint32_t kBitKeyDown = (1 << 7);
|
||||
constexpr uint32_t kBitKeyR = (1 << 8);
|
||||
constexpr uint32_t kBitKeyL = (1 << 9);
|
||||
constexpr uint32_t kBitKeySpeed = (1 << 10);
|
||||
constexpr uint32_t kBitKeyCapture = (1 << 11);
|
||||
constexpr uint32_t kBitKeyGameShark = (1 << 12);
|
||||
constexpr uint32_t kBitKeyAutoA = (1 << 13);
|
||||
constexpr uint32_t kBitKeyAutoB = (1 << 14);
|
||||
constexpr uint32_t kBitKeyMotionUp = (1 << 15);
|
||||
constexpr uint32_t kBitKeyMotionDown = (1 << 16);
|
||||
constexpr uint32_t kBitKeyMotionLeft = (1 << 17);
|
||||
constexpr uint32_t kBitKeyMotionRight = (1 << 18);
|
||||
constexpr uint32_t kBitKeyMotionIn = (1 << 19);
|
||||
constexpr uint32_t kBitKeyMotionOut = (1 << 20);
|
||||
|
||||
constexpr std::array<uint32_t, kNbGameKeys> kBitMask = {
|
||||
kBitKeyUp,
|
||||
kBitKeyDown,
|
||||
kBitKeyLeft,
|
||||
kBitKeyRight,
|
||||
kBitKeyA,
|
||||
kBitKeyB,
|
||||
kBitKeyL,
|
||||
kBitKeyR,
|
||||
kBitKeySelect,
|
||||
kBitKeyStart,
|
||||
kBitKeyMotionUp,
|
||||
kBitKeyMotionDown,
|
||||
kBitKeyMotionLeft,
|
||||
kBitKeyMotionRight,
|
||||
kBitKeyMotionIn,
|
||||
kBitKeyMotionOut,
|
||||
kBitKeyAutoA,
|
||||
kBitKeyAutoB,
|
||||
kBitKeySpeed,
|
||||
kBitKeyCapture,
|
||||
kBitKeyGameShark,
|
||||
};
|
||||
|
||||
inline int GameKeyToInt(const wxGameKey& game_key) {
|
||||
return static_cast<std::underlying_type<wxGameKey>::type>(
|
||||
game_key);
|
||||
}
|
||||
|
||||
// Returns true if `joypad` is in a valid joypad range.
|
||||
inline bool JoypadInRange(const int& joypad) {
|
||||
constexpr int kMinJoypadIndex = 0;
|
||||
return joypad >= kMinJoypadIndex && joypad < kNbJoypads;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
wxString GameKeyToString(const wxGameKey& game_key) {
|
||||
// Note: this must match GUI widget names or GUI won't work
|
||||
// This array's order determines tab order as well
|
||||
static const std::array<wxString, kNbGameKeys> kGameKeyStrings = {
|
||||
wxT("Up"),
|
||||
wxT("Down"),
|
||||
wxT("Left"),
|
||||
wxT("Right"),
|
||||
wxT("A"),
|
||||
wxT("B"),
|
||||
wxT("L"),
|
||||
wxT("R"),
|
||||
wxT("Select"),
|
||||
wxT("Start"),
|
||||
wxT("MotionUp"),
|
||||
wxT("MotionDown"),
|
||||
wxT("MotionLeft"),
|
||||
wxT("MotionRight"),
|
||||
wxT("MotionIn"),
|
||||
wxT("MotionOut"),
|
||||
wxT("AutoA"),
|
||||
wxT("AutoB"),
|
||||
wxT("Speed"),
|
||||
wxT("Capture"),
|
||||
wxT("GS"),
|
||||
};
|
||||
return kGameKeyStrings[GameKeyToInt(game_key)];
|
||||
}
|
||||
|
||||
std::optional<wxGameKey> StringToGameKey(const wxString& input) {
|
||||
static const std::map<wxString, wxGameKey> kStringToGameKey = {
|
||||
{ wxT("Up"), wxGameKey::Up },
|
||||
{ wxT("Down"), wxGameKey::Down },
|
||||
{ wxT("Left"), wxGameKey::Left },
|
||||
{ wxT("Right"), wxGameKey::Right },
|
||||
{ wxT("A"), wxGameKey::A },
|
||||
{ wxT("B"), wxGameKey::B },
|
||||
{ wxT("L"), wxGameKey::L },
|
||||
{ wxT("R"), wxGameKey::R },
|
||||
{ wxT("Select"), wxGameKey::Select },
|
||||
{ wxT("Start"), wxGameKey::Start },
|
||||
{ wxT("MotionUp"), wxGameKey::MotionUp },
|
||||
{ wxT("MotionDown"), wxGameKey::MotionDown },
|
||||
{ wxT("MotionLeft"), wxGameKey::MotionLeft },
|
||||
{ wxT("MotionRight"), wxGameKey::MotionRight },
|
||||
{ wxT("MotionIn"), wxGameKey::MotionIn },
|
||||
{ wxT("MotionOut"), wxGameKey::MotionOut },
|
||||
{ wxT("AutoA"), wxGameKey::AutoA },
|
||||
{ wxT("AutoB"), wxGameKey::AutoB },
|
||||
{ wxT("Speed"), wxGameKey::Speed },
|
||||
{ wxT("Capture"), wxGameKey::Capture },
|
||||
{ wxT("GS"), wxGameKey::Gameshark },
|
||||
};
|
||||
|
||||
const auto iter = kStringToGameKey.find(input);
|
||||
if (iter == kStringToGameKey.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
// static
|
||||
std::optional<wxGameControl> wxGameControl::FromString(const wxString &name) {
|
||||
static const wxString kJoypad(wxT("Joypad"));
|
||||
if (!wxStrncmp(name, kJoypad, kJoypad.size())) {
|
||||
wxLogDebug("Doesn't start with joypad");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto parts = str_split(name, wxT("/"));
|
||||
if (parts.size() != 3) {
|
||||
wxLogDebug("Wrong split size: %d", parts.size());
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const int joypad = parts[1][0] - wxT('1');
|
||||
if (!JoypadInRange(joypad)) {
|
||||
wxLogDebug("Wrong joypad index: %d", joypad);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<wxGameKey> game_key = StringToGameKey(parts[2]);
|
||||
if (!game_key) {
|
||||
wxLogDebug("Failed to parse game_key: %s", parts[2]);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return wxGameControl(joypad, game_key.value());
|
||||
}
|
||||
|
||||
wxGameControl::wxGameControl(int joypad, wxGameKey game_key) :
|
||||
joypad_(joypad),
|
||||
game_key_(game_key),
|
||||
config_string_(wxString::Format(
|
||||
wxT("Joypad/%d/%s"), joypad_ + 1, GameKeyToString(game_key_))) {
|
||||
assert(JoypadInRange(joypad_));
|
||||
}
|
||||
wxGameControl::~wxGameControl() = default;
|
||||
|
||||
bool wxGameControl::operator==(const wxGameControl& other) const {
|
||||
return joypad_ == other.joypad_ && game_key_ == other.game_key_;
|
||||
}
|
||||
bool wxGameControl::operator!=(const wxGameControl& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
bool wxGameControl::operator<(const wxGameControl& other) const {
|
||||
if (joypad_ != other.joypad_) {
|
||||
return joypad_ < other.joypad_;
|
||||
}
|
||||
if (game_key_ != other.game_key_) {
|
||||
return game_key_ < other.game_key_;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool wxGameControl::operator<=(const wxGameControl& other) const {
|
||||
return !(*this > other);
|
||||
}
|
||||
bool wxGameControl::operator>(const wxGameControl& other) const {
|
||||
return other < *this;
|
||||
}
|
||||
bool wxGameControl::operator>=(const wxGameControl& other) const {
|
||||
return !(*this < other);
|
||||
}
|
||||
|
||||
wxGameControlState& wxGameControlState::Instance() {
|
||||
static wxGameControlState g_game_control_state;
|
||||
return g_game_control_state;
|
||||
}
|
||||
|
||||
wxGameControlState::wxGameControlState() : joypads_({0, 0, 0, 0}) {}
|
||||
wxGameControlState::~wxGameControlState() = default;
|
||||
|
||||
bool wxGameControlState::OnInputPressed(const wxUserInput& user_input) {
|
||||
assert(user_input);
|
||||
|
||||
const auto& game_keys = input_bindings_.find(user_input);
|
||||
if (game_keys == input_bindings_.end()) {
|
||||
// No associated game control for `user_input`.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto iter = keys_pressed_.find(user_input);
|
||||
if (iter != keys_pressed_.end()) {
|
||||
// Double press is noop.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remember the key pressed.
|
||||
keys_pressed_.emplace(user_input);
|
||||
|
||||
// Update all corresponding controls.
|
||||
for (const wxGameControl& game_control : game_keys->second) {
|
||||
active_controls_[game_control].emplace(user_input);
|
||||
joypads_[game_control.joypad_] |=
|
||||
kBitMask[GameKeyToInt(game_control.game_key_)];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxGameControlState::OnInputReleased(const wxUserInput& user_input) {
|
||||
assert(user_input);
|
||||
|
||||
const auto& game_keys = input_bindings_.find(user_input);
|
||||
if (game_keys == input_bindings_.end()) {
|
||||
// No associated game control for `user_input`.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto iter = keys_pressed_.find(user_input);
|
||||
if (iter == keys_pressed_.end()) {
|
||||
// Double release is noop.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Release the key pressed.
|
||||
keys_pressed_.erase(iter);
|
||||
|
||||
// Update all corresponding controls.
|
||||
for (const wxGameControl& game_control : game_keys->second) {
|
||||
auto active_controls = active_controls_.find(game_control);
|
||||
if (active_controls == active_controls_.end()) {
|
||||
// This should never happen.
|
||||
assert(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
active_controls->second.erase(user_input);
|
||||
if (active_controls->second.empty()) {
|
||||
// Actually release control.
|
||||
active_controls_.erase(active_controls);
|
||||
joypads_[game_control.joypad_] &=
|
||||
~kBitMask[GameKeyToInt(game_control.game_key_)];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxGameControlState::Reset() {
|
||||
active_controls_.clear();
|
||||
keys_pressed_.clear();
|
||||
joypads_.fill(0);
|
||||
}
|
||||
|
||||
void wxGameControlState::OnGameBindingsChanged() {
|
||||
// We should reset to ensure no key remains accidentally pressed following a
|
||||
// configuration change.
|
||||
Reset();
|
||||
|
||||
input_bindings_.clear();
|
||||
for (const auto& iter : gopts.game_control_bindings) {
|
||||
for (const auto& user_input : iter.second) {
|
||||
input_bindings_[user_input].emplace(iter.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t wxGameControlState::GetJoypad(int joypad) const {
|
||||
assert(JoypadInRange(joypad));
|
||||
return joypads_[joypad];
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <wx/tokenzr.h>
|
||||
|
||||
#include "opts.h"
|
||||
#include "strutils.h"
|
||||
#include "wx/userinput.h"
|
||||
|
||||
|
@ -13,13 +14,6 @@ BEGIN_EVENT_TABLE(wxJoyKeyTextCtrl, wxKeyTextCtrl)
|
|||
EVT_SDLJOY(wxJoyKeyTextCtrl::OnJoy)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
// Initializer for struct wxJoyKeyBinding
|
||||
wxJoyKeyBinding newWxJoyKeyBinding(int key, int mod, int joy)
|
||||
{
|
||||
struct wxJoyKeyBinding tmp = {key, mod, joy};
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int wxJoyKeyTextCtrl::DigitalButton(const wxJoyEvent& event)
|
||||
{
|
||||
int16_t sdlval = event.control_value();
|
||||
|
@ -164,25 +158,6 @@ wxString wxJoyKeyTextCtrl::ToString(int mod, int key, int joy, bool isConfig)
|
|||
return s;
|
||||
}
|
||||
|
||||
wxString wxJoyKeyTextCtrl::ToString(wxJoyKeyBinding_v keys, wxChar sep, bool isConfig)
|
||||
{
|
||||
wxString ret;
|
||||
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
if (i > 0)
|
||||
ret += sep;
|
||||
|
||||
wxString key = ToString(keys[i].mod, keys[i].key, keys[i].joy, isConfig);
|
||||
|
||||
if (key.empty())
|
||||
return wxEmptyString;
|
||||
|
||||
ret += key;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
wxString wxJoyKeyTextCtrl::FromAccelToString(wxAcceleratorEntry_v keys, wxChar sep, bool isConfig)
|
||||
{
|
||||
wxString ret;
|
||||
|
@ -311,22 +286,6 @@ bool wxJoyKeyTextCtrl::FromString(const wxString& s, int& mod, int& key, int& jo
|
|||
return ParseString(s, s.size(), mod, key, joy);
|
||||
}
|
||||
|
||||
wxJoyKeyBinding_v wxJoyKeyTextCtrl::FromString(const wxString& s, wxChar sep)
|
||||
{
|
||||
wxJoyKeyBinding_v ret, empty;
|
||||
int mod, key, joy;
|
||||
if (s.size() == 0)
|
||||
return empty;
|
||||
|
||||
for (const auto& token : str_split_with_sep(s, sep)) {
|
||||
if (!ParseString(token, token.size(), mod, key, joy))
|
||||
return empty;
|
||||
wxJoyKeyBinding jb = { key, mod, joy };
|
||||
ret.insert(ret.begin(), jb);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
wxAcceleratorEntry_v wxJoyKeyTextCtrl::ToAccelFromString(const wxString& s, wxChar sep)
|
||||
{
|
||||
wxAcceleratorEntry_v ret, empty;
|
||||
|
@ -346,28 +305,22 @@ IMPLEMENT_CLASS(wxJoyKeyValidator, wxValidator)
|
|||
|
||||
bool wxJoyKeyValidator::TransferToWindow()
|
||||
{
|
||||
if (!val)
|
||||
return false;
|
||||
|
||||
wxJoyKeyTextCtrl* jk = wxDynamicCast(GetWindow(), wxJoyKeyTextCtrl);
|
||||
|
||||
if (!jk)
|
||||
return false;
|
||||
|
||||
jk->SetValue(wxJoyKeyTextCtrl::ToString(*val));
|
||||
jk->SetValue(wxUserInput::SpanToString(gopts.game_control_bindings[val_]));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxJoyKeyValidator::TransferFromWindow()
|
||||
{
|
||||
if (!val)
|
||||
return false;
|
||||
|
||||
wxJoyKeyTextCtrl* jk = wxDynamicCast(GetWindow(), wxJoyKeyTextCtrl);
|
||||
|
||||
if (!jk)
|
||||
return false;
|
||||
|
||||
*val = wxJoyKeyTextCtrl::FromString(jk->GetValue());
|
||||
gopts.game_control_bindings[val_] = wxUserInput::FromString(jk->GetValue());
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#include "wx/userinput.h"
|
||||
|
||||
#include "wx/joyedit.h"
|
||||
#include "wx/sdljoy.h"
|
||||
#include "wx/string.h"
|
||||
#include "wxutil.h"
|
||||
#include "../../wx/strutils.h"
|
||||
|
||||
// static
|
||||
wxUserInput wxUserInput::Invalid() {
|
||||
|
@ -25,33 +28,47 @@ wxUserInput wxUserInput::FromJoyEvent(const wxJoyEvent& event) {
|
|||
}
|
||||
|
||||
// static
|
||||
wxUserInput wxUserInput::FromLegacyJoyKeyBinding(const wxJoyKeyBinding& binding) {
|
||||
return wxUserInput(binding.joy == 0 ? Device::Keyboard : Device::Joystick,
|
||||
binding.mod,
|
||||
binding.key,
|
||||
binding.joy);
|
||||
wxUserInput wxUserInput::FromLegacyKeyModJoy(int key, int mod, int joy) {
|
||||
return wxUserInput(joy == 0 ? Device::Keyboard : Device::Joystick,
|
||||
mod,
|
||||
key,
|
||||
joy);
|
||||
}
|
||||
|
||||
// static
|
||||
wxUserInput wxUserInput::FromString(const wxString& string) {
|
||||
// TODO: Move the implementation here once all callers have been updated.
|
||||
int mod = 0;
|
||||
int key = 0;
|
||||
int joy = 0;
|
||||
if (!wxJoyKeyTextCtrl::FromString(string, mod, key, joy)) {
|
||||
return wxUserInput::Invalid();
|
||||
}
|
||||
return wxUserInput::FromLegacyJoyKeyBinding({key, mod, joy});
|
||||
std::set<wxUserInput> wxUserInput::FromString(const wxString& string) {
|
||||
std::set<wxUserInput> user_inputs;
|
||||
|
||||
if (string.empty()) {
|
||||
return user_inputs;
|
||||
}
|
||||
|
||||
wxString wxUserInput::ToString() {
|
||||
if (!config_string_.IsNull()) {
|
||||
return config_string_;
|
||||
for (const auto& token : str_split_with_sep(string, wxT(","))) {
|
||||
int mod, key, joy;
|
||||
if (!wxJoyKeyTextCtrl::ParseString(token, token.size(), mod, key, joy)) {
|
||||
user_inputs.clear();
|
||||
return user_inputs;
|
||||
}
|
||||
user_inputs.emplace(FromLegacyKeyModJoy(key, mod, joy));
|
||||
}
|
||||
return user_inputs;
|
||||
}
|
||||
|
||||
// static
|
||||
wxString wxUserInput::SpanToString(const std::set<wxUserInput>& user_inputs, bool is_config) {
|
||||
wxString config_string;
|
||||
if (user_inputs.empty()) {
|
||||
return config_string;
|
||||
}
|
||||
for (const wxUserInput& user_input : user_inputs) {
|
||||
config_string += user_input.ToString(is_config) + wxT(',');
|
||||
}
|
||||
return config_string.SubString(0, config_string.size() - 2);
|
||||
}
|
||||
|
||||
wxString wxUserInput::ToString(bool is_config) const {
|
||||
// TODO: Move the implementation here once all callers have been updated.
|
||||
config_string_ = wxJoyKeyTextCtrl::ToString(mod_, key_, joy_);
|
||||
return config_string_;
|
||||
return wxJoyKeyTextCtrl::ToString(mod_, key_, joy_, is_config);
|
||||
}
|
||||
|
||||
bool wxUserInput::operator==(const wxUserInput& other) const {
|
||||
|
@ -89,6 +106,7 @@ bool wxUserInput::operator>=(const wxUserInput& other) const {
|
|||
// Actual underlying constructor.
|
||||
wxUserInput::wxUserInput(Device device, int mod, uint8_t key, unsigned joy) :
|
||||
device_(device),
|
||||
joystick_(joy == 0 ? wxJoystick::Invalid() : wxJoystick::FromLegacyPlayerIndex(joy)),
|
||||
mod_(mod),
|
||||
key_(key),
|
||||
joy_(joy) {}
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
#ifndef _WX_GAME_CONTROL_H_
|
||||
#define _WX_GAME_CONTROL_H_
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <wx/string.h>
|
||||
|
||||
#include "wx/userinput.h"
|
||||
|
||||
// Forward declaration.
|
||||
class wxGameControlState;
|
||||
|
||||
// Represents an in-game input.
|
||||
enum class wxGameKey {
|
||||
Up = 0,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
A,
|
||||
B,
|
||||
L,
|
||||
R,
|
||||
Select,
|
||||
Start,
|
||||
MotionUp,
|
||||
MotionDown,
|
||||
MotionLeft,
|
||||
MotionRight,
|
||||
MotionIn,
|
||||
MotionOut,
|
||||
AutoA,
|
||||
AutoB,
|
||||
Speed,
|
||||
Capture,
|
||||
Gameshark,
|
||||
Last = Gameshark
|
||||
};
|
||||
|
||||
inline constexpr int kNbGameKeys =
|
||||
static_cast<std::underlying_type<wxGameKey>::type>(wxGameKey::Last) + 1;
|
||||
inline constexpr int kNbJoypads = 4;
|
||||
|
||||
inline constexpr std::array<wxGameKey, kNbGameKeys> kAllGameKeys = {
|
||||
wxGameKey::Up,
|
||||
wxGameKey::Down,
|
||||
wxGameKey::Left,
|
||||
wxGameKey::Right,
|
||||
wxGameKey::A,
|
||||
wxGameKey::B,
|
||||
wxGameKey::L,
|
||||
wxGameKey::R,
|
||||
wxGameKey::Select,
|
||||
wxGameKey::Start,
|
||||
wxGameKey::MotionUp,
|
||||
wxGameKey::MotionDown,
|
||||
wxGameKey::MotionLeft,
|
||||
wxGameKey::MotionRight,
|
||||
wxGameKey::MotionIn,
|
||||
wxGameKey::MotionOut,
|
||||
wxGameKey::AutoA,
|
||||
wxGameKey::AutoB,
|
||||
wxGameKey::Speed,
|
||||
wxGameKey::Capture,
|
||||
wxGameKey::Gameshark,
|
||||
};
|
||||
|
||||
// Conversion utility method. Returns empty string on failure.
|
||||
// This is O(1).
|
||||
wxString GameKeyToString(const wxGameKey& game_key);
|
||||
|
||||
// Conversion utility method. Returns std::nullopt on failure.
|
||||
// This is O(log(kNbGameKeys)).
|
||||
std::optional<wxGameKey> StringToGameKey(const wxString& input);
|
||||
|
||||
// Abstraction for an in-game control, wich is made of a player index (from 0
|
||||
// to 3), and a wxGameKey.
|
||||
class wxGameControl {
|
||||
public:
|
||||
// Converts a string to a wxGameControl. Returns std::nullopt on failure.
|
||||
static std::optional<wxGameControl> FromString(const wxString& name);
|
||||
|
||||
wxGameControl(int joypad, wxGameKey game_key);
|
||||
~wxGameControl();
|
||||
|
||||
wxString ToString() const { return config_string_; };
|
||||
|
||||
bool operator==(const wxGameControl& other) const;
|
||||
bool operator!=(const wxGameControl& other) const;
|
||||
bool operator<(const wxGameControl& other) const;
|
||||
bool operator<=(const wxGameControl& other) const;
|
||||
bool operator>(const wxGameControl& other) const;
|
||||
bool operator>=(const wxGameControl& other) const;
|
||||
|
||||
private:
|
||||
const int joypad_;
|
||||
const wxGameKey game_key_;
|
||||
const wxString config_string_;
|
||||
|
||||
friend class wxGameControlState;
|
||||
};
|
||||
|
||||
// Tracks in-game input and computes the joypad value used to send control input
|
||||
// data to the emulator.
|
||||
class wxGameControlState {
|
||||
public:
|
||||
// This is a global singleton.
|
||||
static wxGameControlState& Instance();
|
||||
|
||||
// Disable copy constructor and assignment operator.
|
||||
wxGameControlState(const wxGameControlState&) = delete;
|
||||
wxGameControlState& operator=(const wxGameControlState&) = delete;
|
||||
|
||||
// Processes `user_input` and updates the internal tracking state.
|
||||
// Returns true if `user_input` corresponds to a game input.
|
||||
bool OnInputPressed(const wxUserInput& user_input);
|
||||
bool OnInputReleased(const wxUserInput& user_input);
|
||||
|
||||
// Clears all input.
|
||||
void Reset();
|
||||
|
||||
// Recomputes internal bindinds. This is a potentially slow operation and
|
||||
// should only be called when the game input configuration has been changed.
|
||||
void OnGameBindingsChanged();
|
||||
|
||||
uint32_t GetJoypad(int joypad) const;
|
||||
|
||||
private:
|
||||
wxGameControlState();
|
||||
~wxGameControlState();
|
||||
|
||||
std::map<wxUserInput, std::set<wxGameControl>> input_bindings_;
|
||||
std::map<wxGameControl, std::set<wxUserInput>> active_controls_;
|
||||
std::set<wxUserInput> keys_pressed_;
|
||||
std::array<uint32_t, kNbJoypads> joypads_;
|
||||
};
|
||||
|
||||
#endif // _WX_GAME_CONTROL_H_
|
|
@ -5,20 +5,10 @@
|
|||
// The value is the symbolic name of the key pressed
|
||||
// Supports manual clearing (bs), multiple keys in widget, automatic tab on key
|
||||
|
||||
#include "wx/gamecontrol.h"
|
||||
#include "wx/keyedit.h"
|
||||
#include "wx/sdljoy.h"
|
||||
|
||||
typedef struct wxJoyKeyBinding {
|
||||
int key; // key code; listed first for easy static init
|
||||
int mod; // modifier flags
|
||||
int joy; // joystick # (starting at 1)
|
||||
// if joy is non-0, key = control number, and mod = control type
|
||||
} wxJoyKeyBinding;
|
||||
|
||||
// Initializer for struct wxJoyKeyBinding
|
||||
wxJoyKeyBinding newWxJoyKeyBinding(int key = 0, int mod = 0, int joy = 0);
|
||||
|
||||
typedef std::vector<wxJoyKeyBinding> wxJoyKeyBinding_v;
|
||||
#include "wx/userinput.h"
|
||||
|
||||
// joystick control types
|
||||
// mod for joysticks
|
||||
|
@ -52,13 +42,8 @@ public:
|
|||
static int DigitalButton(const wxJoyEvent& event);
|
||||
// convert mod+key to accel string, separated by -
|
||||
static wxString ToString(int mod, int key, int joy, bool isConfig = false);
|
||||
// convert multiple keys, separated by multikey
|
||||
static wxString ToString(wxJoyKeyBinding_v keys, wxChar sep = wxT(','), bool isConfig = false);
|
||||
// parses single key string into mod+key
|
||||
static bool FromString(const wxString& s, int& mod, int& key, int& joy);
|
||||
// parse multi-key string into array
|
||||
// returns empty array on parse errors
|
||||
static wxJoyKeyBinding_v FromString(const wxString& s, wxChar sep = wxT(','));
|
||||
// parse a single key in given wxChar array up to given len
|
||||
static bool ParseString(const wxString& s, int len, int& mod, int& key, int& joy);
|
||||
// parse multi-key string into array
|
||||
|
@ -77,30 +62,30 @@ protected:
|
|||
// A simple copy-only validator
|
||||
class wxJoyKeyValidator : public wxValidator {
|
||||
public:
|
||||
wxJoyKeyValidator(wxJoyKeyBinding_v* v)
|
||||
wxJoyKeyValidator(const wxGameControl v)
|
||||
: wxValidator()
|
||||
, val(v)
|
||||
, val_(v)
|
||||
{
|
||||
}
|
||||
wxJoyKeyValidator(const wxJoyKeyValidator& v)
|
||||
: wxValidator()
|
||||
, val(v.val)
|
||||
, val_(v.val_)
|
||||
{
|
||||
}
|
||||
wxObject* Clone() const
|
||||
wxObject* Clone() const override
|
||||
{
|
||||
return new wxJoyKeyValidator(val);
|
||||
return new wxJoyKeyValidator(val_);
|
||||
}
|
||||
bool TransferToWindow();
|
||||
bool TransferFromWindow();
|
||||
bool Validate(wxWindow* p)
|
||||
bool TransferToWindow() override;
|
||||
bool TransferFromWindow() override;
|
||||
bool Validate(wxWindow* p) override
|
||||
{
|
||||
(void)p; // unused params
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
wxJoyKeyBinding_v* val;
|
||||
const wxGameControl val_;
|
||||
|
||||
DECLARE_CLASS(wxJoyKeyValidator)
|
||||
};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef _WX_USER_INPUT_H_
|
||||
#define _WX_USER_INPUT_H_
|
||||
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <wx/event.h>
|
||||
|
||||
#include "wx/joyedit.h"
|
||||
#include "wx/sdljoy.h"
|
||||
|
||||
// Abstraction for a user input, which can come from a keyboard or a joystick.
|
||||
|
@ -12,7 +12,7 @@
|
|||
//
|
||||
// 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 wxJoyKeyBinding type, which
|
||||
// This is to ease a transition away from the key, mod, joy triplet, which
|
||||
// wxUserInput will eventually replace.
|
||||
class wxUserInput {
|
||||
public:
|
||||
|
@ -33,21 +33,25 @@ public:
|
|||
// Constructor from a wxJoyEvent.
|
||||
static wxUserInput FromJoyEvent(const wxJoyEvent& event);
|
||||
|
||||
// Constructor from a configuration string. Returns wxUserInput::Invalid()
|
||||
// on parsing failure.
|
||||
static wxUserInput FromString(const wxString& string);
|
||||
// Constructor from a configuration string. Returns empty set on failure.
|
||||
static std::set<wxUserInput> FromString(const wxString& string);
|
||||
|
||||
// TODO: Remove this once all uses of wxJoyKeyBinding have been removed.
|
||||
static wxUserInput FromLegacyJoyKeyBinding(const wxJoyKeyBinding& binding);
|
||||
// TODO: Remove this once all uses have been removed.
|
||||
static wxUserInput FromLegacyKeyModJoy(int key = 0, int mod = 0, int joy = 0);
|
||||
|
||||
// Converts to a configuration string. Computed on first call, and cached
|
||||
// for further calls.
|
||||
wxString ToString();
|
||||
// Converts a set of wxUserInput 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 SpanToString(
|
||||
const std::set<wxUserInput>& user_inputs, bool is_config = false);
|
||||
|
||||
// TODO: Remove these accessors once all callers have been removed.
|
||||
int mod() const { return mod_; }
|
||||
int key() const { return key_; }
|
||||
int joy() const { return joy_; }
|
||||
// Converts to a configuration string.
|
||||
wxString ToString(bool is_config = false) const;
|
||||
|
||||
wxJoystick joystick() const { return joystick_; }
|
||||
bool is_valid() const { return device_ != Device::Invalid; }
|
||||
operator bool() const { return is_valid(); }
|
||||
|
||||
bool operator==(const wxUserInput& other) const;
|
||||
bool operator!=(const wxUserInput& other) const;
|
||||
|
@ -59,12 +63,11 @@ public:
|
|||
private:
|
||||
wxUserInput(Device device, int mod, uint8_t key, unsigned joy);
|
||||
|
||||
Device device_;
|
||||
int mod_;
|
||||
uint8_t key_;
|
||||
unsigned joy_;
|
||||
|
||||
wxString config_string_;
|
||||
const Device device_;
|
||||
const wxJoystick joystick_;
|
||||
const int mod_;
|
||||
const uint8_t key_;
|
||||
const unsigned joy_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
// The built-in vba-over.ini
|
||||
#include "builtin-over.h"
|
||||
#include "wx/gamecontrol.h"
|
||||
#include "wx/userinput.h"
|
||||
|
||||
IMPLEMENT_APP(wxvbamApp)
|
||||
|
@ -178,8 +179,6 @@ wxString wxvbamApp::GetConfigurationPath()
|
|||
break;
|
||||
}
|
||||
}
|
||||
// use default keys for input.
|
||||
set_default_keys();
|
||||
}
|
||||
|
||||
return data_path;
|
||||
|
@ -430,6 +429,10 @@ bool wxvbamApp::OnInit()
|
|||
}
|
||||
}
|
||||
|
||||
// Initialize game bindings here, after defaults bindings, vbam.ini bindings
|
||||
// and command line overrides have been applied.
|
||||
wxGameControlState::Instance().OnGameBindingsChanged();
|
||||
|
||||
// create the main window
|
||||
int x = windowPositionX;
|
||||
int y = windowPositionY;
|
||||
|
@ -933,19 +936,12 @@ void MainFrame::SetJoystick()
|
|||
return;
|
||||
|
||||
std::set<wxJoystick> needed_joysticks;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < NUM_KEYS; j++) {
|
||||
wxJoyKeyBinding_v b = gopts.joykey_bindings[i][j];
|
||||
for (size_t k = 0; k < b.size(); k++) {
|
||||
int jn = b[k].joy;
|
||||
if (jn) {
|
||||
needed_joysticks.insert(
|
||||
wxJoystick::FromLegacyPlayerIndex(jn));
|
||||
for (const auto& iter : gopts.game_control_bindings) {
|
||||
for (const auto& input_iter : iter.second) {
|
||||
needed_joysticks.emplace(input_iter.joystick());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
joy.PollJoysticks(needed_joysticks);
|
||||
joy.PollJoysticks(std::move(needed_joysticks));
|
||||
}
|
||||
|
||||
void MainFrame::StopJoyPollTimer()
|
||||
|
|
|
@ -805,8 +805,7 @@ void systemStopGamePlayback();
|
|||
// true if turbo mode (like pressing turbo button constantly)
|
||||
extern bool turbo;
|
||||
|
||||
// mask of key press flags; see below
|
||||
extern int joypress[4], autofire, autohold;
|
||||
extern int autofire, autohold;
|
||||
|
||||
// FIXME: these defines should be global to project and used instead of raw numbers
|
||||
#define KEYM_A (1 << 0)
|
||||
|
|
Loading…
Reference in New Issue