Joystick handling refactor.
Use the SDL GameController API with SDL events instead of polling manually. Run SDL_PollEvent() in the panel OnIdle(). The API to the GUI remains the same, the sending of wxSDLJoyEvent events. Except there are no more hat events, we just use the GameController buttons. Also the GUI now has to make arrangements for wxSDLJoy::Poll() to be called periodically, for the config dialog this is done with a timer. All Xbox 360 controller buttons and axes are now in the defaults, and the SDL GameController API will map them to the appropriate keys on other controllers. As a consequence of using SDL events, controller attach/detach from the system is now also handled correctly. It is no longer necessary to have the controller attached and turned on when the program launches. Signed-off-by: Rafael Kitover <rkitover@gmail.com>
This commit is contained in:
parent
d458e75ca6
commit
02520fb63e
|
@ -4,9 +4,7 @@ src/wx/cmd-evtable.h
|
|||
src/wx/cmdhandlers.h
|
||||
src/wx/cmdtab.cpp
|
||||
src/wx/wxvbam.xrs
|
||||
build/*
|
||||
build32/*
|
||||
vsbuild/*
|
||||
*build*/*
|
||||
cmake-build*
|
||||
dependencies/*
|
||||
vcpkg/*
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-09-06 19:39-0300\n"
|
||||
"POT-Creation-Date: 2019-11-22 23:25+0000\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"
|
||||
|
@ -166,12 +166,12 @@ msgstr ""
|
|||
msgid "ROM+HuC-1"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/cmdevents.cpp:746 ../src/wx/guiinit.cpp:1829
|
||||
#: ../src/wx/cmdevents.cpp:746 ../src/wx/guiinit.cpp:1839
|
||||
#: ../src/wx/xrc/DisplayConfig.xrc:85 ../src/wx/xrc/DisplayConfig.xrc:135
|
||||
#: ../src/wx/xrc/DisplayConfig.xrc:221
|
||||
#: ../src/wx/xrc/GameBoyAdvanceConfig.xrc:32
|
||||
#: ../src/wx/xrc/GameBoyAdvanceConfig.xrc:204
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:152 ../src/wx/xrc/SoundConfig.xrc:219
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:114 ../src/wx/xrc/SoundConfig.xrc:219
|
||||
#: ../src/wx/xrc/SoundConfig.xrc:309 ../src/wx/xrc/SpeedupConfig.xrc:45
|
||||
#: ../src/wx/xrc/SpeedupConfig.xrc:120
|
||||
msgid "None"
|
||||
|
@ -204,7 +204,7 @@ msgstr ""
|
|||
msgid "Confirm import"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/cmdevents.cpp:898 ../src/wx/panel.cpp:344
|
||||
#: ../src/wx/cmdevents.cpp:898 ../src/wx/panel.cpp:350
|
||||
#, c-format
|
||||
msgid "Loaded battery %s"
|
||||
msgstr ""
|
||||
|
@ -287,7 +287,7 @@ msgstr ""
|
|||
msgid "Wrote battery %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/cmdevents.cpp:1091 ../src/wx/panel.cpp:651
|
||||
#: ../src/wx/cmdevents.cpp:1091 ../src/wx/panel.cpp:656
|
||||
#, c-format
|
||||
msgid "Error writing battery %s"
|
||||
msgstr ""
|
||||
|
@ -405,18 +405,18 @@ msgstr ""
|
|||
msgid "Using interframe blending #%d"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/cmdevents.cpp:2747
|
||||
#: ../src/wx/cmdevents.cpp:2752
|
||||
msgid "Nintendo GameBoy (+Color+Advance) emulator."
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/cmdevents.cpp:2748
|
||||
#: ../src/wx/cmdevents.cpp:2753
|
||||
msgid ""
|
||||
"Copyright (C) 1999-2003 Forgotten\n"
|
||||
"Copyright (C) 2004-2006 VBA development team\n"
|
||||
"Copyright (C) 2007-2017 VBA-M development team"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/cmdevents.cpp:2749
|
||||
#: ../src/wx/cmdevents.cpp:2754
|
||||
msgid ""
|
||||
"This program is free software: you can redistribute it and/or modify\n"
|
||||
"it under the terms of the GNU General Public License as published by\n"
|
||||
|
@ -432,11 +432,11 @@ msgid ""
|
|||
"along with this program. If not, see http://www.gnu.org/licenses ."
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/cmdevents.cpp:3011
|
||||
#: ../src/wx/cmdevents.cpp:3018
|
||||
msgid "LAN link is already active. Disable link mode to disconnect."
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/cmdevents.cpp:3017
|
||||
#: ../src/wx/cmdevents.cpp:3024
|
||||
msgid "Network is not supported in local mode."
|
||||
msgstr ""
|
||||
|
||||
|
@ -554,7 +554,7 @@ msgstr ""
|
|||
msgid "VBA cheat lists (*.clt)|*.clt|CHT cheat lists (*.cht)|*.cht"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:239 ../src/wx/panel.cpp:401
|
||||
#: ../src/wx/guiinit.cpp:239 ../src/wx/panel.cpp:407
|
||||
msgid "Loaded cheats"
|
||||
msgstr ""
|
||||
|
||||
|
@ -640,122 +640,122 @@ msgstr ""
|
|||
msgid "Default device"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:1709
|
||||
#: ../src/wx/guiinit.cpp:1719
|
||||
msgid "Desktop mode"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:1716
|
||||
#: ../src/wx/guiinit.cpp:1726
|
||||
#, c-format
|
||||
msgid "%d x %d - %dbpp @ %dHz"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:1870
|
||||
#: ../src/wx/guiinit.cpp:1880
|
||||
#, c-format
|
||||
msgid "No usable rpi plugins found in %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:1890 ../src/wx/xrc/DisplayConfig.xrc:107
|
||||
#: ../src/wx/guiinit.cpp:1900 ../src/wx/xrc/DisplayConfig.xrc:107
|
||||
msgid "Plugin"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:1918
|
||||
#: ../src/wx/guiinit.cpp:1928
|
||||
msgid "Please select a plugin or a different filter"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:1919
|
||||
#: ../src/wx/guiinit.cpp:1929
|
||||
msgid "Plugin selection error"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:2118
|
||||
#: ../src/wx/guiinit.cpp:2128
|
||||
msgid "This will clear all user-defined accelerators. Are you sure?"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:2118
|
||||
#: ../src/wx/guiinit.cpp:2128
|
||||
msgid "Confirm"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:2712
|
||||
#: ../src/wx/guiinit.cpp:2722
|
||||
msgid "Main icon not found"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:2722
|
||||
#: ../src/wx/guiinit.cpp:2732
|
||||
msgid "Browse"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:2736
|
||||
#: ../src/wx/guiinit.cpp:2746
|
||||
msgid "Main display panel not found"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:2875
|
||||
#: ../src/wx/guiinit.cpp:2895
|
||||
#, c-format
|
||||
msgid "Duplicate menu accelerator: %s for %s and %s; keeping first"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:2889
|
||||
#: ../src/wx/guiinit.cpp:2909
|
||||
#, c-format
|
||||
msgid "Menu accelerator %s for %s overrides default for %s ; keeping menu"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:3013
|
||||
#: ../src/wx/guiinit.cpp:3039
|
||||
#, c-format
|
||||
msgid "Invalid menu item %s; removing"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:3208
|
||||
#: ../src/wx/guiinit.cpp:3234
|
||||
msgid "Code"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:3217
|
||||
#: ../src/wx/guiinit.cpp:3243
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:3291 ../src/wx/xrc/CheatAdd.xrc:31
|
||||
#: ../src/wx/guiinit.cpp:3317 ../src/wx/xrc/CheatAdd.xrc:31
|
||||
msgid "Address"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:3292
|
||||
#: ../src/wx/guiinit.cpp:3318
|
||||
msgid "Old Value"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:3293
|
||||
#: ../src/wx/guiinit.cpp:3319
|
||||
msgid "New Value"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:3836
|
||||
#: ../src/wx/guiinit.cpp:3839
|
||||
msgid "Menu commands"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:3859
|
||||
#: ../src/wx/guiinit.cpp:3862
|
||||
msgid "Other commands"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/guiinit.cpp:3970
|
||||
#: ../src/wx/guiinit.cpp:3973
|
||||
msgid "JoyBus host invalid; disabling"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/opts.cpp:555 ../src/wx/opts.cpp:851
|
||||
#: ../src/wx/opts.cpp:548 ../src/wx/opts.cpp:849
|
||||
#, c-format
|
||||
msgid "Invalid value %s for option %s; valid values are %s%s%s"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/opts.cpp:572 ../src/wx/opts.cpp:863
|
||||
#: ../src/wx/opts.cpp:565 ../src/wx/opts.cpp:861
|
||||
#, c-format
|
||||
msgid "Invalid value %d for option %s; valid values are %d - %d"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/opts.cpp:579 ../src/wx/opts.cpp:588 ../src/wx/opts.cpp:871
|
||||
#: ../src/wx/opts.cpp:879
|
||||
#: ../src/wx/opts.cpp:572 ../src/wx/opts.cpp:581 ../src/wx/opts.cpp:869
|
||||
#: ../src/wx/opts.cpp:877
|
||||
#, c-format
|
||||
msgid "Invalid value %f for option %s; valid values are %f - %f"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/opts.cpp:648 ../src/wx/opts.cpp:669 ../src/wx/opts.cpp:948
|
||||
#: ../src/wx/opts.cpp:974
|
||||
#: ../src/wx/opts.cpp:641 ../src/wx/opts.cpp:662 ../src/wx/opts.cpp:946
|
||||
#: ../src/wx/opts.cpp:972
|
||||
#, c-format
|
||||
msgid "Invalid key binding %s for %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/opts.cpp:834
|
||||
#: ../src/wx/opts.cpp:832
|
||||
#, c-format
|
||||
msgid "Invalid flag option %s - %s ignored"
|
||||
msgstr ""
|
||||
|
@ -774,7 +774,7 @@ msgstr ""
|
|||
msgid "Unable to load Game Boy ROM %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:185 ../src/wx/panel.cpp:275
|
||||
#: ../src/wx/panel.cpp:185 ../src/wx/panel.cpp:281
|
||||
#, c-format
|
||||
msgid "Could not load BIOS %s"
|
||||
msgstr ""
|
||||
|
@ -784,103 +784,103 @@ msgstr ""
|
|||
msgid "Unable to load Game Boy Advance ROM %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:434
|
||||
#: ../src/wx/panel.cpp:439
|
||||
msgid " player "
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:599
|
||||
#: ../src/wx/panel.cpp:604
|
||||
#, c-format
|
||||
msgid "Loaded state %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:599
|
||||
#: ../src/wx/panel.cpp:604
|
||||
#, c-format
|
||||
msgid "Error loading state %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:623
|
||||
#: ../src/wx/panel.cpp:628
|
||||
#, c-format
|
||||
msgid "Saved state %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:623
|
||||
#: ../src/wx/panel.cpp:628
|
||||
#, c-format
|
||||
msgid "Error saving state %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:827
|
||||
#: ../src/wx/panel.cpp:832
|
||||
#, c-format
|
||||
msgid "Fullscreen mode %dx%d-%d@%d not supported; looking for another"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:865
|
||||
#: ../src/wx/panel.cpp:870
|
||||
#, c-format
|
||||
msgid "Fullscreen mode %dx%d-%d@%d not supported"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:870
|
||||
#: ../src/wx/panel.cpp:875
|
||||
#, c-format
|
||||
msgid "Valid mode: %dx%d-%d@%d"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:878
|
||||
#: ../src/wx/panel.cpp:883
|
||||
#, c-format
|
||||
msgid "Chose mode %dx%d-%d@%d"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:882
|
||||
#: ../src/wx/panel.cpp:887
|
||||
#, c-format
|
||||
msgid "Failed to change mode to %dx%d-%d@%d"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:966
|
||||
#: ../src/wx/panel.cpp:971
|
||||
msgid "Not a valid GBA cartridge"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:1107
|
||||
#: ../src/wx/panel.cpp:1113
|
||||
msgid "No memory for rewinding"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:1117
|
||||
#: ../src/wx/panel.cpp:1123
|
||||
msgid "Error writing rewind state"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:2329
|
||||
#: ../src/wx/panel.cpp:2334
|
||||
msgid "memory allocation error"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:2332
|
||||
#: ../src/wx/panel.cpp:2337
|
||||
msgid "error initializing codec"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:2335
|
||||
#: ../src/wx/panel.cpp:2340
|
||||
msgid "error writing to output file"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:2338
|
||||
#: ../src/wx/panel.cpp:2343
|
||||
msgid "can't guess output format from file name"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:2343
|
||||
#: ../src/wx/panel.cpp:2348
|
||||
msgid "programming error; aborting!"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:2360 ../src/wx/panel.cpp:2391
|
||||
#: ../src/wx/panel.cpp:2365 ../src/wx/panel.cpp:2396
|
||||
#, c-format
|
||||
msgid "Unable to begin recording to %s (%s)"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:2419
|
||||
#: ../src/wx/panel.cpp:2424
|
||||
#, c-format
|
||||
msgid "Error in audio/video recording (%s); aborting"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:2425
|
||||
#: ../src/wx/panel.cpp:2430
|
||||
#, c-format
|
||||
msgid "Error in audio recording (%s); aborting"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/panel.cpp:2435
|
||||
#: ../src/wx/panel.cpp:2440
|
||||
#, c-format
|
||||
msgid "Error in video recording (%s); aborting"
|
||||
msgstr ""
|
||||
|
@ -925,37 +925,37 @@ msgstr ""
|
|||
msgid "%d%%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/sys.cpp:757 ../src/wx/xrc/GBPrinter.xrc:65
|
||||
#: ../src/wx/sys.cpp:760 ../src/wx/xrc/GBPrinter.xrc:65
|
||||
msgid "&Discard"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/sys.cpp:791
|
||||
#: ../src/wx/sys.cpp:794
|
||||
msgid "Image files (*.bmp;*.jpg;*.png)|*.bmp;*.jpg;*.png|"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/sys.cpp:800
|
||||
#: ../src/wx/sys.cpp:803
|
||||
msgid "Save printer image to"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/sys.cpp:814 ../src/wx/sys.cpp:997
|
||||
#: ../src/wx/sys.cpp:817 ../src/wx/sys.cpp:1000
|
||||
#, c-format
|
||||
msgid "Wrote printer output to %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/sys.cpp:819 ../src/wx/sys.cpp:890
|
||||
#: ../src/wx/sys.cpp:822 ../src/wx/sys.cpp:893
|
||||
msgid "&Close"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/sys.cpp:885
|
||||
#: ../src/wx/sys.cpp:888
|
||||
msgid "Printed"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/sys.cpp:1187
|
||||
#: ../src/wx/sys.cpp:1190
|
||||
#, c-format
|
||||
msgid "Error opening pseudo tty: %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/sys.cpp:1286
|
||||
#: ../src/wx/sys.cpp:1289
|
||||
#, c-format
|
||||
msgid "Error setting up server socket (%d)"
|
||||
msgstr ""
|
||||
|
@ -1048,51 +1048,51 @@ msgstr ""
|
|||
msgid "B:"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:203
|
||||
#: ../src/wx/wxvbam.cpp:222
|
||||
msgid "visualboyadvance-m"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:417
|
||||
#: ../src/wx/wxvbam.cpp:436
|
||||
msgid "Could not create main window"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:484
|
||||
#: ../src/wx/wxvbam.cpp:507
|
||||
msgid "Save built-in XRC file and exit"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:487
|
||||
#: ../src/wx/wxvbam.cpp:510
|
||||
msgid "Save built-in vba-over.ini and exit"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:490
|
||||
#: ../src/wx/wxvbam.cpp:513
|
||||
msgid "Print configuration path and exit"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:493
|
||||
#: ../src/wx/wxvbam.cpp:516
|
||||
msgid "Start in full-screen mode"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:497
|
||||
#: ../src/wx/wxvbam.cpp:520
|
||||
msgid "Delete shared link state first, if it exists"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:504
|
||||
#: ../src/wx/wxvbam.cpp:527
|
||||
msgid "List all settable options and exit"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:507
|
||||
#: ../src/wx/wxvbam.cpp:530
|
||||
msgid "ROM file"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:509
|
||||
#: ../src/wx/wxvbam.cpp:532
|
||||
msgid "<config>=<value>"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:540
|
||||
#: ../src/wx/wxvbam.cpp:563
|
||||
msgid "Configuration/build error: can't find built-in xrc"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:548
|
||||
#: ../src/wx/wxvbam.cpp:571
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Wrote built-in configuration to %s.\n"
|
||||
|
@ -1101,11 +1101,11 @@ msgid ""
|
|||
"built-in:"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:563
|
||||
#: ../src/wx/wxvbam.cpp:586
|
||||
msgid "Configuration is read from, in order:"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:577
|
||||
#: ../src/wx/wxvbam.cpp:600
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Wrote built-in override file to %s\n"
|
||||
|
@ -1113,13 +1113,13 @@ msgid ""
|
|||
"from search path:"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:583
|
||||
#: ../src/wx/wxvbam.cpp:606
|
||||
msgid ""
|
||||
"\n"
|
||||
"\tbuilt-in"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:594
|
||||
#: ../src/wx/wxvbam.cpp:617
|
||||
msgid ""
|
||||
"Options set from the command line are saved if any configuration changes are "
|
||||
"made in the user interface.\n"
|
||||
|
@ -1128,13 +1128,13 @@ msgid ""
|
|||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:615
|
||||
#: ../src/wx/wxvbam.cpp:638
|
||||
msgid ""
|
||||
"The commands available for the Keyboard/* option are:\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/wxvbam.cpp:649
|
||||
#: ../src/wx/wxvbam.cpp:672
|
||||
msgid "Bad configuration option or multiple ROM files given:\n"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1203,6 +1203,16 @@ msgstr ""
|
|||
msgid "CONTROL"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/widgets/sdljoy.cpp:105
|
||||
#, c-format
|
||||
msgid "Connected game controller %d"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/widgets/sdljoy.cpp:115
|
||||
#, c-format
|
||||
msgid "Disconnected game controller %d"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/AccelConfig.xrc:4
|
||||
msgid "Key Shortcuts"
|
||||
msgstr ""
|
||||
|
@ -2356,152 +2366,136 @@ msgid "General"
|
|||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:26
|
||||
msgid "Check for updates:"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:33
|
||||
msgid "&Never"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:42
|
||||
msgid "&Daily"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:50
|
||||
msgid "&Weekly"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:64
|
||||
msgid "Screenshot Format:"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:71
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:33
|
||||
msgid "&PNG"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:80
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:42
|
||||
msgid "&BMP"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:95
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:57
|
||||
msgid "&Rewind interval :"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:96
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:58
|
||||
msgid "If not empty or 0, enable rewind (seconds)"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:105
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:67
|
||||
msgid "seconds (0-600); 0 = disable"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:116
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:78
|
||||
msgid "&Throttle"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:134 ../src/wx/xrc/SpeedupConfig.xrc:27
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:96 ../src/wx/xrc/SpeedupConfig.xrc:27
|
||||
#, c-format
|
||||
msgid "% of normal:"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:144
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:106
|
||||
msgid "0 = no throttle"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:153 ../src/wx/xrc/SpeedupConfig.xrc:46
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:115 ../src/wx/xrc/SpeedupConfig.xrc:46
|
||||
msgid "25%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:154 ../src/wx/xrc/SpeedupConfig.xrc:47
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:116 ../src/wx/xrc/SpeedupConfig.xrc:47
|
||||
msgid "50%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:155 ../src/wx/xrc/SpeedupConfig.xrc:48
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:117 ../src/wx/xrc/SpeedupConfig.xrc:48
|
||||
msgid "75%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:156 ../src/wx/xrc/SoundConfig.xrc:45
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:118 ../src/wx/xrc/SoundConfig.xrc:45
|
||||
#: ../src/wx/xrc/SpeedupConfig.xrc:49
|
||||
msgid "100%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:157 ../src/wx/xrc/SpeedupConfig.xrc:50
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:119 ../src/wx/xrc/SpeedupConfig.xrc:50
|
||||
msgid "125%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:158 ../src/wx/xrc/SpeedupConfig.xrc:51
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:120 ../src/wx/xrc/SpeedupConfig.xrc:51
|
||||
msgid "150%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:159 ../src/wx/xrc/SpeedupConfig.xrc:52
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:121 ../src/wx/xrc/SpeedupConfig.xrc:52
|
||||
msgid "175%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:160 ../src/wx/xrc/SpeedupConfig.xrc:53
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:122 ../src/wx/xrc/SpeedupConfig.xrc:53
|
||||
msgid "200%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:161 ../src/wx/xrc/SpeedupConfig.xrc:54
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:123 ../src/wx/xrc/SpeedupConfig.xrc:54
|
||||
msgid "225%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:162 ../src/wx/xrc/SpeedupConfig.xrc:55
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:124 ../src/wx/xrc/SpeedupConfig.xrc:55
|
||||
msgid "250%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:163 ../src/wx/xrc/SpeedupConfig.xrc:56
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:125 ../src/wx/xrc/SpeedupConfig.xrc:56
|
||||
msgid "275%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:164 ../src/wx/xrc/SpeedupConfig.xrc:57
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:126 ../src/wx/xrc/SpeedupConfig.xrc:57
|
||||
msgid "300%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:165 ../src/wx/xrc/SpeedupConfig.xrc:58
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:127 ../src/wx/xrc/SpeedupConfig.xrc:58
|
||||
msgid "325%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:166 ../src/wx/xrc/SpeedupConfig.xrc:59
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:128 ../src/wx/xrc/SpeedupConfig.xrc:59
|
||||
msgid "350%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:167 ../src/wx/xrc/SpeedupConfig.xrc:60
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:129 ../src/wx/xrc/SpeedupConfig.xrc:60
|
||||
msgid "375%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:168 ../src/wx/xrc/SpeedupConfig.xrc:61
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:130 ../src/wx/xrc/SpeedupConfig.xrc:61
|
||||
msgid "400%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:169 ../src/wx/xrc/SpeedupConfig.xrc:62
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:131 ../src/wx/xrc/SpeedupConfig.xrc:62
|
||||
msgid "425%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:170 ../src/wx/xrc/SpeedupConfig.xrc:63
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:132 ../src/wx/xrc/SpeedupConfig.xrc:63
|
||||
msgid "450%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:171 ../src/wx/xrc/SpeedupConfig.xrc:64
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:133 ../src/wx/xrc/SpeedupConfig.xrc:64
|
||||
msgid "475%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:172 ../src/wx/xrc/SpeedupConfig.xrc:65
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:134 ../src/wx/xrc/SpeedupConfig.xrc:65
|
||||
msgid "500%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:173 ../src/wx/xrc/SpeedupConfig.xrc:66
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:135 ../src/wx/xrc/SpeedupConfig.xrc:66
|
||||
msgid "525%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:174 ../src/wx/xrc/SpeedupConfig.xrc:67
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:136 ../src/wx/xrc/SpeedupConfig.xrc:67
|
||||
msgid "550%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:175 ../src/wx/xrc/SpeedupConfig.xrc:68
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:137 ../src/wx/xrc/SpeedupConfig.xrc:68
|
||||
msgid "575%"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:176 ../src/wx/xrc/SpeedupConfig.xrc:69
|
||||
#: ../src/wx/xrc/GeneralConfig.xrc:138 ../src/wx/xrc/SpeedupConfig.xrc:69
|
||||
msgid "600%"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3413,6 +3407,10 @@ msgstr ""
|
|||
msgid "Translations"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/MainMenu.xrc:709
|
||||
msgid "Check for updates"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/wx/xrc/MainMenu.xrc:712
|
||||
msgid "&Factory Reset..."
|
||||
msgstr ""
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <SDL_events.h>
|
||||
#include "SoundSDL.h"
|
||||
#include "ConfigManager.h"
|
||||
#include "../gba/Globals.h"
|
||||
|
@ -148,6 +149,12 @@ bool SoundSDL::init(long sampleRate) {
|
|||
data_available = SDL_CreateSemaphore(0);
|
||||
data_read = SDL_CreateSemaphore(1);
|
||||
|
||||
// turn off audio events because we are not processing them
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 4)
|
||||
SDL_EventState(SDL_AUDIODEVICEADDED, SDL_IGNORE);
|
||||
SDL_EventState(SDL_AUDIODEVICEREMOVED, SDL_IGNORE);
|
||||
#endif
|
||||
|
||||
return initialized = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef CONTAINS_HPP_
|
||||
#define CONTAINS_HPP_
|
||||
|
||||
template <class C, class V>
|
||||
bool contains(const C& container, const V& val)
|
||||
{
|
||||
return (container.find(val) != container.end());
|
||||
}
|
||||
|
||||
#endif /* CONTAINS_HPP_ */
|
|
@ -0,0 +1,669 @@
|
|||
/*
|
||||
Range
|
||||
=====
|
||||
|
||||
Copyright (c) 2009-2011 Khaled Alshaya
|
||||
|
||||
Distributed under the Boost Software License, version 1.0
|
||||
(See the license at: http://www.boost.org/license_1_0.txt).
|
||||
*/
|
||||
|
||||
/*
|
||||
Rationale
|
||||
=========
|
||||
|
||||
In Python, there is a beautiful function called "range".
|
||||
"range" allows the programmer to iterate over a range elegantly.
|
||||
This concept is not as general as "for-loops" in C++,
|
||||
but non the less, it expresses the intent of the programmer
|
||||
clearer than the general "for-loops" in many cases.
|
||||
|
||||
|
||||
Design
|
||||
======
|
||||
|
||||
Range is made to be STL-like library. In fact, it is
|
||||
built on top of the concepts of STL. The library is designed to
|
||||
work with STL algorithms as well. Range is more flexible
|
||||
than the Python "range", because:
|
||||
|
||||
Range is an "immutable ordered random access container"
|
||||
|
||||
|
||||
Specifications
|
||||
==============
|
||||
|
||||
Range satisfies the following requirements:
|
||||
|
||||
* Immutable.
|
||||
* Random Access Container.
|
||||
* Random Access Iterator Interface.
|
||||
* Constant Time Complexity Operations.
|
||||
|
||||
|
||||
Range models an ordered sequence of elements,
|
||||
where a range is defined by:
|
||||
|
||||
[begin, end)
|
||||
|
||||
* begin: the first element in the range. (Inclusive)
|
||||
* end : the last element in the range. (Exclusive)
|
||||
* step : the distance between two consecutive elements in a range.
|
||||
|
||||
where each element in the range is defined by:
|
||||
|
||||
element = begin + step * i
|
||||
|
||||
* i: is the index of the element in range.
|
||||
|
||||
The following precondition must be met for the sequence
|
||||
to be a valid range:
|
||||
|
||||
step != 0
|
||||
&&
|
||||
(
|
||||
begin <= end && step > 0
|
||||
||
|
||||
begin >= end && step < 0
|
||||
)
|
||||
|
||||
|
||||
Portability
|
||||
===========
|
||||
|
||||
Range Generator is written in standard C++ (C++98). It depends
|
||||
-only- on the standard C++ library.
|
||||
*/
|
||||
|
||||
#ifndef range_h__
|
||||
#define range_h__
|
||||
|
||||
// using std::range
|
||||
// using std::size_t from <cstddef>
|
||||
// using std::ceil from <cmath>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <cstddef>
|
||||
#include <cmath>
|
||||
|
||||
namespace Range
|
||||
{
|
||||
template <class IntegerType>
|
||||
struct basic_range
|
||||
{
|
||||
struct const_iterator_impl
|
||||
{
|
||||
typedef IntegerType value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef IntegerType difference_type;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type& reference;
|
||||
typedef
|
||||
std::random_access_iterator_tag
|
||||
iterator_category;
|
||||
|
||||
const_iterator_impl(): r(0), index(0)
|
||||
{ }
|
||||
|
||||
const_iterator_impl(const const_iterator_impl& rhs)
|
||||
: r(rhs.r), index(rhs.index)
|
||||
{ }
|
||||
|
||||
const_iterator_impl(basic_range<IntegerType> const * p_range, size_type p_index)
|
||||
:r(p_range), index(p_index)
|
||||
{ }
|
||||
|
||||
const_iterator_impl& operator=(const const_iterator_impl& rhs)
|
||||
{
|
||||
r = rhs.r;
|
||||
index = rhs.index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const const_iterator_impl& rhs) const
|
||||
{
|
||||
return *r == *(rhs.r) && index == rhs.index;
|
||||
}
|
||||
|
||||
bool operator!=(const const_iterator_impl& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
bool operator<(const const_iterator_impl& rhs) const
|
||||
{
|
||||
return index < rhs.index;
|
||||
}
|
||||
|
||||
bool operator>(const const_iterator_impl& rhs) const
|
||||
{
|
||||
return index > rhs.index;
|
||||
}
|
||||
|
||||
bool operator<=(const const_iterator_impl& rhs) const
|
||||
{
|
||||
return index <= rhs.index;
|
||||
}
|
||||
|
||||
bool operator>=(const const_iterator_impl& rhs) const
|
||||
{
|
||||
return index >= rhs.index;
|
||||
}
|
||||
|
||||
value_type operator*() const
|
||||
{
|
||||
return r->m_first_element + r->m_step*index;
|
||||
}
|
||||
|
||||
// operator->
|
||||
// is not implemented because the value_type is an integer type
|
||||
// and primitive types in C++ don't define member functions.
|
||||
|
||||
const_iterator_impl& operator++()
|
||||
{
|
||||
++index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator_impl operator++(int)
|
||||
{
|
||||
const_iterator_impl temp = *this;
|
||||
++index;
|
||||
return temp;
|
||||
}
|
||||
|
||||
const_iterator_impl& operator--()
|
||||
{
|
||||
--index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator_impl operator--(int)
|
||||
{
|
||||
const_iterator_impl temp = *this;
|
||||
--index;
|
||||
return temp;
|
||||
}
|
||||
|
||||
const_iterator_impl& operator+=(difference_type increment)
|
||||
{
|
||||
index += increment;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// operator+
|
||||
// is friend operator but operator-
|
||||
// is not, because we want to allow the following for "+":
|
||||
// iterator+5
|
||||
// 5+iterator
|
||||
// For the "-" it is not correct to do so, because
|
||||
// iterator-5 != 5-iterator
|
||||
friend const_iterator_impl operator+
|
||||
(const const_iterator_impl& lhs, difference_type increment)
|
||||
{
|
||||
const_iterator_impl sum;
|
||||
sum.r = lhs.r;
|
||||
sum.index = lhs.index + increment;
|
||||
return sum;
|
||||
}
|
||||
|
||||
const_iterator_impl& operator-=(difference_type decrement)
|
||||
{
|
||||
index -= decrement;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator_impl operator-(difference_type decrement) const
|
||||
{
|
||||
const_iterator_impl shifted_iterator;
|
||||
shifted_iterator.r = r;
|
||||
shifted_iterator.index = index - decrement;
|
||||
return shifted_iterator;
|
||||
}
|
||||
|
||||
difference_type operator-(const const_iterator_impl& rhs) const
|
||||
{
|
||||
return index - rhs.index;
|
||||
}
|
||||
|
||||
value_type operator[](difference_type offset) const
|
||||
{
|
||||
size_type new_index = index + offset;
|
||||
return r->m_first_element + r->m_step*new_index;
|
||||
}
|
||||
|
||||
private:
|
||||
basic_range<IntegerType> const * r;
|
||||
size_type index;
|
||||
};
|
||||
|
||||
|
||||
struct const_reverse_iterator_impl
|
||||
{
|
||||
typedef IntegerType value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef IntegerType difference_type;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type& reference;
|
||||
typedef
|
||||
std::random_access_iterator_tag
|
||||
iterator_category;
|
||||
|
||||
|
||||
const_reverse_iterator_impl(): r(0), index(0)
|
||||
{ }
|
||||
|
||||
const_reverse_iterator_impl(const const_reverse_iterator_impl& rhs)
|
||||
: r(rhs.r), index(rhs.index)
|
||||
{ }
|
||||
|
||||
const_reverse_iterator_impl(basic_range<IntegerType> const * p_range, size_type p_index)
|
||||
:r(p_range), index(p_index)
|
||||
{ }
|
||||
|
||||
const_reverse_iterator_impl& operator=(const const_reverse_iterator_impl& rhs)
|
||||
{
|
||||
r = rhs.r;
|
||||
index = rhs.index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const const_reverse_iterator_impl& rhs) const
|
||||
{
|
||||
return *r == *(rhs.r) && index == rhs.index;
|
||||
}
|
||||
|
||||
bool operator!=(const const_reverse_iterator_impl& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
bool operator<(const const_reverse_iterator_impl& rhs) const
|
||||
{
|
||||
return index < rhs.index;
|
||||
}
|
||||
|
||||
bool operator>(const const_reverse_iterator_impl& rhs) const
|
||||
{
|
||||
return index > rhs.index;
|
||||
}
|
||||
|
||||
bool operator<=(const const_reverse_iterator_impl& rhs) const
|
||||
{
|
||||
return index <= rhs.index;
|
||||
}
|
||||
|
||||
bool operator>=(const const_reverse_iterator_impl& rhs) const
|
||||
{
|
||||
return index >= rhs.index;
|
||||
}
|
||||
|
||||
value_type operator*() const
|
||||
{
|
||||
size_type reverse_index
|
||||
= (r->m_element_count - 1) - index;
|
||||
return r->m_first_element + r->m_step*reverse_index;
|
||||
}
|
||||
|
||||
// operator->
|
||||
// is not implemented because the value_type is integer type
|
||||
// and primitive types in C++ don't define member functions.
|
||||
|
||||
const_reverse_iterator_impl& operator++()
|
||||
{
|
||||
++index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_reverse_iterator_impl operator++(int)
|
||||
{
|
||||
const_reverse_iterator_impl temp = *this;
|
||||
++index;
|
||||
return temp;
|
||||
}
|
||||
|
||||
const_reverse_iterator_impl& operator--()
|
||||
{
|
||||
--index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_reverse_iterator_impl operator--(int)
|
||||
{
|
||||
const_reverse_iterator_impl temp = *this;
|
||||
--index;
|
||||
return temp;
|
||||
}
|
||||
|
||||
const_reverse_iterator_impl& operator+=(difference_type increment)
|
||||
{
|
||||
index += increment;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// operator+
|
||||
// is friend operator but operator-
|
||||
// is not, because we want to allow the following for "+":
|
||||
// iterator+5
|
||||
// 5+iterator
|
||||
// For the "-" it is not correct to do so, because
|
||||
// iterator-5 != 5-iterator
|
||||
friend const_reverse_iterator_impl operator+
|
||||
(const const_reverse_iterator_impl& lhs, difference_type increment)
|
||||
{
|
||||
const_reverse_iterator_impl sum;
|
||||
sum.r = lhs.r;
|
||||
sum.index = lhs.index + increment;
|
||||
return sum;
|
||||
}
|
||||
|
||||
const_reverse_iterator_impl& operator-=(difference_type decrement)
|
||||
{
|
||||
index -= decrement;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_reverse_iterator_impl operator-(difference_type decrement) const
|
||||
{
|
||||
const_reverse_iterator_impl shifted_iterator;
|
||||
shifted_iterator.r = r;
|
||||
shifted_iterator.index = index - decrement;
|
||||
return shifted_iterator;
|
||||
}
|
||||
|
||||
difference_type operator-(const const_reverse_iterator_impl& rhs) const
|
||||
{
|
||||
return index - rhs.index;
|
||||
}
|
||||
|
||||
value_type operator[](difference_type offset) const
|
||||
{
|
||||
size_type new_reverse_index
|
||||
= (r->m_element_count - 1) - (index + offset);
|
||||
return r->m_first_element + r->m_step*new_reverse_index;
|
||||
}
|
||||
|
||||
private:
|
||||
basic_range<IntegerType> const * r;
|
||||
size_type index;
|
||||
};
|
||||
|
||||
typedef IntegerType value_type;
|
||||
typedef const_iterator_impl iterator;
|
||||
typedef const_iterator_impl const_iterator;
|
||||
typedef const_reverse_iterator_impl reverse_iterator;
|
||||
typedef const_reverse_iterator_impl const_reverse_iterator;
|
||||
typedef value_type& reference;
|
||||
typedef const value_type& const_reference;
|
||||
typedef value_type* pointer;
|
||||
typedef IntegerType difference_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// In the case of default construction,
|
||||
// the range is considered as an empty range with no elements.
|
||||
// step can be anything other than 0. 1 is
|
||||
// an implementation convention, and it doesn't have
|
||||
// a significance in this case because the range is empty.
|
||||
basic_range(): m_first_element(0), m_element_count(0), m_step(1)
|
||||
{ }
|
||||
|
||||
// first_element: is begin in specifications.
|
||||
// last_element: is end in specifications.
|
||||
basic_range(value_type first_element, value_type last_element, value_type step)
|
||||
: m_first_element(first_element),
|
||||
m_step(step)
|
||||
{
|
||||
// We need to count the number of elements.
|
||||
// The only case where a range is invalid,
|
||||
// when the step=0. It means that the range
|
||||
// is infinite, because the number of elements
|
||||
// in a range, is the length of that range
|
||||
// divided by the difference between
|
||||
// every two successive elements.
|
||||
|
||||
if(step == 0)
|
||||
throw std::out_of_range("Invalid Range: step can't be equal to zero!");
|
||||
if(first_element < last_element && step < 0)
|
||||
throw std::out_of_range("Invalid Range: step can't be backward, while the range is forward!");
|
||||
if(first_element > last_element && step > 0)
|
||||
throw std::out_of_range("Invalid Range: step can't be forward, while the range is backward!");
|
||||
|
||||
m_element_count = (last_element-first_element)/step;
|
||||
if( (last_element-first_element)%step != 0 )
|
||||
++m_element_count;
|
||||
}
|
||||
|
||||
// The following constructor, determines the step
|
||||
// automatically. If the range is forward, then
|
||||
// step will be one. If the range is backward,
|
||||
// step will be minus one. If the begin is equal
|
||||
// to end, then the step must not equal to zero
|
||||
// and it is set to one as a convention.
|
||||
basic_range(value_type first_element, value_type last_element)
|
||||
: m_first_element(first_element)
|
||||
{
|
||||
if(last_element >= first_element) *this = basic_range<IntegerType>(first_element, last_element, 1);
|
||||
else *this = basic_range<IntegerType>(first_element, last_element, -1);
|
||||
|
||||
}
|
||||
|
||||
// The following constructor is a shortcut
|
||||
// if you want the first element as zero.
|
||||
// the step is determined automatically, based
|
||||
// on the last element. If the last element is
|
||||
// positive, then step is one, but if it is negative
|
||||
// then step is minus one.
|
||||
basic_range<IntegerType>(value_type last_element)
|
||||
: m_first_element(0)
|
||||
{
|
||||
if(last_element >= m_first_element) *this = basic_range<IntegerType>(m_first_element, last_element, 1);
|
||||
else *this = basic_range<IntegerType>(m_first_element, last_element, -1);
|
||||
}
|
||||
|
||||
basic_range<IntegerType>(const basic_range<IntegerType>& r)
|
||||
: m_first_element(r.m_first_element),
|
||||
m_element_count(r.m_element_count),
|
||||
m_step(r.m_step)
|
||||
{ }
|
||||
|
||||
basic_range<IntegerType>& operator=(const basic_range<IntegerType>& r)
|
||||
{
|
||||
m_first_element = r.m_first_element;
|
||||
m_element_count = r.m_element_count;
|
||||
m_step = r.m_step;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const basic_range<IntegerType>& r) const
|
||||
{
|
||||
return m_first_element == r.m_first_element
|
||||
&&
|
||||
m_element_count == r.m_element_count
|
||||
&&
|
||||
m_step == r.m_step;
|
||||
}
|
||||
|
||||
bool operator!=(const basic_range<IntegerType>& r) const
|
||||
{
|
||||
return !(*this == r);
|
||||
}
|
||||
|
||||
// The following four functions enable the user to compare
|
||||
// ranges using ( <, >, <=, >=).
|
||||
// The comparison between two ranges is a simple lexicographical
|
||||
// comparison(element by element). By convention, if two ranges
|
||||
// R1, R2 where R1 has a smaller number of elements. Then if
|
||||
// R1 contains more elements but all R1 elements are found in R2
|
||||
// R1 is considered less than R2.
|
||||
bool operator<(const basic_range<IntegerType>& r) const
|
||||
{
|
||||
// ********** This function needs refactoring.
|
||||
|
||||
if(m_element_count == 0 && r.m_element_count == 0)
|
||||
return false;
|
||||
if(m_element_count == 0 && r.m_element_count > 0)
|
||||
return true;
|
||||
if(m_element_count > 0 && r.m_element_count == 0)
|
||||
return false;
|
||||
|
||||
// At this point, both has at least one element.
|
||||
if(m_first_element < r.m_first_element)
|
||||
return true;
|
||||
if(m_first_element > r.m_first_element)
|
||||
return false;
|
||||
|
||||
// At this point, the first element of both are equal.
|
||||
if(m_element_count == 1 && r.m_element_count == 1)
|
||||
return false;
|
||||
if(m_element_count == 1 && r.m_element_count > 1)
|
||||
return true;
|
||||
if(m_element_count > 1 && r.m_element_count == 1)
|
||||
return false;
|
||||
|
||||
// At this point, both have at least two elements with
|
||||
// a similar first element. Note than the final answer
|
||||
// in this case depends on the second element only, because
|
||||
// we don't need to compare the elements further.
|
||||
// Note that the second element is at (index == 1), because
|
||||
// the first element is at (index == 0).
|
||||
if(m_first_element+m_step*1 < r.m_first_element+r.m_step*1)
|
||||
return true;
|
||||
if(m_first_element+m_step*1 > r.m_first_element+r.m_step*1)
|
||||
return false;
|
||||
|
||||
// if the first two elements of both ranges are equal, then
|
||||
// they are co-linear ranges(because the step is constant).
|
||||
// In that case, they comparison depends only on
|
||||
// the size of the ranges by convention.
|
||||
return m_element_count < r.m_element_count;
|
||||
}
|
||||
|
||||
bool operator>(const basic_range<IntegerType>& r) const
|
||||
{
|
||||
// ********** This function needs refactoring.
|
||||
|
||||
if(m_element_count == 0 && r.m_element_count == 0)
|
||||
return false;
|
||||
if(m_element_count == 0 && r.m_element_count > 0)
|
||||
return false;
|
||||
if(m_element_count > 0 && r.m_element_count == 0)
|
||||
return true;
|
||||
|
||||
// At this point, both has at least one element.
|
||||
if(m_first_element < r.m_first_element)
|
||||
return false;
|
||||
if(m_first_element > r.m_first_element)
|
||||
return true;
|
||||
|
||||
// At this point, the first element of both are equal.
|
||||
if(m_element_count == 1 && r.m_element_count == 1)
|
||||
return false;
|
||||
if(m_element_count == 1 && r.m_element_count > 1)
|
||||
return false;
|
||||
if(m_element_count > 1 && r.m_element_count == 1)
|
||||
return true;
|
||||
|
||||
// At this point, both have at least two elements with
|
||||
// a similar first element. Note than the final answer
|
||||
// in this case depends on the second element only, because
|
||||
// we don't need to compare the elements further.
|
||||
// Note that the second element is at (index == 1), because
|
||||
// the first element is at (index == 0).
|
||||
if(m_first_element+m_step*1 < r.m_first_element+r.m_step*1)
|
||||
return false;
|
||||
if(m_first_element+m_step*1 > r.m_first_element+r.m_step*1)
|
||||
return true;
|
||||
|
||||
// if the first two elements of both ranges are equal, then
|
||||
// they are co-linear ranges(because the step is constant).
|
||||
// In that case, they comparison depends only on
|
||||
// the size of the ranges by convention.
|
||||
return m_element_count > r.m_element_count;
|
||||
}
|
||||
|
||||
bool operator <=(const basic_range<IntegerType>& r) const
|
||||
{
|
||||
return !(*this > r);
|
||||
}
|
||||
|
||||
bool operator >=(const basic_range<IntegerType>& r) const
|
||||
{
|
||||
return !(*this < r);
|
||||
}
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return const_iterator(this, 0);
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return const_iterator(this, m_element_count);
|
||||
}
|
||||
|
||||
const_reverse_iterator rbegin() const
|
||||
{
|
||||
return const_reverse_iterator(this, 0);
|
||||
}
|
||||
|
||||
const_reverse_iterator rend() const
|
||||
{
|
||||
return const_reverse_iterator(this, m_element_count);
|
||||
}
|
||||
|
||||
size_type size() const
|
||||
{
|
||||
return m_element_count;
|
||||
}
|
||||
|
||||
size_type max_size() const
|
||||
{
|
||||
// Because this is an immutable container,
|
||||
// max_size() == size()
|
||||
return m_element_count;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return m_element_count == 0;
|
||||
}
|
||||
|
||||
// exist() and find() are similar except that
|
||||
// find() returns the index of the element.
|
||||
iterator find(value_type element) const
|
||||
{
|
||||
value_type element_index = (element - m_first_element) / m_step;
|
||||
bool in_range = element_index >= 0 && element_index < m_element_count &&
|
||||
(element - m_first_element) % m_step == 0;
|
||||
if(in_range)
|
||||
return begin() + element_index;
|
||||
return end();
|
||||
}
|
||||
|
||||
bool exist(value_type element) const
|
||||
{
|
||||
return find(element) != end();
|
||||
}
|
||||
|
||||
// In the standard, the operator[]
|
||||
// should return a const reference.
|
||||
// Because Range Generator doesn't store its elements
|
||||
// internally, we return a copy of the value.
|
||||
// In any case, this doesn't affect the semantics of the operator.
|
||||
value_type operator[](size_type index) const
|
||||
{
|
||||
return m_first_element + m_step*index;
|
||||
}
|
||||
|
||||
private:
|
||||
// m_first_element: begin (see specifications).
|
||||
// m_element_count: (end - begin) / step
|
||||
value_type m_first_element, m_element_count, m_step;
|
||||
};
|
||||
|
||||
// This is the default type of range!
|
||||
typedef basic_range<int> range;
|
||||
}
|
||||
|
||||
#endif // range_h__
|
|
@ -681,6 +681,7 @@ endif()
|
|||
set(
|
||||
HDR_WX
|
||||
wxvbam.h
|
||||
wxlogdebug.h
|
||||
drawing.h
|
||||
filters.h
|
||||
ioregs.h
|
||||
|
@ -698,6 +699,8 @@ set(
|
|||
# from external source with minor modifications
|
||||
widgets/wx/checkedlistctrl.h
|
||||
../common/version_cpp.h
|
||||
../common/range.hpp
|
||||
../common/contains.h
|
||||
)
|
||||
|
||||
if(WIN32 AND (AMD64 OR X86_32) AND ENABLE_ONLINEUPDATES)
|
||||
|
|
|
@ -1669,11 +1669,8 @@ public:
|
|||
if (defkeys_keyboard[i].key)
|
||||
a.push_back(defkeys_keyboard[i]);
|
||||
|
||||
if (defkeys_joystick[i].joy)
|
||||
a.push_back(defkeys_joystick[i]);
|
||||
|
||||
if (extrakeys_joystick[i].joy)
|
||||
a.push_back(extrakeys_joystick[i]);
|
||||
for (auto bind : defkeys_joystick[i])
|
||||
a.push_back(bind);
|
||||
|
||||
tc->SetValue(wxJoyKeyTextCtrl::ToString(a));
|
||||
}
|
||||
|
@ -1681,6 +1678,19 @@ public:
|
|||
}
|
||||
} JoyPadConfigHandler[4];
|
||||
|
||||
class JoystickPoller : public wxTimer {
|
||||
public:
|
||||
void Notify() {
|
||||
wxGetApp().frame->PollJoysticks();
|
||||
}
|
||||
void ShowDialog(wxShowEvent& ev) {
|
||||
if (ev.IsShown())
|
||||
Start(50);
|
||||
else
|
||||
Stop();
|
||||
}
|
||||
};
|
||||
|
||||
// manage fullscreen mode widget
|
||||
// technically, it's more than a validator: it modifies the widget as well
|
||||
class ScreenModeList : public wxValidator {
|
||||
|
@ -3787,6 +3797,14 @@ bool MainFrame::BindControls()
|
|||
wxCommandEventHandler(JoyPadConfig_t::JoypadConfigButtons),
|
||||
NULL, &JoyPadConfigHandler[i]);
|
||||
}
|
||||
|
||||
// poll the joystick
|
||||
JoystickPoller* jpoll = new JoystickPoller();
|
||||
|
||||
joyDialog->Connect(wxID_ANY, wxEVT_SHOW,
|
||||
wxShowEventHandler(JoystickPoller::ShowDialog),
|
||||
jpoll, jpoll);
|
||||
|
||||
joyDialog->Fit();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../common/ConfigManager.h"
|
||||
#include "wxvbam.h"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <wx/display.h>
|
||||
#include "strutils.h"
|
||||
|
@ -151,22 +152,20 @@ wxJoyKeyBinding defkeys_keyboard[NUM_KEYS] = {
|
|||
WJKB(WXK_SPACE), WJKB(0), WJKB(0)
|
||||
};
|
||||
|
||||
wxJoyKeyBinding defkeys_joystick[NUM_KEYS] = {
|
||||
WJKB(0, WXJB_HAT_N, 1), WJKB(0, WXJB_HAT_S, 1), WJKB(0, WXJB_HAT_W, 1), WJKB(0, WXJB_HAT_E, 1),
|
||||
WJKB(0, WXJB_BUTTON, 1), WJKB(1, WXJB_BUTTON, 1), WJKB(4, WXJB_BUTTON, 1), WJKB(5, WXJB_BUTTON, 1),
|
||||
WJKB(6, WXJB_BUTTON, 1), WJKB(7, WXJB_BUTTON, 1),
|
||||
WJKB(0), WJKB(0), WJKB(0), WJKB(0),
|
||||
WJKB(0), WJKB(0), WJKB(0), WJKB(0),
|
||||
WJKB(0), WJKB(0), WJKB(0)
|
||||
};
|
||||
|
||||
wxJoyKeyBinding extrakeys_joystick[NUM_KEYS] = {
|
||||
WJKB(1, WXJB_AXIS_MINUS, 1), WJKB(1, WXJB_AXIS_PLUS, 1), WJKB(0, WXJB_AXIS_MINUS, 1), WJKB(0, WXJB_AXIS_PLUS, 1),
|
||||
WJKB(0), WJKB(0), WJKB(0), WJKB(0),
|
||||
WJKB(0), WJKB(0),
|
||||
WJKB(0), WJKB(0), WJKB(0), WJKB(0),
|
||||
WJKB(0), WJKB(0), WJKB(0), WJKB(0),
|
||||
WJKB(0), WJKB(0), WJKB(0)
|
||||
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) },
|
||||
{}, {}, {}, {},
|
||||
{}, {}, {}, {},
|
||||
{}, {}, {}
|
||||
};
|
||||
|
||||
wxAcceleratorEntry_v sys_accels;
|
||||
|
@ -372,12 +371,12 @@ bool opt_lt(const opt_desc& opt1, const opt_desc& opt2)
|
|||
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]);
|
||||
if (defkeys_joystick[i].joy)
|
||||
gopts.joykey_bindings[0][i].push_back(defkeys_joystick[i]);
|
||||
if (extrakeys_joystick[i].joy)
|
||||
gopts.joykey_bindings[0][i].push_back(extrakeys_joystick[i]);
|
||||
for (auto bind : defkeys_joystick[i])
|
||||
gopts.joykey_bindings[0][i].push_back(bind);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
#ifndef WX_OPTS_H
|
||||
#define WX_OPTS_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define NUM_KEYS 21
|
||||
extern const wxString joynames[NUM_KEYS];
|
||||
extern wxJoyKeyBinding defkeys_keyboard[NUM_KEYS]; // keyboard defaults
|
||||
extern wxJoyKeyBinding defkeys_joystick[NUM_KEYS]; // joystick defaults
|
||||
extern wxJoyKeyBinding extrakeys_joystick[NUM_KEYS];// extra joystick defaults
|
||||
|
||||
extern std::vector<std::vector<wxJoyKeyBinding>> defkeys_joystick; // joystick defaults
|
||||
|
||||
extern struct opts_t {
|
||||
opts_t();
|
||||
|
|
|
@ -955,13 +955,13 @@ void GameArea::Resume()
|
|||
void GameArea::OnIdle(wxIdleEvent& event)
|
||||
{
|
||||
wxString pl = wxGetApp().pending_load;
|
||||
MainFrame* mf = wxGetApp().frame;
|
||||
|
||||
if (pl.size()) {
|
||||
// sometimes this gets into a loop if LoadGame() called before
|
||||
// clearing pending_load. weird.
|
||||
wxGetApp().pending_load = wxEmptyString;
|
||||
LoadGame(pl);
|
||||
MainFrame* mf = wxGetApp().frame;
|
||||
|
||||
#ifndef NO_DEBUGGER
|
||||
if (gdbBreakOnLoad)
|
||||
|
@ -1095,6 +1095,7 @@ void GameArea::OnIdle(wxIdleEvent& event)
|
|||
CheckLinkConnection();
|
||||
|
||||
#endif
|
||||
mf->PollJoysticks();
|
||||
} else {
|
||||
was_paused = true;
|
||||
|
||||
|
@ -1122,7 +1123,6 @@ void GameArea::OnIdle(wxIdleEvent& event)
|
|||
wxLogInfo(_("Error writing rewind state"));
|
||||
else {
|
||||
if (!num_rewind_states) {
|
||||
MainFrame* mf = wxGetApp().frame;
|
||||
mf->cmd_enable |= CMDEN_REWIND;
|
||||
mf->enable_menus();
|
||||
}
|
||||
|
|
|
@ -1,103 +1,126 @@
|
|||
#include "wxvbam.h"
|
||||
#include "wx/sdljoy.h"
|
||||
#include "SDL.h"
|
||||
#include <SDL_joystick.h>
|
||||
#include <SDL_events.h>
|
||||
#include <SDL_gamecontroller.h>
|
||||
#include <wx/window.h>
|
||||
#include "../common/range.hpp"
|
||||
#include "../common/contains.h"
|
||||
|
||||
using namespace Range;
|
||||
|
||||
DEFINE_EVENT_TYPE(wxEVT_SDLJOY)
|
||||
|
||||
struct wxSDLJoyState {
|
||||
SDL_Joystick* dev;
|
||||
int nax, nhat, nbut;
|
||||
short* curval;
|
||||
short* initial_val;
|
||||
bool is_valid;
|
||||
~wxSDLJoyState()
|
||||
{
|
||||
if (dev)
|
||||
SDL_JoystickClose(dev);
|
||||
if (curval)
|
||||
delete[] curval;
|
||||
if (initial_val)
|
||||
delete[] initial_val;
|
||||
}
|
||||
wxSDLJoyState()
|
||||
{
|
||||
dev = NULL;
|
||||
nax = nhat = nbut = 0;
|
||||
curval = NULL;
|
||||
initial_val = NULL;
|
||||
is_valid = true;
|
||||
}
|
||||
};
|
||||
|
||||
wxSDLJoy::wxSDLJoy(bool analog)
|
||||
wxSDLJoy::wxSDLJoy()
|
||||
: wxTimer()
|
||||
, digital(!analog)
|
||||
, joystate(0)
|
||||
, evthandler(0)
|
||||
, nosticks(true)
|
||||
, evthandler(nullptr)
|
||||
{
|
||||
// Start up joystick if not already started
|
||||
// FIXME: check for errors
|
||||
SDL_Init(SDL_INIT_JOYSTICK);
|
||||
// but we'll have to manage it manually
|
||||
SDL_JoystickEventState(SDL_IGNORE);
|
||||
// now query joystick config and open joysticks
|
||||
// there is no way to reread this later (e.g. if joystick plugged in),
|
||||
// since SDL won't
|
||||
njoy = SDL_NumJoysticks();
|
||||
|
||||
if (!njoy)
|
||||
return;
|
||||
|
||||
joystate = new wxSDLJoyState[njoy];
|
||||
|
||||
for (int i = 0; i < njoy; i++) {
|
||||
SDL_Joystick* dev = joystate[i].dev = SDL_JoystickOpen(i);
|
||||
|
||||
int nctrl = 0, axes = 0, hats = 0, buttons = 0;
|
||||
|
||||
axes = SDL_JoystickNumAxes(dev);
|
||||
hats = SDL_JoystickNumHats(dev);
|
||||
buttons = SDL_JoystickNumButtons(dev);
|
||||
|
||||
if (buttons <= 0 && axes <= 0 && hats <= 0) {
|
||||
joystate[i].is_valid = false;
|
||||
|
||||
SDL_JoystickClose(dev);
|
||||
joystate[i].dev = NULL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
nctrl += joystate[i].nax = axes < 0 ? 0 : axes;
|
||||
nctrl += joystate[i].nhat = hats < 0 ? 0 : hats;
|
||||
nctrl += joystate[i].nbut = buttons < 0 ? 0 : buttons;
|
||||
|
||||
joystate[i].curval = new short[nctrl]{};
|
||||
|
||||
// set initial values array
|
||||
// see below for 360 trigger handling
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 6)
|
||||
joystate[i].initial_val = new short[nctrl]{};
|
||||
|
||||
for (int j = 0; j < joystate[i].nax; j++) {
|
||||
int16_t initial_state = 0;
|
||||
SDL_JoystickGetAxisInitialState(dev, j, &initial_state);
|
||||
joystate[i].initial_val[j] = initial_state;
|
||||
|
||||
// curval is 0 which is what initial state maps to ATM
|
||||
}
|
||||
#endif
|
||||
}
|
||||
SDL_Init(SDL_INIT_GAMECONTROLLER);
|
||||
SDL_GameControllerEventState(SDL_ENABLE);
|
||||
}
|
||||
|
||||
wxSDLJoy::~wxSDLJoy()
|
||||
{
|
||||
delete[] joystate;
|
||||
// SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
}
|
||||
|
||||
static int axisval(int x)
|
||||
{
|
||||
if (x > 0x1fff)
|
||||
return 1;
|
||||
else if (x < -0x1fff)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wxSDLJoy::Poll()
|
||||
{
|
||||
wxEvtHandler* handler = evthandler ? evthandler : wxWindow::FindFocus();
|
||||
SDL_Event e;
|
||||
|
||||
while (SDL_PollEvent(&e)) {
|
||||
switch (e.type) {
|
||||
case SDL_CONTROLLERBUTTONDOWN:
|
||||
case SDL_CONTROLLERBUTTONUP:
|
||||
{
|
||||
auto joy = e.cbutton.which;
|
||||
|
||||
if (contains(joystate, joy)) {
|
||||
auto but = e.cbutton.button;
|
||||
auto val = e.cbutton.state;
|
||||
auto prev_val = !val;
|
||||
|
||||
if (handler) {
|
||||
wxSDLJoyEvent* ev = new wxSDLJoyEvent(wxEVT_SDLJOY);
|
||||
ev->joy = joy;
|
||||
ev->ctrl_type = WXSDLJOY_BUTTON;
|
||||
ev->ctrl_idx = but;
|
||||
ev->ctrl_val = val;
|
||||
ev->prev_val = prev_val;
|
||||
|
||||
handler->QueueEvent(ev);
|
||||
}
|
||||
|
||||
wxLogDebug("GOT SDL_CONTROLLERBUTTON: joy:%d but:%d val:%d prev_val:%d", joy, but, val, prev_val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDL_CONTROLLERAXISMOTION:
|
||||
{
|
||||
auto joy = e.caxis.which;
|
||||
|
||||
if (contains(joystate, joy)) {
|
||||
auto axis = e.caxis.axis;
|
||||
auto val = axisval(e.caxis.value);
|
||||
auto prev_val = joystate[joy].axis[axis];
|
||||
|
||||
if (handler && val != prev_val) {
|
||||
wxSDLJoyEvent* ev = new wxSDLJoyEvent(wxEVT_SDLJOY);
|
||||
ev->joy = joy;
|
||||
ev->ctrl_type = WXSDLJOY_AXIS;
|
||||
ev->ctrl_idx = axis;
|
||||
ev->ctrl_val = val;
|
||||
ev->prev_val = prev_val;
|
||||
|
||||
handler->QueueEvent(ev);
|
||||
|
||||
joystate[joy].axis[axis] = val;
|
||||
|
||||
wxLogDebug("GOT SDL_CONTROLLERAXISMOTION: joy:%d axis:%d val:%d prev_val:%d", joy, axis, val, prev_val);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDL_CONTROLLERDEVICEADDED:
|
||||
case SDL_CONTROLLERDEVICEREMAPPED:
|
||||
{
|
||||
auto joy = e.cdevice.which;
|
||||
|
||||
if (add_all || contains(joystate, joy)) {
|
||||
joystate[joy].dev = SDL_GameControllerOpen(joy);
|
||||
|
||||
systemScreenMessage(wxString::Format(_("Connected game controller %d"), joy + 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDL_CONTROLLERDEVICEREMOVED:
|
||||
{
|
||||
auto joy = e.cdevice.which;
|
||||
|
||||
if (contains(joystate, joy)) {
|
||||
joystate[joy].dev = nullptr;
|
||||
|
||||
systemScreenMessage(wxString::Format(_("Disconnected game controller %d"), joy + 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxEvtHandler* wxSDLJoy::Attach(wxEvtHandler* handler)
|
||||
{
|
||||
wxEvtHandler* prev = evthandler;
|
||||
|
@ -105,151 +128,56 @@ wxEvtHandler* wxSDLJoy::Attach(wxEvtHandler* handler)
|
|||
return prev;
|
||||
}
|
||||
|
||||
void wxSDLJoy::Add(int joy)
|
||||
void wxSDLJoy::Add(int8_t joy_n)
|
||||
{
|
||||
if (joy >= njoy || !njoy)
|
||||
return;
|
||||
if (joy_n < 0) {
|
||||
for (uint8_t joy : range(0, SDL_NumJoysticks()))
|
||||
joystate[joy].dev = SDL_GameControllerOpen(joy);
|
||||
|
||||
if (joy < 0) {
|
||||
for (int i = 0; i < njoy; i++)
|
||||
Add(i);
|
||||
add_all = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!joystate[joy].dev)
|
||||
joystate[joy].dev = SDL_JoystickOpen(joy);
|
||||
|
||||
if (nosticks && joystate[joy].dev) {
|
||||
Start(poll_time_ms);
|
||||
nosticks = false;
|
||||
}
|
||||
joystate[joy_n].dev = SDL_GameControllerOpen(joy_n);
|
||||
}
|
||||
|
||||
void wxSDLJoy::Remove(int joy)
|
||||
void wxSDLJoy::Remove(int8_t joy_n)
|
||||
{
|
||||
if (joy >= njoy || !njoy)
|
||||
return;
|
||||
add_all = false;
|
||||
|
||||
if (joy < 0) {
|
||||
for (int i = 0; i < njoy; i++)
|
||||
if (joystate[i].dev) {
|
||||
SDL_JoystickClose(joystate[i].dev);
|
||||
joystate[i].dev = NULL;
|
||||
}
|
||||
|
||||
Stop();
|
||||
nosticks = true;
|
||||
if (joy_n < 0) {
|
||||
joystate.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!joystate[joy].dev)
|
||||
return;
|
||||
joystate.erase(joy_n);
|
||||
}
|
||||
|
||||
SDL_JoystickClose(joystate[joy].dev);
|
||||
joystate[joy].dev = NULL;
|
||||
void wxSDLJoy::SetRumble(bool do_rumble)
|
||||
{
|
||||
rumbling = do_rumble;
|
||||
|
||||
for (int i = 0; i < njoy; i++)
|
||||
if (joystate[i].dev)
|
||||
return;
|
||||
|
||||
Stop();
|
||||
nosticks = true;
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
// do rumble only on device 0
|
||||
auto dev = joystate[0].dev;
|
||||
if (dev) {
|
||||
if (rumbling) {
|
||||
SDL_GameControllerRumble(dev, 0xFFFF, 0xFFFF, 300);
|
||||
if (!IsRunning())
|
||||
Start(150);
|
||||
}
|
||||
else {
|
||||
SDL_GameControllerRumble(dev, 0, 0, 0);
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
else
|
||||
Stop();
|
||||
#endif
|
||||
}
|
||||
|
||||
void wxSDLJoy::Notify()
|
||||
{
|
||||
if (nosticks)
|
||||
return;
|
||||
|
||||
SDL_JoystickUpdate();
|
||||
wxEvtHandler* handler = evthandler ? evthandler : wxWindow::FindFocus();
|
||||
|
||||
for (int i = 0; i < njoy; i++) {
|
||||
if (!joystate[i].is_valid) continue;
|
||||
|
||||
SDL_Joystick* dev = joystate[i].dev;
|
||||
|
||||
if (dev) {
|
||||
int nax = joystate[i].nax, nhat = joystate[i].nhat,
|
||||
nbut = joystate[i].nbut;
|
||||
short val;
|
||||
|
||||
for (int j = 0; j < nax; j++) {
|
||||
val = SDL_JoystickGetAxis(dev, j);
|
||||
|
||||
if (digital) {
|
||||
if (val > 0x3fff)
|
||||
val = 0x7fff;
|
||||
else if (val <= -0x3fff)
|
||||
val = -0x7fff;
|
||||
else
|
||||
val = 0;
|
||||
}
|
||||
|
||||
// This is for the 360 and similar triggers which return a
|
||||
// value on initial state of the trigger axis. This hack may be
|
||||
// insufficient, we may need to expand the joy event API to
|
||||
// support initial values.
|
||||
if (joystate[i].initial_val && val == joystate[i].initial_val[j])
|
||||
val = 0;
|
||||
|
||||
if (handler && val != joystate[i].curval[j]) {
|
||||
wxSDLJoyEvent ev(wxEVT_SDLJOY, GetId());
|
||||
ev.joy = i;
|
||||
ev.ctrl_type = WXSDLJOY_AXIS;
|
||||
ev.ctrl_idx = j;
|
||||
ev.ctrl_val = val;
|
||||
ev.prev_val = joystate[i].curval[j];
|
||||
handler->ProcessEvent(ev);
|
||||
}
|
||||
|
||||
joystate[i].curval[j] = val;
|
||||
}
|
||||
|
||||
for (int j = 0; j < nhat; j++) {
|
||||
val = SDL_JoystickGetHat(dev, j);
|
||||
|
||||
if (handler && val != joystate[i].curval[nax + j]) {
|
||||
wxSDLJoyEvent ev(wxEVT_SDLJOY, GetId());
|
||||
ev.joy = i;
|
||||
ev.ctrl_type = WXSDLJOY_HAT;
|
||||
ev.ctrl_idx = j;
|
||||
ev.ctrl_val = val;
|
||||
ev.prev_val = joystate[i].curval[nax + j];
|
||||
handler->ProcessEvent(ev);
|
||||
}
|
||||
|
||||
joystate[i].curval[nax + j] = val;
|
||||
}
|
||||
|
||||
for (int j = 0; j < nbut; j++) {
|
||||
val = SDL_JoystickGetButton(dev, j);
|
||||
|
||||
if (handler && val != joystate[i].curval[nax + nhat + j]) {
|
||||
wxSDLJoyEvent ev(wxEVT_SDLJOY, GetId());
|
||||
ev.joy = i;
|
||||
ev.ctrl_type = WXSDLJOY_BUTTON;
|
||||
ev.ctrl_idx = j;
|
||||
ev.ctrl_val = val;
|
||||
ev.prev_val = joystate[i].curval[nax + nhat + j];
|
||||
handler->ProcessEvent(ev);
|
||||
}
|
||||
|
||||
joystate[i].curval[nax + nhat + j] = val;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// do rumble only on device 0
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
SDL_Joystick* dev = joystate[0].dev;
|
||||
if (dev) {
|
||||
if (rumbling)
|
||||
SDL_JoystickRumble(dev, 0xFFFF, 0xFFFF, poll_time_ms * 2);
|
||||
else
|
||||
SDL_JoystickRumble(dev, 0, 0, 0);
|
||||
}
|
||||
#endif
|
||||
SetRumble(rumbling);
|
||||
}
|
||||
|
|
|
@ -4,28 +4,26 @@
|
|||
// This is my own SDL-based joystick handler, since wxJoystick is brain-dead.
|
||||
// It's geared towards keyboard emulation
|
||||
|
||||
// To use, create a wxSDLJoy object Add() the joysticks you want to monitor.
|
||||
// wxSDLJoy derives from wxTimer, so you can pause it with Stop() and
|
||||
// resume with Start().
|
||||
// To use, create a wxSDLJoy object Add() the joysticks you want to monitor and
|
||||
// Attach() the target window to receive events.
|
||||
//
|
||||
// The target window will receive EVT_SDLJOY events of type wxSDLJoyEvent.
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <wx/event.h>
|
||||
#include <wx/timer.h>
|
||||
#include <SDL_gamecontroller.h>
|
||||
#include "../common/contains.h"
|
||||
|
||||
struct wxSDLJoyState;
|
||||
struct wxSDLJoyState {
|
||||
SDL_GameController* dev = nullptr;
|
||||
std::unordered_map<uint8_t, int8_t> axis;
|
||||
};
|
||||
|
||||
class wxSDLJoy : public wxTimer {
|
||||
public:
|
||||
// if analog, send events for all axis movement
|
||||
// otherwise, only send events when values cross the 50% mark
|
||||
// and max out values
|
||||
wxSDLJoy(bool analog = false);
|
||||
// but flag can be set later
|
||||
void SetAnalog(bool analog = true)
|
||||
{
|
||||
digital = !analog;
|
||||
};
|
||||
wxSDLJoy();
|
||||
// send events to this handler
|
||||
// If NULL (default), send to window with keyboard focus
|
||||
wxEvtHandler* Attach(wxEvtHandler*);
|
||||
|
@ -33,43 +31,29 @@ public:
|
|||
// -1 == add all
|
||||
// If joy > # of joysticks, it is ignored
|
||||
// This will start polling if a valid joystick is selected
|
||||
void Add(int joy = -1);
|
||||
void Add(int8_t joy = -1);
|
||||
// remove a joystick from the polled sticks
|
||||
// -1 == remove all
|
||||
// If joy > # of joysticks, it is ignored
|
||||
// This will stop polling if all joysticks are disabled
|
||||
void Remove(int joy = -1);
|
||||
void Remove(int8_t joy = -1);
|
||||
// query if a stick is being polled
|
||||
bool IsPolling(int joy);
|
||||
// query # of joysticks
|
||||
int GetNumJoysticks()
|
||||
{
|
||||
return njoy;
|
||||
}
|
||||
// query # of axes on given joystick
|
||||
// 0 is returned if joy is invalid
|
||||
int GetNumAxes(int joy);
|
||||
// query # of hats on given joystick
|
||||
// 0 is returned if joy is invalid
|
||||
int GetNumHats(int joy);
|
||||
// query # of buttons on given joystick
|
||||
// 0 is returned if joy is invalid
|
||||
int GetNumButtons(int joy);
|
||||
bool IsPolling(uint8_t joy) { return contains(joystate, joy); }
|
||||
|
||||
// true = currently rumbling, false = turn off rumbling
|
||||
void SetRumble(bool b) { rumbling = b; }
|
||||
void SetRumble(bool do_rumble);
|
||||
|
||||
void Poll();
|
||||
|
||||
virtual ~wxSDLJoy();
|
||||
|
||||
protected:
|
||||
bool digital;
|
||||
int njoy;
|
||||
wxSDLJoyState* joystate;
|
||||
wxEvtHandler* evthandler;
|
||||
bool nosticks;
|
||||
bool rumbling = false;
|
||||
// used to continue rumbling on a timer
|
||||
void Notify();
|
||||
uint16_t poll_time_ms = 50;
|
||||
private:
|
||||
std::unordered_map<uint8_t, wxSDLJoyState> joystate;
|
||||
wxEvtHandler* evthandler;
|
||||
bool add_all = false, rumbling = false;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -86,8 +70,8 @@ class wxSDLJoyEvent : public wxCommandEvent {
|
|||
|
||||
public:
|
||||
// Default constructor
|
||||
wxSDLJoyEvent(wxEventType commandType = wxEVT_NULL, int id = 0)
|
||||
: wxCommandEvent(commandType, id)
|
||||
wxSDLJoyEvent(wxEventType commandType = wxEVT_NULL)
|
||||
: wxCommandEvent(commandType)
|
||||
{
|
||||
}
|
||||
// accessors
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef WXLOGDEBUG_H_
|
||||
#define WXLOGDEBUG_H_
|
||||
|
||||
#include <wx/log.h>
|
||||
|
||||
// make wxLogDebug work on non-debug builds of Wx, and make it use the console
|
||||
// on Windows
|
||||
// (this works on 2.8 too!)
|
||||
#if !defined(NDEBUG) && (!wxDEBUG_LEVEL || defined(__WXMSW__))
|
||||
#ifdef __WXMSW__
|
||||
#define VBAM_DEBUG_STREAM stdout
|
||||
#else
|
||||
#define VBAM_DEBUG_STREAM stderr
|
||||
#endif
|
||||
#undef wxLogDebug
|
||||
#define wxLogDebug(...) \
|
||||
do { \
|
||||
fputs(wxString::Format(wxDateTime::UNow().Format(wxT("%X")) + wxT(": Debug: ") + __VA_ARGS__).utf8_str(), VBAM_DEBUG_STREAM); \
|
||||
fputc('\n', VBAM_DEBUG_STREAM); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
#endif /* WXLOGDEBUG_H_ */
|
|
@ -32,22 +32,7 @@
|
|||
#include "../gba/Globals.h"
|
||||
#include "../gba/Sound.h"
|
||||
|
||||
// make wxLogDebug work on non-debug builds of Wx, and make it use the console
|
||||
// on Windows
|
||||
// (this works on 2.8 too!)
|
||||
#if !defined(NDEBUG) && (!wxDEBUG_LEVEL || defined(__WXMSW__))
|
||||
#ifdef __WXMSW__
|
||||
#define VBAM_DEBUG_STREAM stdout
|
||||
#else
|
||||
#define VBAM_DEBUG_STREAM stderr
|
||||
#endif
|
||||
#undef wxLogDebug
|
||||
#define wxLogDebug(...) \
|
||||
do { \
|
||||
fputs(wxString::Format(wxDateTime::UNow().Format(wxT("%X")) + wxT(": Debug: ") + __VA_ARGS__).utf8_str(), VBAM_DEBUG_STREAM); \
|
||||
fputc('\n', VBAM_DEBUG_STREAM); \
|
||||
} while(0)
|
||||
#endif
|
||||
#include "wxlogdebug.h"
|
||||
|
||||
template <typename T>
|
||||
void CheckPointer(T pointer)
|
||||
|
@ -328,15 +313,18 @@ public:
|
|||
|
||||
virtual void SetJoystickRumble(bool b) { joy.SetRumble(b); }
|
||||
|
||||
bool IsPaused(bool incendental = false)
|
||||
{
|
||||
return (paused && !pause_next && !incendental) || menus_opened || dialog_opened;
|
||||
}
|
||||
|
||||
void PollJoysticks() { joy.Poll(); }
|
||||
|
||||
// required for building from xrc
|
||||
DECLARE_DYNAMIC_CLASS(MainFrame);
|
||||
// required for event handling
|
||||
DECLARE_EVENT_TABLE();
|
||||
|
||||
bool IsPaused(bool incendental = false)
|
||||
{
|
||||
return (paused && !pause_next && !incendental) || menus_opened || dialog_opened;
|
||||
}
|
||||
protected:
|
||||
virtual void BindAppIcon();
|
||||
|
||||
|
|
Loading…
Reference in New Issue