diff --git a/.gitignore b/.gitignore index f2a8f061..94b3d7f2 100644 --- a/.gitignore +++ b/.gitignore @@ -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/* diff --git a/po/wxvbam/wxvbam.pot b/po/wxvbam/wxvbam.pot index 094e5bf7..6feda162 100644 --- a/po/wxvbam/wxvbam.pot +++ b/po/wxvbam/wxvbam.pot @@ -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 \n" "Language-Team: LANGUAGE \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 "=" 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 "" diff --git a/src/common/SoundSDL.cpp b/src/common/SoundSDL.cpp index 2ad7218e..4abcced8 100644 --- a/src/common/SoundSDL.cpp +++ b/src/common/SoundSDL.cpp @@ -17,6 +17,7 @@ #include #include +#include #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; } diff --git a/src/common/contains.h b/src/common/contains.h new file mode 100644 index 00000000..96fd1b3c --- /dev/null +++ b/src/common/contains.h @@ -0,0 +1,10 @@ +#ifndef CONTAINS_HPP_ +#define CONTAINS_HPP_ + +template +bool contains(const C& container, const V& val) +{ + return (container.find(val) != container.end()); +} + +#endif /* CONTAINS_HPP_ */ diff --git a/src/common/range.hpp b/src/common/range.hpp new file mode 100644 index 00000000..f5f9081c --- /dev/null +++ b/src/common/range.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 +// using std::ceil from +#include +#include +#include +#include + +namespace Range +{ + template + 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 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 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 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 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(first_element, last_element, 1); + else *this = basic_range(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(value_type last_element) + : m_first_element(0) + { + if(last_element >= m_first_element) *this = basic_range(m_first_element, last_element, 1); + else *this = basic_range(m_first_element, last_element, -1); + } + + basic_range(const basic_range& r) + : m_first_element(r.m_first_element), + m_element_count(r.m_element_count), + m_step(r.m_step) + { } + + basic_range& operator=(const basic_range& 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& 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& 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& 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& 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& r) const + { + return !(*this > r); + } + + bool operator >=(const basic_range& 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 range; +} + +#endif // range_h__ \ No newline at end of file diff --git a/src/wx/CMakeLists.txt b/src/wx/CMakeLists.txt index d37c1cdd..5605916b 100644 --- a/src/wx/CMakeLists.txt +++ b/src/wx/CMakeLists.txt @@ -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) diff --git a/src/wx/guiinit.cpp b/src/wx/guiinit.cpp index 0ab9e36d..60a77d58 100644 --- a/src/wx/guiinit.cpp +++ b/src/wx/guiinit.cpp @@ -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(); } diff --git a/src/wx/opts.cpp b/src/wx/opts.cpp index 82930614..6faa7eaf 100644 --- a/src/wx/opts.cpp +++ b/src/wx/opts.cpp @@ -1,5 +1,6 @@ #include "../common/ConfigManager.h" #include "wxvbam.h" +#include #include #include #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> 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); } } diff --git a/src/wx/opts.h b/src/wx/opts.h index 366ddbdd..809d51ed 100644 --- a/src/wx/opts.h +++ b/src/wx/opts.h @@ -1,11 +1,13 @@ #ifndef WX_OPTS_H #define WX_OPTS_H +#include + #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> defkeys_joystick; // joystick defaults extern struct opts_t { opts_t(); diff --git a/src/wx/panel.cpp b/src/wx/panel.cpp index 52c21504..4b5d4e8b 100644 --- a/src/wx/panel.cpp +++ b/src/wx/panel.cpp @@ -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(); } diff --git a/src/wx/widgets/sdljoy.cpp b/src/wx/widgets/sdljoy.cpp index 1a6af18d..e55bcb84 100644 --- a/src/wx/widgets/sdljoy.cpp +++ b/src/wx/widgets/sdljoy.cpp @@ -1,103 +1,126 @@ +#include "wxvbam.h" #include "wx/sdljoy.h" #include "SDL.h" -#include +#include +#include #include +#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); } diff --git a/src/wx/widgets/wx/sdljoy.h b/src/wx/widgets/wx/sdljoy.h index b80a7a28..a313d8f8 100644 --- a/src/wx/widgets/wx/sdljoy.h +++ b/src/wx/widgets/wx/sdljoy.h @@ -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 +#include #include #include +#include +#include "../common/contains.h" -struct wxSDLJoyState; +struct wxSDLJoyState { + SDL_GameController* dev = nullptr; + std::unordered_map 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 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 diff --git a/src/wx/wxlogdebug.h b/src/wx/wxlogdebug.h new file mode 100644 index 00000000..52eda436 --- /dev/null +++ b/src/wx/wxlogdebug.h @@ -0,0 +1,23 @@ +#ifndef WXLOGDEBUG_H_ +#define WXLOGDEBUG_H_ + +#include + +// 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_ */ diff --git a/src/wx/wxvbam.h b/src/wx/wxvbam.h index e46471e5..3002033b 100644 --- a/src/wx/wxvbam.h +++ b/src/wx/wxvbam.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 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();