Compare commits

...

72 Commits

Author SHA1 Message Date
Rosalie Wanders d842baa2c5 Package: v0.4.4 2023-07-17 15:58:04 +02:00
Rosalie Wanders 86db43aab4 RMG: set OnScreenDisplay{Pause,Resume} in on_Core_StateCallback() 2023-07-17 15:55:44 +02:00
Rosalie Wanders 4397a0c614 3rdParty: update mupen64plus-core 2023-07-17 15:36:42 +02:00
Rosalie Wanders 898e1596b3 RMG: use CoreStateCallbackType::ScreenshotCaptured 2023-07-17 15:00:06 +02:00
Rosalie Wanders 66e08de2fe RMG-Core: add ScreenshotCaptured to CoreStateCallbackType 2023-07-17 14:59:04 +02:00
Rosalie Wanders 7b73254ad2 3rdParty: update mupen64plus-core 2023-07-17 14:58:47 +02:00
Rosalie Wanders 9bd77efbdb Package: fix AppImage LD_LIBRARY_PATH hack 2023-07-17 14:17:06 +02:00
Rosalie Wanders aaf42ea8b9 ci: correct $build_dir 2023-07-17 14:16:17 +02:00
JaxonWasTaken 57c5af0f30 RMG-Input: refactor deadzone and sensitivity (#143)
* rework application of deadzone

 * Move application of deadzone outside octagon simulation.
 * Scale result after applying deadzone back to the range ±[0, 1].
 * Remove deadzone from octagon simulation, as a real N64 controller can
   output output values in the full range.

* move application of sensitivity

The sensitivity is only for the real controller and doesn't really have
anything to do with simulating an octagon, so we move its application to
the processing of input from the real controller.

* use std::hypot instead of manual calculation
2023-07-17 14:12:44 +02:00
Rosalie Wanders 43c3e55466 RMG-Input: add hotkeys for inc/decr save state slot and switching paks 2023-07-16 16:43:17 +02:00
Rosalie Wanders ffbd84df82 RMG-Core: add more controller hotkey settings 2023-07-16 16:41:28 +02:00
Rosalie Wanders 25ee5f2ca1 RMG-Core: introduce Core{Increase,Decrease}SaveStateSlot() 2023-07-16 16:07:02 +02:00
Rosalie Wanders f223b88803 RMG-Input: add support for joystick/triggers in HotkeysDialog.cpp 2023-07-16 15:36:06 +02:00
Rosalie Wanders cd56680e38 RMG-Core: fix mupen64plus-rsp-hle fallback not working on first run 2023-07-16 15:16:26 +02:00
Rosalie Wanders b9e1e230f9 RMG-Core: minor code fixes 2023-07-15 11:24:41 +02:00
Rosalie Wanders eb8294363a RMG-Core: fix memory leak in Rom.cpp 2023-07-15 11:10:05 +02:00
Rosalie Wanders d9e2ed2b9a Package: v0.4.3 2023-07-11 14:46:06 +02:00
Rosalie Wanders 81015e086c 3rdParty: update mupen64plus-core 2023-07-11 14:43:06 +02:00
Rosalie Wanders a0e31029d1 RMG-Core: set mupen64plus-rsp-parallel as mupen64plus-rsp-hle fallback 2023-07-11 14:14:29 +02:00
Rosalie Wanders 53f87d0793 RMG-Core: introduce & use CoreUpdateCachedRomHeaderAndSettings() 2023-07-11 14:00:24 +02:00
Rosalie Wanders 1e6c906300 3rdParty: update mupen64plus-core 2023-07-11 10:06:45 +02:00
Rosalie Wanders b76023209c 3rdParty: update mupen64plus-core 2023-07-10 16:03:33 +02:00
Rosalie Wanders b4c7821630 3rdParty: update GLideN64 2023-07-10 16:03:01 +02:00
Rosalie Wanders e86261e2dc Package: update screenshots 2023-07-07 19:48:35 +02:00
Rosalie Wanders 7534c5bb3c Package: v0.4.2 2023-07-07 19:41:51 +02:00
Rosalie Wanders 7d5eec2d41 RMG: use filename in window title when good name contains (unknown rom) 2023-07-07 19:33:07 +02:00
Rosalie Wanders 69b8461a87 RMG-Core: introduce CoreGetRomPath() 2023-07-07 19:32:46 +02:00
Rosalie Wanders 32d2a12331 RMG-Input: (wip) introduce controller hotkeys 2023-07-07 15:54:40 +02:00
Rosalie Wanders ce8de27fb5 RMG-Core: add input hotkey settings 2023-07-07 15:25:42 +02:00
Rosalie Wanders 9c64d647ad 3rdParty: update GLideN64 2023-07-04 23:42:34 +02:00
Rosalie Wanders 726861dfaa RMG: don't support VidExt_SetModeWithRate() 2023-07-04 23:38:10 +02:00
Rosalie Wanders 51dea638c9 Package: update RomBrowser.png and Ingame.png 2023-07-04 12:52:44 +02:00
Rosalie Wanders 298a717225 RMG: use state callbacks for more OSD messages/UI states 2023-07-03 00:37:01 +02:00
Rosalie Wanders 27b2bc8387 RMG-Core: add CoreEmulationState enum to Emulation.hpp 2023-07-03 00:34:20 +02:00
Rosalie Wanders 6f6310c776 RMG-Input: only expose VRU for Player 4 2023-07-02 18:00:36 +02:00
Rosalie Wanders e45fcdfb3e RMG-Input: add VRU support 2023-07-01 01:15:54 +02:00
Rosalie Wanders ea02f68abe 3rdParty: add vosk-api 2023-07-01 01:14:53 +02:00
Rosalie Wanders 65d7d149f1 Package: use --lib-path commandline option in AppImage 2023-07-01 01:13:52 +02:00
Rosalie Wanders c5f23f8b71 RMG: expose --lib-path commandline option 2023-07-01 01:13:39 +02:00
Rosalie Wanders ba327ce1c6 RMG-Core: change to shared library 2023-07-01 01:12:40 +02:00
Rosalie Wanders 583687cfe1 RMG-Core: add CoreGetLibraryDirectory() and CoreSetLibraryPathOverride() 2023-07-01 01:09:27 +02:00
Rosalie Wanders 19eda69468 RMG-Core: support sending callback messages for plugins 2023-07-01 01:08:54 +02:00
Rosalie Wanders 4b3f979a74 RMG-Core: check if core and config functions are hooked in CoreInit() 2023-07-01 01:07:45 +02:00
Rosalie Wanders d171d62609 RMG-Core: remove cpp file include 2023-07-01 01:06:53 +02:00
Rosalie Wanders 5ba195d32e RMG-Core: fix read_7zip_file for 7-Zip v23.01 2023-06-30 16:01:12 +02:00
Rosalie Wanders 950aa60fca 3rdParty: update 7-Zip to v23.01 2023-06-30 16:00:52 +02:00
Rosalie Wanders 3547e9bf53 Package: v0.4.1 2023-06-19 17:26:53 +02:00
Rosalie Wanders 5dbf6cfb2e RMG: add *.st* and *.pj* files to on_Action_System_Load() 2023-06-19 17:23:05 +02:00
Rosalie Wanders fb12f6432b 3rdParty: update mupen64plus-core 2023-06-19 17:16:34 +02:00
Rosalie Wanders 5b61f811da 3rdParty: update SDL_GameControllerDB 2023-06-13 17:33:14 +02:00
Rosalie Wanders fe0fa0b527 3rdParty: downgrade mupen64plus-input-gca 2023-06-13 17:28:11 +02:00
Rosalie Wanders ba371f1349 RMG-Core: move Cheats-User directory to the user config directory 2023-06-11 19:37:14 +02:00
Rosalie Wanders 38ec62c238 RMG-Core: set error last in CoreStartEmulation() 2023-06-01 22:46:34 +02:00
Rosalie Wanders 942c2ee1b0 Package: update ArchLinux PKGBUILD 2023-06-01 22:39:11 +02:00
Rosalie Wanders 2a7d8aa4d2 RMG-Core: print callbacks even when callbacks haven't been setup 2023-05-06 00:49:29 +02:00
Rosalie Wanders b166eac200 Package: update InGame.png 2023-05-04 23:29:12 +02:00
Rosalie Wanders c06316f4aa Package: update RomBrowser.png 2023-05-04 23:27:22 +02:00
Rosalie Wanders 09d96d9e4d README: improve Support section 2023-05-04 23:18:23 +02:00
Rosalie Wanders 66703970b6 Package: v0.4.0 2023-05-04 22:49:45 +02:00
Rosalie Wanders 0d3314a39b 3rdParty: update mupen64plus-input-gca 2023-05-04 22:41:22 +02:00
Rosalie Wanders 748492cc68 Data: add more custom cheats from Gent 2023-05-04 22:25:00 +02:00
Rosalie Wanders e18ad31c53 RMG: set default QSurfaceFormat with vsync disabled in main.cpp 2023-05-04 22:24:32 +02:00
Rosalie Wanders 0dd297f0f8 3rdParty: update angrylion-rdp-plus 2023-04-24 16:42:52 +02:00
Rosalie Wanders 0da4becd46 3rdParty: update parallel-rsp 2023-04-24 16:40:35 +02:00
Rosalie Wanders d284911d4a Installer: don't skip Run when silent 2023-04-16 00:12:11 +02:00
Rosalie Wanders e772eb3906 RMG: don't install desktop icon on update on windows 2023-04-16 00:11:48 +02:00
Rosalie Wanders 577ee4c3e0 3rdParty: update GLideN64 2023-04-15 16:00:58 +02:00
Rosalie Wanders c534df8303 RMG: disable floating on toolbar 2023-04-13 17:47:47 +02:00
Rosalie Wanders a36c8f7de8 3rdParty: update SDL_GameControllerDB 2023-04-07 22:42:11 +02:00
Rosalie Wanders dfb5f1b687 Package: update InputSettings.png 2023-04-07 21:58:29 +02:00
Rosalie Wanders d8eea015fd RMG: allow the toolbar to be moved 2023-04-07 20:54:20 +02:00
Rosalie Wanders f17b7eb2c9 RMG-Core: add GUI_ToolbarArea setting 2023-04-07 20:52:06 +02:00
74 changed files with 5596 additions and 229 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
run: |
mkdir Build Build/AppImage Bin/ -p
export src_dir="$(pwd)"
export build_dir="$(pwd)/build"
export build_dir="$(pwd)/Build/AppImage"
export bin_dir="$(pwd)/Bin/AppImage"
cmake -S "$src_dir" -B "$build_dir" -DCMAKE_BUILD_TYPE="Release" -DPORTABLE_INSTALL="OFF" -DUPDATER=ON -DAPPIMAGE_UPDATER=ON -DCMAKE_INSTALL_PREFIX="/usr" -G "Ninja"
cmake --build "$build_dir"
+20 -1
View File
@@ -8,6 +8,7 @@ option(NO_GIT_CLONE "Disables git clone usage for 3rdParty dependencies" OFF
option(UPDATER "Enables updater" ${PORTABLE_INSTALL})
option(APPIMAGE_UPDATER "Enables AppImage updater" OFF)
option(DISCORD_RPC "Enables Discord Rich Presence" ON)
option(VRU "Enables VRU support in RMG-Input" ON)
option(USE_CCACHE "Enables usage of ccache when ccache has been found" ON)
option(FORCE_XCB "Forces Qt to use the xcb platform on linux" ${LINUX})
option(NO_RUST "Disables the building of rust subprojects" OFF)
@@ -61,12 +62,16 @@ if (PORTABLE_INSTALL)
set(CMAKE_INSTALL_PREFIX "")
set(INSTALL_PATH "Bin/${CMAKE_BUILD_TYPE}")
set(RMG_INSTALL_PATH "${INSTALL_PATH}")
set(SYSTEM_LIB_INSTALL_PATH "${INSTALL_PATH}")
set(LIB_INSTALL_PATH "${INSTALL_PATH}")
set(CORE_INSTALL_PATH "${INSTALL_PATH}/Core")
set(PLUGIN_INSTALL_PATH "${INSTALL_PATH}/Plugin")
set(DATA_INSTALL_PATH "${INSTALL_PATH}/Data")
set(INSTALL_DESKTOP_FILE OFF)
else()
set(RMG_INSTALL_PATH "bin")
set(SYSTEM_LIB_INSTALL_PATH "lib")
set(LIB_INSTALL_PATH "lib/RMG")
set(CORE_INSTALL_PATH "lib/RMG/Core")
set(PLUGIN_INSTALL_PATH "lib/RMG/Plugin")
set(DATA_INSTALL_PATH "share/RMG")
@@ -78,11 +83,17 @@ endif()
add_subdirectory(Source/3rdParty)
add_subdirectory(Source/3rdParty/7-Zip)
if (VRU)
add_subdirectory(Source/3rdParty/vosk-api)
endif(VRU)
add_subdirectory(Source/RMG-Core)
add_subdirectory(Source/RMG)
add_subdirectory(Source/RMG-Audio)
add_subdirectory(Source/RMG-Input)
install(TARGETS RMG-Core
DESTINATION ${SYSTEM_LIB_INSTALL_PATH}
)
install(TARGETS RMG
DESTINATION ${RMG_INSTALL_PATH}
)
@@ -95,7 +106,7 @@ install(TARGETS RMG-Input
if (WIN32)
add_subdirectory(Source/Installer)
add_custom_target(bundle_dependencies
COMMAND bash "${CMAKE_SOURCE_DIR}/Source/Script/BundleDependencies.sh" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}/RMG.exe" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}" "/mingw64/bin"
)
@@ -107,6 +118,14 @@ install(FILES ${MUPEN64PLUSCORE_LIB}
install(FILES ${MUPEN64PLUSCORE_INI} Data/font.ttf
DESTINATION ${DATA_INSTALL_PATH}
)
if (VRU)
install(FILES ${VOSK_API_LIBRARY}
DESTINATION ${LIB_INSTALL_PATH}
)
install(FILES ${VOSK_API_MODEL}
DESTINATION ${DATA_INSTALL_PATH}
)
endif(VRU)
install(FILES ${SDL_GAMECONTROLLERDB}
DESTINATION ${DATA_INSTALL_PATH}
)
@@ -0,0 +1,64 @@
[1FBAF161-2C1C54F1-C:41]
Name=1080 Snowboarding (JU) (M2)
$Enable All Levels & Boarders
80255089 00FF
8025508B 0005
81255096 FCFF
80255098 0007
$Have All\Contest First Place Done
80244098 0007
$Have All\Match Levels Completed
8025508A 0005
$Have All\Trick Attacks Done
81255096 FCFF
$Infinite Damage All Players & Levels
803F4C3C 0024
807F4C3C 0024
$Infinite Lives & Continues
8026B1CB 0003
$Always First Place (Player 1)
81267B88 2400
Note=The game will still show you in 2nd when you are behind. But when you cross the finish line, you will win!
$Open Level Character Select
Note=With these codes, you have to press the buttons listed below when you are viewing a certain boarders stats. Highlight Akari Hayami's stats, and then hold down the C-Left button and then press the A button to be the Crystal Boarder. Highlight Kensuke Kimachi's stats, and then hold down the C-Up button and then press the A button to be the Metal Boarder. Hightlight Rob Haywood's stats, and then hold down the C-Right button and then press the A button to be the Panda Boarder
8125508A 00??
01 Easy Level
02 Easy & Normal Level
03 Easy Normal & Hard Levels
04 Easy Normal Hard Levels & Crystal Boarder
05 Easy Normal Hard Levels & Crystal & Metal Boarders
$Play As
800200E7 00??
00 Dion Blaster
01 Kensuke Kimachi
02 Akari Hayami
03 Ricky Winterborn
04 Rob Haywood
05 Silver Boarder
06 Gold Boarder
07 Panda Boarder
$Freeze Timer In\Match Race
D1267B20 05E1
81267B20 1000
$Freeze Timer In\Time Attack
D12660CC 05E1
812660CC 1000
$Freeze Timer In\Trick Attack
D1266138 05E1
81266138 1000
$Freeze Timer In\Contest
D126628C 05E1
8126628C 1000
@@ -0,0 +1,55 @@
[58FD3F25-D92EAA8D-C:50]
Name=1080 Snowboarding (E) (M4)
$Enable All Levels & Boarders
80250AB9 00FF
80250ABB 0005
81250AC6 FCFF
80250AC8 0007
$Infinite Damage All Players and Levels
803F4C00 0024
807F4C00 0024
$Infinite Lives & Continues
802648A4 0003
$Open Level Character Select
Note=With these codes, you have to press the buttons listed below when you are viewing a certain boarders stats. Highlight Akari Hayami's stats, and then hold down the C-Left button and then press the A button to be the Crystal Boarder. Highlight Kensuke Kimachi's stats, and then hold down the C-Up button and then press the A button to be the Metal Boarder. Hightlight Rob Haywood's stats, and then hold down the C-Right button and then press the A button to be the Panda Boarder
8125508A 00??
01 Easy Level
02 Easy & Normal Level
03 Easy Normal & Hard Levels
04 Easy Normal Hard Levels & Crystal Boarder
05 Easy Normal Hard Levels & Crystal & Metal Boarders
$Play As
8001A0E7 00??
00 Dion Blaster
01 Kensuke Kimachi
02 Akari Hayami
03 Ricky Winterborn
04 Rob Haywood
05 Silver Boarder
06 Gold Boarder
07 Panda Boarder
$Always First Place (Player 1)
812679BC 2400
Note=The game will still show you in 2nd when you are behind. But when you cross the finish line, you will win!
$Freeze Timer In\Match Race
D1267954 05E1
81267954 1000
$Freeze Timer In\Time Attack
D1265D4C 05E1
81265D4C 1000
$Freeze Timer In\Trick Attack
D1265DB8 05E1
81265DB8 1000
$Freeze Timer In\Contest
D1265F48 05E1
81265F48 1000
+1
View File
@@ -4,6 +4,7 @@ set -e
cur_dir="$(readlink -f "$(dirname "$0")")"
exec "$cur_dir/usr/bin/RMG" \
--lib-path="$cur_dir/usr/lib/RMG" \
--core-path="$cur_dir/usr/lib/RMG/Core" \
--plugin-path="$cur_dir/usr/lib/RMG/Plugin" \
--shared-data-path="$cur_dir/usr/share/RMG" \
+1
View File
@@ -9,6 +9,7 @@ export QMAKE="$(which qmake6)"
export EXTRA_QT_PLUGINS="imageformats;iconengines;"
export VERSION="$(git describe --tags --always)"
export OUTPUT="$bin_dir/../RMG-Portable-Linux64-$VERSION.AppImage"
export LD_LIBRARY_PATH="$toplvl_dir/Build/AppImage/Source/RMG-Core" # hack
if [ ! -f "$script_dir/linuxdeploy-x86_64.AppImage" ]
then
+2 -2
View File
@@ -1,9 +1,9 @@
# Maintainer: Rosalie Wanders <rosalie@mailbox.org>
pkgname=rmg
pkgver=0.3.9
pkgver=0.4.4
pkgrel=1
pkgdesc="Rosalie's Mupen GUI"
arch=('x86_64')
arch=('x86_64' 'aarch64')
url="https://github.com/Rosalie241/$pkgname"
license=('GPL3')
Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 KiB

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 80 KiB

+72 -5
View File
@@ -1,4 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<!-- Copyright 2022 Rosalie Wanders -->
<component type="desktop">
<!--Created with jdAppdataEdit 2.1-->
<id>com.github.Rosalie241.RMG</id>
@@ -11,27 +12,93 @@
<description><p>Rosalie's Mupen GUI is an easy to use yet customizable mupen64plus front-end, allowing you to easily play N64 games.</p></description>
<screenshots>
<screenshot type="default">
<caption>The Rom Browser</caption>
<caption>01 - The Rom Browser</caption>
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/RomBrowser.png</image>
</screenshot>
<screenshot type="default">
<caption>During A Game</caption>
<caption>02 - During A Game</caption>
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/InGame.png</image>
</screenshot>
<screenshot type="default">
<caption>Cheats</caption>
<caption>03 - Cheats</caption>
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/Cheats.png</image>
</screenshot>
<screenshot type="default">
<caption>Settings</caption>
<caption>04 - Settings</caption>
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/Settings.png</image>
</screenshot>
<screenshot type="default">
<caption>Input Settings</caption>
<caption>05 - Input Settings</caption>
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/InputSettings.png</image>
</screenshot>
</screenshots>
<releases>
<release version="v0.4.4" date="2023-07-17" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix memory leak when using a 64DD disk in an archive</li>
<li>Fix fallback of mupen64plus-rsp-hle not working on first run</li>
<li>Fix 'Screenshot Captured' OSD message not appearing when using controller hotkeys</li>
<li>Fix dynamic recompiler crashing on ARM64 since v0.4.1</li>
<li>Add support for joysticks/triggers for hotkeys in RMG-Input</li>
<li>Add hotkeys for increasing and decreasing the save state slot in RMG-Input</li>
<li>Add hotkeys for switching controller paks in RMG-Input</li>
<li>Improve deadzone and sensitivity code in RMG-Input (thank you JaxonWasTaken)</li>
</ul>
</description>
</release>
<release version="v0.4.3" date="2023-07-11" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix minor corruption issues when using GLideN64 in Wave Race 64 and Space Station Silicon Valley</li>
<li>Fix some potential issues with out of bounds RDRAM reads (thank you loganmc10)</li>
<li>Fix ROM browser not updating entries when they've changed in the ROM database</li>
<li>Fix mupen64plus-rsp-hle not having a fallback configured (fixes Xeno Crisis not booting with mupen64plus-rsp-hle)</li>
<li>Fix Xeno Crisis showing an error message</li>
<li>Add Xeno Crisis to the ROM database</li>
</ul>
</description>
</release>
<release version="v0.4.2" date="2023-07-07" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix window behavior issues when saving GLideN64 settings while in-game</li>
<li>Add VRU support to RMG-Input</li>
<li>Add controller hotkey support to RMG-Input</li>
<li>Improve window title by using the ROM filename when the ROM isn't in the database</li>
</ul>
</description>
</release>
<release version="v0.4.1" date="2023-06-19" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix debug callbacks not printing before GUI has been started</li>
<li>Fix emulation error being incorrect in some cases</li>
<li>Fix user cheat file location (new ones will be placed in the user config directory instead of the user data directory)</li>
<li>Fix mupen64plus-input-gca crashing in v0.4.0 due to updating to a broken commit</li>
<li>Fix Paper Mario crashing when using the hammer on a specific tree in-game by implementing RDRAM address range 0x0800000-0x03EFFFFF</li>
<li>Improve accuracy of the pure and cached interpreter</li>
<li>Add *.st* and *.pj* to the file filter when loading a save state from a file</li>
</ul>
</description>
</release>
<release version="v0.4.0" date="2023-05-04" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix updater on windows always installing the desktop icon</li>
<li>Fix updater on windows not re-launching RMG after installation</li>
<li>Fix the speed limiter toggle and speed factor options not working on linux on some systems</li>
<li>Fix the 1080 Snowboarding cheats (thank you Gent)</li>
<li>Add support for moving the toolbar (changes to the docked position are persistent across application runs)</li>
<li>Update GLideN64 and mupen64plus-input-gca</li>
</ul>
</description>
</release>
<release version="v0.3.9" date="2023-04-06" type="stable">
<description>
<p>Changes:</p>
+3 -1
View File
@@ -17,7 +17,9 @@ You can download Rosalie's Mupen GUI on
## Support
Join the [Rosalie's Mupen GUI Discord Server](https://discord.gg/k9GuyJ2PpF) for support
You can ask for help or report issues on
* [Github](https://github.com/Rosalie241/RMG/issues/new)
* [Discord](https://discord.gg/k9GuyJ2PpF)
## License
+1 -1
View File
@@ -31,7 +31,7 @@ set(7ZIP_SOURCES
add_custom_command(
OUTPUT ${7ZIP_SOURCES}
COMMAND ${CMAKE_COMMAND} -E tar "xvz" "${CMAKE_CURRENT_SOURCE_DIR}/lzma2201.tar.gz"
COMMAND ${CMAKE_COMMAND} -E tar "xvz" "${CMAKE_CURRENT_SOURCE_DIR}/lzma2301.tar.gz"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
+1 -1
View File
@@ -1,2 +1,2 @@
# 7-Zip SDK v22.01
# 7-Zip SDK v23.01
Downloaded from https://www.7-zip.org/sdk.html
Binary file not shown.
Binary file not shown.
+11 -11
View File
@@ -38,8 +38,8 @@ else(USE_CCACHE)
endif(USE_CCACHE)
if(NOT NO_GIT_CLONE)
set(MUPEN64PLUSCORE_URL "https://github.com/mupen64plus/mupen64plus-core")
set(MUPEN64PLUSCORE_TAG "d4f3e12db0609158c7b4e0beef2bb950aad0ccb9")
set(MUPEN64PLUSCORE_URL "https://github.com/Rosalie241/mupen64plus-core")
set(MUPEN64PLUSCORE_TAG "9c4e7837b13ace684b6429674d5e89cc81c57e12")
set(MUPEN64PLUS_RSP_CXD4_URL "https://github.com/mupen64plus/mupen64plus-rsp-cxd4")
set(MUPEN64PLUS_RSP_CXD4_TAG "39f79201baa15890c4cbae92f2215a634cc3ee6d")
@@ -48,7 +48,7 @@ if(NOT NO_GIT_CLONE)
set(MUPEN64PLUS_RSP_HLE_TAG "88093cb43499eff53d343653cddcae2132af17ef")
set(MUPEN64PLUS_RSP_PARALLEL_URL "https://github.com/Rosalie241/parallel-rsp")
set(MUPEN64PLUS_RSP_PARALLEL_TAG "cfeea3a0f89ba5bc4265acb75778e1267ed1e424")
set(MUPEN64PLUS_RSP_PARALLEL_TAG "dbecbe3a120e428436c5972fa7b872cfc2c9db3e")
set(MUPEN64PLUS_INPUT_RAPHNET_URL "https://github.com/raphnet/mupen64plus-input-raphnetraw")
set(MUPEN64PLUS_INPUT_RAPHNET_TAG "86112413e98a8648edb11d199673cc24d5799af8")
@@ -57,10 +57,10 @@ if(NOT NO_GIT_CLONE)
set(MUPEN64PLUS_INPUT_GCA_TAG "21639fb13dfa797a7c0949ffd9bbda9a3456fc69")
set(MUPEN64PLUS_GFX_ANGRYLION_URL "https://github.com/Rosalie241/angrylion-rdp-plus")
set(MUPEN64PLUS_GFX_ANGRYLION_TAG "158e74d4ec1c818289cd19c3a05e498c3ceff758")
set(MUPEN64PLUS_GFX_ANGRYLION_TAG "670abbc972bd430fa77291b0967dd73128314317")
set(MUPEN64PLUS_GFX_GLIDEN64_URL "https://github.com/gonetz/GLideN64")
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "1f4d04f43b53739bc9b128ab5577d20e3d60ed6a")
set(MUPEN64PLUS_GFX_GLIDEN64_URL "https://github.com/Rosalie241/GLideN64")
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "2f1b358028e700fcae2502a53f4f5e6822ce0367")
set(MUPEN64PLUS_GFX_PARALLEL_URL "https://github.com/Rosalie241/parallel-rdp-standalone")
set(MUPEN64PLUS_GFX_PARALLEL_TAG "2c2226517c4c8929e08ec944654867e26efe0cf5")
@@ -72,7 +72,7 @@ if(NOT NO_GIT_CLONE)
set(IMGUI_TAG "d7c8516a4b848c0291e3d75b627c0843f515f591")
set(SDL_GAMECONTROLLERDB_URL "https://github.com/gabomdq/SDL_GameControllerDB")
set(SDL_GAMECONTROLLERDB_TAG "0562b00eaf5c0308c49d329b79263d2dae1c3a85")
set(SDL_GAMECONTROLLERDB_TAG "5e25aeccb84fb166451443c4cd9fff349e8b0360")
endif(NOT NO_GIT_CLONE)
ExternalProject_Add(mupen64plus-core
@@ -84,11 +84,11 @@ ExternalProject_Add(mupen64plus-core
GIT_REPOSITORY ${MUPEN64PLUSCORE_URL}
GIT_TAG ${MUPEN64PLUSCORE_TAG}
BUILD_COMMAND make all OSD=0 NEW_DYNAREC=1 TARGET=${CORE_FILE} DEBUG=$<CONFIG:Debug> KEYBINDINGS=0 CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
BUILD_COMMAND make all OSD=0 NEW_DYNAREC=1 KEYBINDINGS=0 ACCURATE_FPU=1 TARGET=${CORE_FILE} DEBUG=$<CONFIG:Debug> CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
BUILD_IN_SOURCE False
BINARY_DIR ${M64P_CORE_DIR}/projects/unix
BUILD_BYPRODUCTS ${M64P_CORE_DIR}/projects/unix/${CORE_FILE}
)
@@ -107,7 +107,7 @@ ExternalProject_Add(mupen64plus-rsp-cxd4
BUILD_IN_SOURCE False
BINARY_DIR ${THIRDPARTY_DIR}/mupen64plus-rsp-cxd4/projects/unix
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-rsp-cxd4/projects/unix/mupen64plus-rsp-cxd4.${SO_EXT}
DEPENDS mupen64plus-core
)
@@ -158,7 +158,7 @@ ExternalProject_Add(mupen64plus-input-raphnetraw
BUILD_IN_SOURCE False
BINARY_DIR ${THIRDPARTY_DIR}/mupen64plus-input-raphnetraw/projects/unix
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-input-raphnetraw/projects/unix/mupen64plus-input-raphnetraw.${SO_EXT}
DEPENDS mupen64plus-core
)
+27
View File
@@ -0,0 +1,27 @@
#
# 7-Zip CMakeLists.txt
#
project(vosk-api)
set(VOSK_API_VERSION "0.3.45")
if (WIN32)
set(VOSK_API_PLATFORM "win64")
set(SO_EXT "dll")
else(WIN32)
set(SO_EXT "so")
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
set(VOSK_API_PLATFORM "linux-aarch64")
else()
set(VOSK_API_PLATFORM "linux-x86_64")
endif()
endif(WIN32)
set(VOSK_API_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/vosk-${VOSK_API_PLATFORM}-${VOSK_API_VERSION}/libvosk.${SO_EXT}
)
add_library(vosk-api IMPORTED SHARED ${VOSK_API_SOURCES})
set(VOSK_API_LIBRARY ${VOSK_API_SOURCES} PARENT_SCOPE)
set(VOSK_API_MODEL "${CMAKE_CURRENT_SOURCE_DIR}/vosk-model-small-en-us-0.15.zip" PARENT_SCOPE)
+4
View File
@@ -0,0 +1,4 @@
# vosk-api
Downloaded from https://github.com/alphacep/vosk-api/releases/tag/v0.3.45
# vosk-model-small-en-us-0.15.zip
Downloaded from https://alphacephei.com/vosk/models
+361
View File
@@ -0,0 +1,361 @@
// Copyright 2020-2021 Alpha Cephei Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/* This header contains the C API for Vosk speech recognition system */
#ifndef VOSK_API_H
#define VOSK_API_H
#ifdef __cplusplus
extern "C" {
#endif
/** Model stores all the data required for recognition
* it contains static data and can be shared across processing
* threads. */
typedef struct VoskModel VoskModel;
/** Speaker model is the same as model but contains the data
* for speaker identification. */
typedef struct VoskSpkModel VoskSpkModel;
/** Recognizer object is the main object which processes data.
* Each recognizer usually runs in own thread and takes audio as input.
* Once audio is processed recognizer returns JSON object as a string
* which represent decoded information - words, confidences, times, n-best lists,
* speaker information and so on */
typedef struct VoskRecognizer VoskRecognizer;
/**
* Batch model object
*/
typedef struct VoskBatchModel VoskBatchModel;
/**
* Batch recognizer object
*/
typedef struct VoskBatchRecognizer VoskBatchRecognizer;
/** Loads model data from the file and returns the model object
*
* @param model_path: the path of the model on the filesystem
* @returns model object or NULL if problem occured */
VoskModel *vosk_model_new(const char *model_path);
/** Releases the model memory
*
* The model object is reference-counted so if some recognizer
* depends on this model, model might still stay alive. When
* last recognizer is released, model will be released too. */
void vosk_model_free(VoskModel *model);
/** Check if a word can be recognized by the model
* @param word: the word
* @returns the word symbol if @param word exists inside the model
* or -1 otherwise.
* Reminding that word symbol 0 is for <epsilon> */
int vosk_model_find_word(VoskModel *model, const char *word);
/** Loads speaker model data from the file and returns the model object
*
* @param model_path: the path of the model on the filesystem
* @returns model object or NULL if problem occured */
VoskSpkModel *vosk_spk_model_new(const char *model_path);
/** Releases the model memory
*
* The model object is reference-counted so if some recognizer
* depends on this model, model might still stay alive. When
* last recognizer is released, model will be released too. */
void vosk_spk_model_free(VoskSpkModel *model);
/** Creates the recognizer object
*
* The recognizers process the speech and return text using shared model data
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sample_rate The sample rate of the audio you going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @returns recognizer object or NULL if problem occured */
VoskRecognizer *vosk_recognizer_new(VoskModel *model, float sample_rate);
/** Creates the recognizer object with speaker recognition
*
* With the speaker recognition mode the recognizer not just recognize
* text but also return speaker vectors one can use for speaker identification
*
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sample_rate The sample rate of the audio you going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @param spk_model speaker model for speaker identification
* @returns recognizer object or NULL if problem occured */
VoskRecognizer *vosk_recognizer_new_spk(VoskModel *model, float sample_rate, VoskSpkModel *spk_model);
/** Creates the recognizer object with the phrase list
*
* Sometimes when you want to improve recognition accuracy and when you don't need
* to recognize large vocabulary you can specify a list of phrases to recognize. This
* will improve recognizer speed and accuracy but might return [unk] if user said
* something different.
*
* Only recognizers with lookahead models support this type of quick configuration.
* Precompiled HCLG graph models are not supported.
*
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sample_rate The sample rate of the audio you going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @param grammar The string with the list of phrases to recognize as JSON array of strings,
* for example "["one two three four five", "[unk]"]".
*
* @returns recognizer object or NULL if problem occured */
VoskRecognizer *vosk_recognizer_new_grm(VoskModel *model, float sample_rate, const char *grammar);
/** Adds speaker model to already initialized recognizer
*
* Can add speaker recognition model to already created recognizer. Helps to initialize
* speaker recognition for grammar-based recognizer.
*
* @param spk_model Speaker recognition model */
void vosk_recognizer_set_spk_model(VoskRecognizer *recognizer, VoskSpkModel *spk_model);
/** Reconfigures recognizer to use grammar
*
* @param recognizer Already running VoskRecognizer
* @param grammar Set of phrases in JSON array of strings or "[]" to use default model graph.
* See also vosk_recognizer_new_grm
*/
void vosk_recognizer_set_grm(VoskRecognizer *recognizer, char const *grammar);
/** Configures recognizer to output n-best results
*
* <pre>
* {
* "alternatives": [
* { "text": "one two three four five", "confidence": 0.97 },
* { "text": "one two three for five", "confidence": 0.03 },
* ]
* }
* </pre>
*
* @param max_alternatives - maximum alternatives to return from recognition results
*/
void vosk_recognizer_set_max_alternatives(VoskRecognizer *recognizer, int max_alternatives);
/** Enables words with times in the output
*
* <pre>
* "result" : [{
* "conf" : 1.000000,
* "end" : 1.110000,
* "start" : 0.870000,
* "word" : "what"
* }, {
* "conf" : 1.000000,
* "end" : 1.530000,
* "start" : 1.110000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 1.950000,
* "start" : 1.530000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.340000,
* "start" : 1.950000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.610000,
* "start" : 2.340000,
* "word" : "one"
* }],
* </pre>
*
* @param words - boolean value
*/
void vosk_recognizer_set_words(VoskRecognizer *recognizer, int words);
/** Like above return words and confidences in partial results
*
* @param partial_words - boolean value
*/
void vosk_recognizer_set_partial_words(VoskRecognizer *recognizer, int partial_words);
/** Set NLSML output
* @param nlsml - boolean value
*/
void vosk_recognizer_set_nlsml(VoskRecognizer *recognizer, int nlsml);
/** Accept voice data
*
* accept and process new chunk of voice data
*
* @param data - audio data in PCM 16-bit mono format
* @param length - length of the audio data
* @returns 1 if silence is occured and you can retrieve a new utterance with result method
* 0 if decoding continues
* -1 if exception occured */
int vosk_recognizer_accept_waveform(VoskRecognizer *recognizer, const char *data, int length);
/** Same as above but the version with the short data for language bindings where you have
* audio as array of shorts */
int vosk_recognizer_accept_waveform_s(VoskRecognizer *recognizer, const short *data, int length);
/** Same as above but the version with the float data for language bindings where you have
* audio as array of floats */
int vosk_recognizer_accept_waveform_f(VoskRecognizer *recognizer, const float *data, int length);
/** Returns speech recognition result
*
* @returns the result in JSON format which contains decoded line, decoded
* words, times in seconds and confidences. You can parse this result
* with any json parser
*
* <pre>
* {
* "text" : "what zero zero zero one"
* }
* </pre>
*
* If alternatives enabled it returns result with alternatives, see also vosk_recognizer_set_max_alternatives().
*
* If word times enabled returns word time, see also vosk_recognizer_set_word_times().
*/
const char *vosk_recognizer_result(VoskRecognizer *recognizer);
/** Returns partial speech recognition
*
* @returns partial speech recognition text which is not yet finalized.
* result may change as recognizer process more data.
*
* <pre>
* {
* "partial" : "cyril one eight zero"
* }
* </pre>
*/
const char *vosk_recognizer_partial_result(VoskRecognizer *recognizer);
/** Returns speech recognition result. Same as result, but doesn't wait for silence
* You usually call it in the end of the stream to get final bits of audio. It
* flushes the feature pipeline, so all remaining audio chunks got processed.
*
* @returns speech result in JSON format.
*/
const char *vosk_recognizer_final_result(VoskRecognizer *recognizer);
/** Resets the recognizer
*
* Resets current results so the recognition can continue from scratch */
void vosk_recognizer_reset(VoskRecognizer *recognizer);
/** Releases recognizer object
*
* Underlying model is also unreferenced and if needed released */
void vosk_recognizer_free(VoskRecognizer *recognizer);
/** Set log level for Kaldi messages
*
* @param log_level the level
* 0 - default value to print info and error messages but no debug
* less than 0 - don't print info messages
* greather than 0 - more verbose mode
*/
void vosk_set_log_level(int log_level);
/**
* Init, automatically select a CUDA device and allow multithreading.
* Must be called once from the main thread.
* Has no effect if HAVE_CUDA flag is not set.
*/
void vosk_gpu_init();
/**
* Init CUDA device in a multi-threaded environment.
* Must be called for each thread.
* Has no effect if HAVE_CUDA flag is not set.
*/
void vosk_gpu_thread_init();
/** Creates the batch recognizer object
*
* @returns model object or NULL if problem occured */
VoskBatchModel *vosk_batch_model_new(const char *model_path);
/** Releases batch model object */
void vosk_batch_model_free(VoskBatchModel *model);
/** Wait for the processing */
void vosk_batch_model_wait(VoskBatchModel *model);
/** Creates batch recognizer object
* @returns recognizer object or NULL if problem occured */
VoskBatchRecognizer *vosk_batch_recognizer_new(VoskBatchModel *model, float sample_rate);
/** Releases batch recognizer object */
void vosk_batch_recognizer_free(VoskBatchRecognizer *recognizer);
/** Accept batch voice data */
void vosk_batch_recognizer_accept_waveform(VoskBatchRecognizer *recognizer, const char *data, int length);
/** Set NLSML output
* @param nlsml - boolean value
*/
void vosk_batch_recognizer_set_nlsml(VoskBatchRecognizer *recognizer, int nlsml);
/** Closes the stream */
void vosk_batch_recognizer_finish_stream(VoskBatchRecognizer *recognizer);
/** Return results */
const char *vosk_batch_recognizer_front_result(VoskBatchRecognizer *recognizer);
/** Release and free first retrieved result */
void vosk_batch_recognizer_pop(VoskBatchRecognizer *recognizer);
/** Get amount of pending chunks for more intelligent waiting */
int vosk_batch_recognizer_get_pending_chunks(VoskBatchRecognizer *recognizer);
#ifdef __cplusplus
}
#endif
#endif /* VOSK_API_H */
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -55,5 +55,5 @@ Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall
+1 -2
View File
@@ -4,7 +4,6 @@
project(RMG-Core)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
@@ -68,7 +67,7 @@ if (PORTABLE_INSTALL)
add_definitions(-DPORTABLE_INSTALL)
endif(PORTABLE_INSTALL)
add_library(RMG-Core STATIC ${RMG_CORE_SOURCES})
add_library(RMG-Core SHARED ${RMG_CORE_SOURCES})
if(UNIX)
target_link_libraries(RMG-Core dl)
@@ -9,6 +9,8 @@
*/
#include "CachedRomHeaderAndSettings.hpp"
#include "Directories.hpp"
#include "RomSettings.hpp"
#include "RomHeader.hpp"
#include "Error.hpp"
#include "osal/osal_files.hpp"
@@ -307,6 +309,53 @@ bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType t
return true;
}
bool CoreUpdateCachedRomHeaderAndSettings(std::filesystem::path file)
{
l_CacheEntry cachedEntry;
CoreRomType type;
CoreRomHeader header;
CoreRomSettings settings;
// try to find existing entry with same filename,
// when not found, do nothing
auto iter = get_cache_entry_iter(file, false);
if (iter == l_CacheEntries.end())
{
return true;
}
cachedEntry = (*iter);
// attempt to retrieve required information
if (!CoreGetRomType(type) ||
!CoreGetCurrentRomHeader(header) ||
!CoreGetCurrentDefaultRomSettings(settings))
{
return false;
}
// check if the cached entry needs to be updated,
// if it does, then update the entry
if (/* rom type */
cachedEntry.type != type ||
/* header */
cachedEntry.header.Name != header.Name ||
cachedEntry.header.Region != header.Region ||
cachedEntry.header.CRC1 != header.CRC1 ||
cachedEntry.header.CRC2 != header.CRC2 ||
/* settings */
cachedEntry.settings.MD5 != settings.MD5 ||
cachedEntry.settings.GoodName != settings.GoodName)
{
(*iter).type = type;
(*iter).header = header;
(*iter).settings.MD5 = settings.MD5;
(*iter).settings.GoodName = settings.GoodName;
l_CacheEntriesChanged = true;
}
return true;
}
bool CoreClearRomHeaderAndSettingsCache(void)
{
l_CacheEntries.clear();
@@ -37,6 +37,12 @@ bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType&
// for given filename succeeds
bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType type, CoreRomHeader header, CoreRomSettings settings);
#ifdef CORE_INTERNAL
// returns whether updating the cached rom header & settings
// for given filename succeeds
bool CoreUpdateCachedRomHeaderAndSettings(std::filesystem::path file);
#endif // CORE_INTERNAL
// returns whether clearing rom header & settings cache
// succeeds
bool CoreClearRomHeaderAndSettingsCache(void);
+29 -8
View File
@@ -22,20 +22,29 @@ static std::function<void(enum CoreDebugMessageType, std::string, std::string)>
static std::function<void(enum CoreStateCallbackType, int)> l_StateCallbackFunc;
static bool l_PrintCallbacks = false;
static bool l_SetupDebugMessageCallback = false;
static std::function<void(void*, int, const char*)> l_DebugMessageCallbackFunc;
static void* l_DebugMessageCallbackFuncContext;
//
// Internal Functions
//
void CoreDebugCallback(void* context, int level, const char* message)
{
std::string contextString((const char*)context);
std::string messageString(message);
if (l_PrintCallbacks)
{
std::cout << contextString << messageString << std::endl;
}
if (!l_SetupCallbacks)
{
return;
}
std::string contextString((const char*)context);
std::string messageString(message);
// convert string encoding accordingly
if (messageString.starts_with("IS64:"))
{
@@ -46,11 +55,6 @@ void CoreDebugCallback(void* context, int level, const char* message)
messageString = CoreConvertStringEncoding(message, CoreStringEncoding::Shift_JIS);
}
if (l_PrintCallbacks)
{
std::cout << contextString << messageString << std::endl;
}
l_DebugCallbackFunc((CoreDebugMessageType)level, contextString, messageString);
}
@@ -81,3 +85,20 @@ void CoreSetPrintDebugCallback(bool enabled)
{
l_PrintCallbacks = enabled;
}
void CoreSetupDebugCallbackMessage(std::function<void(void*, int, const char*)> debugCallbackFunc, void* debugCallbackFuncContext)
{
l_DebugMessageCallbackFunc = debugCallbackFunc;
l_DebugMessageCallbackFuncContext = debugCallbackFuncContext;
l_SetupDebugMessageCallback = true;
}
void CoreDebugCallbackMessage(CoreDebugMessageType type, std::string message)
{
if (!l_SetupDebugMessageCallback)
{
return;
}
l_DebugMessageCallbackFunc(l_DebugMessageCallbackFuncContext, (int)type, message.c_str());
}
+9
View File
@@ -45,6 +45,7 @@ enum class CoreStateCallbackType
GamesharkInput,
SaveStateLoaded,
SaveStateSaved,
ScreenshotCaptured,
};
// attempts to setup callbacks with the provided functions
@@ -54,4 +55,12 @@ bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::strin
// sets whether the debug callbacks will be printed to stdout
void CoreSetPrintDebugCallback(bool enabled);
#ifdef CORE_PLUGIN
// attempts to setup up the debug message debug callback
void CoreSetupDebugCallbackMessage(std::function<void(void*, int, const char*)> debugCallbackFunc, void* debugCallbackFuncContext);
// sends a debug message to the debug callback (if it exists)
void CoreDebugCallbackMessage(CoreDebugMessageType type, std::string message);
#endif // CORE_PLUGIN
#endif // CORE_CALLBACK_HPP
+18 -5
View File
@@ -118,9 +118,16 @@ static std::filesystem::path get_shared_cheat_file_path(CoreRomHeader romHeader,
static std::filesystem::path get_user_cheat_file_path(CoreRomHeader romHeader, CoreRomSettings romSettings)
{
std::filesystem::path oldCheatFilePath;
std::filesystem::path cheatFilePath;
cheatFilePath = CoreGetUserDataDirectory();
oldCheatFilePath = CoreGetUserDataDirectory();
oldCheatFilePath += OSAL_FILES_DIR_SEPERATOR_STR;
oldCheatFilePath += "Cheats-User";
oldCheatFilePath += OSAL_FILES_DIR_SEPERATOR_STR;
oldCheatFilePath += get_cheat_file_name(romHeader, romSettings);
cheatFilePath = CoreGetUserConfigDirectory();
cheatFilePath += OSAL_FILES_DIR_SEPERATOR_STR;
cheatFilePath += "Cheats-User";
cheatFilePath += OSAL_FILES_DIR_SEPERATOR_STR;
@@ -140,6 +147,12 @@ static std::filesystem::path get_user_cheat_file_path(CoreRomHeader romHeader, C
// we'll fail later...
}
// keep compatability with <v0.4.1
if (std::filesystem::is_regular_file(oldCheatFilePath))
{
return oldCheatFilePath;
}
return cheatFilePath;
}
@@ -162,7 +175,7 @@ static std::string join_split_string(std::vector<std::string> splitStr, char sep
std::string joinedString;
std::string element;
int skippedElements = 0;
for (int i = 0; i < splitStr.size(); i++)
for (uint32_t i = 0; i < splitStr.size(); i++)
{
// allow for skipping elements
if (skippedElements++ < skip)
@@ -188,7 +201,7 @@ static bool parse_cheat(std::vector<std::string> lines, int startIndex, CoreChea
{
std::string error;
std::string line;
for (int i = startIndex; i < lines.size(); i++)
for (uint32_t i = startIndex; i < lines.size(); i++)
{
line = lines.at(i);
@@ -327,7 +340,7 @@ static bool parse_cheat_file(std::vector<std::string> lines, CoreCheatFile& chea
bool readHeader = false;
bool readHeaderName = false;
for (int index = 0; index < lines.size(); index++)
for (uint32_t index = 0; index < lines.size(); index++)
{
line = lines.at(index);
@@ -898,7 +911,7 @@ bool CoreGetCheatOption(CoreCheat cheat, CoreCheatOption& option)
for (CoreCheatOption& cheatOption : cheat.CheatOptions)
{
if (cheatOption.Value == value)
if (cheatOption.Value == (uint32_t)value)
{
option = cheatOption;
return true;
+1 -2
View File
@@ -27,7 +27,6 @@ std::string CoreConvertStringEncoding(std::string str, CoreStringEncoding encodi
iconv_t cd;
char inputBuf[256] = {0};
char outputBuf[256] = {0};
char* inputBufPtr = (char*)str.c_str();
@@ -56,7 +55,7 @@ std::string CoreConvertStringEncoding(std::string str, CoreStringEncoding encodi
}
size_t ret = iconv(cd, &inputBufPtr, &inputBufSize, &outputBufPtr, &outputBufSize);
if (ret == -1)
if (ret == (size_t)-1)
{
error = "CoreConvertStringEncoding Failed: ";
error += "iconv Failed: ";
+2 -2
View File
@@ -174,7 +174,7 @@ bool CoreInit(m64p_dynlib_handle handle)
std::string error;
bool ret = false;
ret = m64p::Core.Hook(handle);
ret = m64p::Core.IsHooked() || m64p::Core.Hook(handle);
if (!ret)
{
error = m64p::Core.GetLastError();
@@ -182,7 +182,7 @@ bool CoreInit(m64p_dynlib_handle handle)
return false;
}
ret = m64p::Config.Hook(handle);
ret = m64p::Config.IsHooked() || m64p::Config.Hook(handle);
if (!ret)
{
error = m64p::Config.GetLastError();
+25
View File
@@ -22,6 +22,7 @@
// Local Variables
//
static std::filesystem::path l_LibraryPathOverride;
static std::filesystem::path l_CorePathOverride;
static std::filesystem::path l_PluginPathOverride;
static std::filesystem::path l_SharedDataPathOverride;
@@ -125,6 +126,25 @@ bool CoreCreateDirectories(void)
return true;
}
std::filesystem::path CoreGetLibraryDirectory(void)
{
std::filesystem::path directory;
#ifdef PORTABLE_INSTALL
directory = ".";
#else // Not Portable
if (!l_LibraryPathOverride.empty())
{
directory = l_LibraryPathOverride;
}
else
{
directory = CORE_INSTALL_PREFIX;
directory += "/lib/RMG/";
}
#endif // PORTABLE_INSTALL
return directory;
}
std::filesystem::path CoreGetCoreDirectory(void)
{
std::filesystem::path directory;
@@ -284,6 +304,11 @@ std::filesystem::path CoreGetScreenshotDirectory(void)
}
#ifndef PORTABLE_INSTALL
void CoreSetLibraryPathOverride(std::filesystem::path path)
{
l_LibraryPathOverride = path;
}
void CoreSetCorePathOverride(std::filesystem::path path)
{
l_CorePathOverride = path;
+7
View File
@@ -21,6 +21,10 @@ bool CoreCreateDirectories(void);
// located
std::filesystem::path CoreGetCoreDirectory(void);
// returns the library directory where
// misc libraries should be located
std::filesystem::path CoreGetLibraryDirectory(void);
// returns the plugin directory where
// plugins should be located
std::filesystem::path CoreGetPluginDirectory(void);
@@ -73,6 +77,9 @@ std::filesystem::path CoreGetSaveStateDirectory(void);
// screenshots should be located
std::filesystem::path CoreGetScreenshotDirectory(void);
// changes the library path to the given path
void CoreSetLibraryPathOverride(std::filesystem::path path);
// changes the core path to the given path
void CoreSetCorePathOverride(std::filesystem::path path);
+5 -1
View File
@@ -158,7 +158,6 @@ bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64d
{
error = "CoreStartEmulation m64p::Core.DoCommand(M64CMD_EXECUTE) Failed: ";
error += m64p::Core.ErrorMessage(ret);
CoreSetError(error);
}
CoreClearCheats();
@@ -175,6 +174,11 @@ bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64d
CoreDiscordRpcUpdate(false);
#endif // DISCORD_RPC
// we need to set the emulation error last,
// to prevent the other functions from
// overriding the emulation error
CoreSetError(error);
return ret == M64ERR_SUCCESS;
}
+7
View File
@@ -12,6 +12,13 @@
#include <filesystem>
enum class CoreEmulationState
{
Stopped = 1,
Running,
Paused
};
// starts emulation with given ROM
bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64ddrom);
+1 -2
View File
@@ -16,11 +16,10 @@
#include "RomSettings.hpp"
#include "Settings/Settings.hpp"
#include "m64p/PluginApi.hpp"
#include "osal/osal_dynlib.hpp"
#include "osal/osal_files.hpp"
#include "m64p/PluginApi.cpp"
#include "m64p/PluginApi.hpp"
#include "m64p/Api.hpp"
#include <filesystem>
+35 -10
View File
@@ -7,6 +7,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#define CORE_INTERNAL
#include "Rom.hpp"
#include "Directories.hpp"
#include "Error.hpp"
@@ -15,6 +16,7 @@
#include "RomSettings.hpp"
#include "Cheats.hpp"
#include "osal/osal_files.hpp"
#include "CachedRomHeaderAndSettings.hpp"
// 7-Zip includes
#include "../3rdParty/7-Zip/C/7zTypes.h"
@@ -46,6 +48,7 @@ static bool l_HasRomOpen = false;
static bool l_HasDisk = false;
static bool l_HasExtractedDisk = false;
static std::filesystem::path l_ExtractedDiskPath;
static std::filesystem::path l_RomPath;
//
// Local Functions
@@ -135,8 +138,6 @@ static bool read_zip_file(std::filesystem::path file, std::filesystem::path* ext
{
std::string error;
std::fstream fileStream;
int fileStreamLen;
char* fileStreamBuf;
unzFile zipFile;
unz_global_info64 zipInfo;
@@ -178,7 +179,7 @@ static bool read_zip_file(std::filesystem::path file, std::filesystem::path* ext
return false;
}
for (int i = 0; i < zipInfo.number_entry; i++)
for (uint64_t i = 0; i < zipInfo.number_entry; i++)
{
unz_file_info fileInfo;
char fileName[PATH_MAX];
@@ -354,7 +355,7 @@ static bool read_7zip_file(std::filesystem::path file, std::filesystem::path* ex
// initialize look reader
lookStream.bufSize = bufSize;
lookStream.realStream = &archiveStream.vt;
LookToRead2_Init(&lookStream);
LookToRead2_INIT(&lookStream);
// initialize CRC table
CrcGenerateTable();
@@ -374,7 +375,7 @@ static bool read_7zip_file(std::filesystem::path file, std::filesystem::path* ex
return false;
}
for (int i = 0; i < db.NumFiles; i++)
for (uint32_t i = 0; i < db.NumFiles; i++)
{
size_t filename_size = 0;
uint16_t fileName[PATH_MAX];
@@ -584,12 +585,10 @@ bool CoreOpenRom(std::filesystem::path file)
// attempt to create extraction directory
try
{
if (!std::filesystem::exists(disk_file.parent_path()))
if (!std::filesystem::exists(disk_file.parent_path()) &&
!std::filesystem::create_directory(disk_file.parent_path()))
{
if (!std::filesystem::create_directory(disk_file.parent_path()))
{
throw std::exception();
}
throw std::exception();
}
}
catch (...)
@@ -599,12 +598,14 @@ bool CoreOpenRom(std::filesystem::path file)
error += disk_file.parent_path().string();
error += "\"!";
CoreSetError(error);
free(buf);
return false;
}
// attempt to write temporary file
if (!write_file(disk_file, buf, buf_size))
{
free(buf);
return false;
}
@@ -643,6 +644,10 @@ bool CoreOpenRom(std::filesystem::path file)
{
ret = m64p::Core.DoCommand(M64CMD_ROM_OPEN, buf_size, buf);
error = "CoreOpenRom: m64p::Core.DoCommand(M64CMD_ROM_OPEN) Failed: ";
}
if (!l_HasDisk || l_HasExtractedDisk)
{
free(buf);
}
@@ -656,10 +661,14 @@ bool CoreOpenRom(std::filesystem::path file)
if (l_HasRomOpen)
{
// store ROM path
l_RomPath = file;
// store default ROM settings
CoreStoreCurrentDefaultRomSettings();
// apply rom settings overlay
CoreApplyRomSettingsOverlay();
// update cached rom header and settings entry
CoreUpdateCachedRomHeaderAndSettings(file);
}
return l_HasRomOpen;
@@ -686,6 +695,22 @@ bool CoreGetRomType(CoreRomType& type)
return true;
}
bool CoreGetRomPath(std::filesystem::path& path)
{
std::string error;
if (!l_HasRomOpen)
{
error = "CoreGetRomPath Failed: ";
error += "cannot retrieve ROM path when no ROM has been opened!";
CoreSetError(error);
return false;
}
path = l_RomPath;
return true;
}
bool CoreCloseRom(void)
{
std::string error;
+3
View File
@@ -27,6 +27,9 @@ bool CoreHasRomOpen(void);
// attempts to retrieve the ROM type
bool CoreGetRomType(CoreRomType& type);
// attempts to retrieve ROM path
bool CoreGetRomPath(std::filesystem::path& path);
// closes ROM
bool CoreCloseRom(void);
+43 -1
View File
@@ -25,7 +25,7 @@
// replaces all occurences of any chars in replace with c inside str
static void str_replace_chars(std::string& str, const std::string replace, const char c)
{
for (int i = 0; i < str.size(); i++)
for (uint32_t i = 0; i < str.size(); i++)
{
char str_char = str.at(i);
if (replace.find(str_char) != std::string::npos)
@@ -82,6 +82,48 @@ int CoreGetSaveStateSlot(void)
return slot;
}
bool CoreIncreaseSaveStateSlot(void)
{
std::string error;
int slot;
if (!m64p::Core.IsHooked())
{
return false;
}
slot = CoreGetSaveStateSlot();
if (slot >= 9)
{
error = "CoreIncreaseSaveStateSlot Failed: cannot increase save state slot!";
CoreSetError(error);
return false;
}
return CoreSetSaveStateSlot(slot + 1);
}
bool CoreDecreaseSaveStateSlot(void)
{
std::string error;
int slot;
if (!m64p::Core.IsHooked())
{
return false;
}
slot = CoreGetSaveStateSlot();
if (slot <= 0)
{
error = "CoreDecreaseSaveStateSlot Failed: cannot decrease save state slot!";
CoreSetError(error);
return false;
}
return CoreSetSaveStateSlot(slot - 1);
}
bool CoreGetSaveStatePath(int slot, std::filesystem::path& path)
{
// TODO: this should probably be an API function
+6
View File
@@ -19,6 +19,12 @@ bool CoreSetSaveStateSlot(int slot);
// returns -1 on error
int CoreGetSaveStateSlot(void);
// attempts to increase the save state slot
bool CoreIncreaseSaveStateSlot(void);
// attempts to decrease the save state slot
bool CoreDecreaseSaveStateSlot(void);
// retrieves the file path for
// the save state in the given slot
bool CoreGetSaveStatePath(int slot, std::filesystem::path& path);
+488 -5
View File
@@ -97,7 +97,8 @@ struct l_Setting
std::string Key;
l_DynamicValue DefaultValue;
std::string Description = "";
bool ForceUseSetOnce = false;
bool ForceUseSetOnce = false;
bool ForceUseSetAlways = false;
};
//
@@ -123,6 +124,7 @@ static std::vector<std::string> l_keyList;
#define SETTING_SECTION_M64P "Core"
#define SETTING_SECTION_AUDIO SETTING_SECTION_GUI " - Audio Plugin"
#define SETTING_SECTION_INPUT SETTING_SECTION_GUI " - Input Plugin"
#define SETTING_SECTION_RSP "Rsp-HLE"
// retrieves l_Setting from settingId
static l_Setting get_setting(SettingsID settingId)
@@ -183,6 +185,9 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::GUI_Toolbar:
setting = {SETTING_SECTION_GUI, "Toolbar", true};
break;
case SettingsID::GUI_ToolbarArea:
setting = {SETTING_SECTION_GUI, "ToolbarArea", 0};
break;
case SettingsID::GUI_StatusBar:
setting = {SETTING_SECTION_GUI, "StatusBar", true};
break;
@@ -613,6 +618,27 @@ static l_Setting get_setting(SettingsID settingId)
setting = {SETTING_SECTION_AUDIO, "Synchronize", false};
break;
case SettingsID::RSP_Version:
setting = {SETTING_SECTION_RSP, "Version", 1.0f, "Mupen64Plus RSP HLE Plugin config parameter version number"};
break;
case SettingsID::RSP_Fallback:
setting = {SETTING_SECTION_RSP, "RspFallback", CoreGetPluginDirectory().string() +
#ifdef _WIN32
"\\RSP\\mupen64plus-rsp-parallel.dll",
#else
"/RSP/mupen64plus-rsp-parallel.so",
#endif // _WIN32
"", false, true
};
break;
case SettingsID::RSP_GraphicsHLE:
setting = {SETTING_SECTION_RSP, "DisplayListToGraphicsPlugin", true, "Send display lists to the graphics plugin"};
break;
case SettingsID::RSP_AudioHLE:
setting = {SETTING_SECTION_RSP, "AudioListToAudioPlugin", false, "Send audio lists to the audio plugin"};
break;
case SettingsID::Input_Profiles:
setting = {SETTING_SECTION_INPUT, "Profiles", ""};
break;
@@ -874,6 +900,462 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::Input_AnalogStickRight_ExtraData:
setting = {"", "AnalogStickRight_ExtraData"};
break;
case SettingsID::Input_Hotkey_Shutdown_InputType:
setting = {"", "Hotkey_Shutdown_InputType" };
break;
case SettingsID::Input_Hotkey_Shutdown_Name:
setting = {"", "Hotkey_Shutdown_Name" };
break;
case SettingsID::Input_Hotkey_Shutdown_Data:
setting = {"", "Hotkey_Shutdown_Data" };
break;
case SettingsID::Input_Hotkey_Shutdown_ExtraData:
setting = {"", "Hotkey_Shutdown_ExtraData" };
break;
case SettingsID::Input_Hotkey_Exit_InputType:
setting = {"", "Hotkey_Exit_InputType" };
break;
case SettingsID::Input_Hotkey_Exit_Name:
setting = {"", "Hotkey_Exit_Name" };
break;
case SettingsID::Input_Hotkey_Exit_Data:
setting = {"", "Hotkey_Exit_Data" };
break;
case SettingsID::Input_Hotkey_Exit_ExtraData:
setting = {"", "Hotkey_Exit_ExtraData" };
break;
case SettingsID::Input_Hotkey_SoftReset_InputType:
setting = {"", "Hotkey_SoftReset_InputType" };
break;
case SettingsID::Input_Hotkey_SoftReset_Name:
setting = {"", "Hotkey_SoftReset_Name" };
break;
case SettingsID::Input_Hotkey_SoftReset_Data:
setting = {"", "Hotkey_SoftReset_Data" };
break;
case SettingsID::Input_Hotkey_SoftReset_ExtraData:
setting = {"", "Hotkey_SoftReset_ExtraData" };
break;
case SettingsID::Input_Hotkey_HardReset_InputType:
setting = {"", "Hotkey_HardReset_InputType" };
break;
case SettingsID::Input_Hotkey_HardReset_Name:
setting = {"", "Hotkey_HardReset_Name" };
break;
case SettingsID::Input_Hotkey_HardReset_Data:
setting = {"", "Hotkey_HardReset_Data" };
break;
case SettingsID::Input_Hotkey_HardReset_ExtraData:
setting = {"", "Hotkey_HardReset_ExtraData" };
break;
case SettingsID::Input_Hotkey_Resume_InputType:
setting = {"", "Hotkey_Resume_InputType" };
break;
case SettingsID::Input_Hotkey_Resume_Name:
setting = {"", "Hotkey_Resume_Name" };
break;
case SettingsID::Input_Hotkey_Resume_Data:
setting = {"", "Hotkey_Resume_Data" };
break;
case SettingsID::Input_Hotkey_Resume_ExtraData:
setting = {"", "Hotkey_Resume_ExtraData" };
break;
case SettingsID::Input_Hotkey_Screenshot_InputType:
setting = {"", "Hotkey_Screenshot_InputType" };
break;
case SettingsID::Input_Hotkey_Screenshot_Name:
setting = {"", "Hotkey_Screenshot_Name" };
break;
case SettingsID::Input_Hotkey_Screenshot_Data:
setting = {"", "Hotkey_Screenshot_Data" };
break;
case SettingsID::Input_Hotkey_Screenshot_ExtraData:
setting = {"", "Hotkey_Screenshot_ExtraData" };
break;
case SettingsID::Input_Hotkey_LimitFPS_InputType:
setting = {"", "Hotkey_LimitFPS_InputType" };
break;
case SettingsID::Input_Hotkey_LimitFPS_Name:
setting = {"", "Hotkey_LimitFPS_Name" };
break;
case SettingsID::Input_Hotkey_LimitFPS_Data:
setting = {"", "Hotkey_LimitFPS_Data" };
break;
case SettingsID::Input_Hotkey_LimitFPS_ExtraData:
setting = {"", "Hotkey_LimitFPS_ExtraData" };
break;
case SettingsID::Input_Hotkey_SpeedFactor25_InputType:
setting = {"", "Hotkey_SpeedFactor25_InputType" };
break;
case SettingsID::Input_Hotkey_SpeedFactor25_Name:
setting = {"", "Hotkey_SpeedFactor25_Name" };
break;
case SettingsID::Input_Hotkey_SpeedFactor25_Data:
setting = {"", "Hotkey_SpeedFactor25_Data" };
break;
case SettingsID::Input_Hotkey_SpeedFactor25_ExtraData:
setting = {"", "Hotkey_SpeedFactor25_ExtraData" };
break;
case SettingsID::Input_Hotkey_SpeedFactor50_InputType:
setting = {"", "Hotkey_SpeedFactor50_InputType" };
break;
case SettingsID::Input_Hotkey_SpeedFactor50_Name:
setting = {"", "Hotkey_SpeedFactor50_Name" };
break;
case SettingsID::Input_Hotkey_SpeedFactor50_Data:
setting = {"", "Hotkey_SpeedFactor50_Data" };
break;
case SettingsID::Input_Hotkey_SpeedFactor50_ExtraData:
setting = {"", "Hotkey_SpeedFactor50_ExtraData" };
break;
case SettingsID::Input_Hotkey_SpeedFactor75_InputType:
setting = {"", "Hotkey_SpeedFactor75_InputType" };
break;
case SettingsID::Input_Hotkey_SpeedFactor75_Name:
setting = {"", "Hotkey_SpeedFactor75_Name" };
break;
case SettingsID::Input_Hotkey_SpeedFactor75_Data:
setting = {"", "Hotkey_SpeedFactor75_Data" };
break;
case SettingsID::Input_Hotkey_SpeedFactor75_ExtraData:
setting = {"", "Hotkey_SpeedFactor75_ExtraData" };
break;
case SettingsID::Input_Hotkey_SpeedFactor100_InputType:
setting = {"", "Hotkey_SpeedFactor100_InputType" };
break;
case SettingsID::Input_Hotkey_SpeedFactor100_Name:
setting = {"", "Hotkey_SpeedFactor100_Name" };
break;
case SettingsID::Input_Hotkey_SpeedFactor100_Data:
setting = {"", "Hotkey_SpeedFactor100_Data" };
break;
case SettingsID::Input_Hotkey_SpeedFactor100_ExtraData:
setting = {"", "Hotkey_SpeedFactor100_ExtraData" };
break;
case SettingsID::Input_Hotkey_SpeedFactor125_InputType:
setting = {"", "Hotkey_SpeedFactor125_InputType" };
break;
case SettingsID::Input_Hotkey_SpeedFactor125_Name:
setting = {"", "Hotkey_SpeedFactor125_Name" };
break;
case SettingsID::Input_Hotkey_SpeedFactor125_Data:
setting = {"", "Hotkey_SpeedFactor125_Data" };
break;
case SettingsID::Input_Hotkey_SpeedFactor125_ExtraData:
setting = {"", "Hotkey_SpeedFactor125_ExtraData" };
break;
case SettingsID::Input_Hotkey_SpeedFactor150_InputType:
setting = {"", "Hotkey_SpeedFactor150_InputType" };
break;
case SettingsID::Input_Hotkey_SpeedFactor150_Name:
setting = {"", "Hotkey_SpeedFactor150_Name" };
break;
case SettingsID::Input_Hotkey_SpeedFactor150_Data:
setting = {"", "Hotkey_SpeedFactor150_Data" };
break;
case SettingsID::Input_Hotkey_SpeedFactor150_ExtraData:
setting = {"", "Hotkey_SpeedFactor150_ExtraData" };
break;
case SettingsID::Input_Hotkey_SpeedFactor175_InputType:
setting = {"", "Hotkey_SpeedFactor175_InputType" };
break;
case SettingsID::Input_Hotkey_SpeedFactor175_Name:
setting = {"", "Hotkey_SpeedFactor175_Name" };
break;
case SettingsID::Input_Hotkey_SpeedFactor175_Data:
setting = {"", "Hotkey_SpeedFactor175_Data" };
break;
case SettingsID::Input_Hotkey_SpeedFactor175_ExtraData:
setting = {"", "Hotkey_SpeedFactor175_ExtraData" };
break;
case SettingsID::Input_Hotkey_SpeedFactor200_InputType:
setting = {"", "Hotkey_SpeedFactor200_InputType" };
break;
case SettingsID::Input_Hotkey_SpeedFactor200_Name:
setting = {"", "Hotkey_SpeedFactor200_Name" };
break;
case SettingsID::Input_Hotkey_SpeedFactor200_Data:
setting = {"", "Hotkey_SpeedFactor200_Data" };
break;
case SettingsID::Input_Hotkey_SpeedFactor200_ExtraData:
setting = {"", "Hotkey_SpeedFactor200_ExtraData" };
break;
case SettingsID::Input_Hotkey_SpeedFactor225_InputType:
setting = {"", "Hotkey_SpeedFactor225_InputType" };
break;
case SettingsID::Input_Hotkey_SpeedFactor225_Name:
setting = {"", "Hotkey_SpeedFactor225_Name" };
break;
case SettingsID::Input_Hotkey_SpeedFactor225_Data:
setting = {"", "Hotkey_SpeedFactor225_Data" };
break;
case SettingsID::Input_Hotkey_SpeedFactor225_ExtraData:
setting = {"", "Hotkey_SpeedFactor225_ExtraData" };
break;
case SettingsID::Input_Hotkey_SpeedFactor250_InputType:
setting = {"", "Hotkey_SpeedFactor250_InputType" };
break;
case SettingsID::Input_Hotkey_SpeedFactor250_Name:
setting = {"", "Hotkey_SpeedFactor250_Name" };
break;
case SettingsID::Input_Hotkey_SpeedFactor250_Data:
setting = {"", "Hotkey_SpeedFactor250_Data" };
break;
case SettingsID::Input_Hotkey_SpeedFactor250_ExtraData:
setting = {"", "Hotkey_SpeedFactor250_ExtraData" };
break;
case SettingsID::Input_Hotkey_SpeedFactor275_InputType:
setting = {"", "Hotkey_SpeedFactor275_InputType" };
break;
case SettingsID::Input_Hotkey_SpeedFactor275_Name:
setting = {"", "Hotkey_SpeedFactor275_Name" };
break;
case SettingsID::Input_Hotkey_SpeedFactor275_Data:
setting = {"", "Hotkey_SpeedFactor275_Data" };
break;
case SettingsID::Input_Hotkey_SpeedFactor275_ExtraData:
setting = {"", "Hotkey_SpeedFactor275_ExtraData" };
break;
case SettingsID::Input_Hotkey_SpeedFactor300_InputType:
setting = {"", "Hotkey_SpeedFactor300_InputType" };
break;
case SettingsID::Input_Hotkey_SpeedFactor300_Name:
setting = {"", "Hotkey_SpeedFactor300_Name" };
break;
case SettingsID::Input_Hotkey_SpeedFactor300_Data:
setting = {"", "Hotkey_SpeedFactor300_Data" };
break;
case SettingsID::Input_Hotkey_SpeedFactor300_ExtraData:
setting = {"", "Hotkey_SpeedFactor300_ExtraData" };
break;
case SettingsID::Input_Hotkey_SaveState_InputType:
setting = {"", "Hotkey_SaveState_InputType" };
break;
case SettingsID::Input_Hotkey_SaveState_Name:
setting = {"", "Hotkey_SaveState_Name" };
break;
case SettingsID::Input_Hotkey_SaveState_Data:
setting = {"", "Hotkey_SaveState_Data" };
break;
case SettingsID::Input_Hotkey_SaveState_ExtraData:
setting = {"", "Hotkey_SaveState_ExtraData" };
break;
case SettingsID::Input_Hotkey_LoadState_InputType:
setting = {"", "Hotkey_LoadState_InputType" };
break;
case SettingsID::Input_Hotkey_LoadState_Name:
setting = {"", "Hotkey_LoadState_Name" };
break;
case SettingsID::Input_Hotkey_LoadState_Data:
setting = {"", "Hotkey_LoadState_Data" };
break;
case SettingsID::Input_Hotkey_LoadState_ExtraData:
setting = {"", "Hotkey_LoadState_ExtraData" };
break;
case SettingsID::Input_Hotkey_GSButton_InputType:
setting = {"", "Hotkey_GSButton_InputType" };
break;
case SettingsID::Input_Hotkey_GSButton_Name:
setting = {"", "Hotkey_GSButton_Name" };
break;
case SettingsID::Input_Hotkey_GSButton_Data:
setting = {"", "Hotkey_GSButton_Data" };
break;
case SettingsID::Input_Hotkey_GSButton_ExtraData:
setting = {"", "Hotkey_GSButton_ExtraData" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot0_InputType:
setting = {"", "Hotkey_SaveStateSlot0_InputType" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot0_Name:
setting = {"", "Hotkey_SaveStateSlot0_Name" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot0_Data:
setting = {"", "Hotkey_SaveStateSlot0_Data" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot0_ExtraData:
setting = {"", "Hotkey_SaveStateSlot0_ExtraData" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot1_InputType:
setting = {"", "Hotkey_SaveStateSlot1_InputType" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot1_Name:
setting = {"", "Hotkey_SaveStateSlot1_Name" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot1_Data:
setting = {"", "Hotkey_SaveStateSlot1_Data" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot1_ExtraData:
setting = {"", "Hotkey_SaveStateSlot1_ExtraData" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot2_InputType:
setting = {"", "Hotkey_SaveStateSlot2_InputType" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot2_Name:
setting = {"", "Hotkey_SaveStateSlot2_Name" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot2_Data:
setting = {"", "Hotkey_SaveStateSlot2_Data" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot2_ExtraData:
setting = {"", "Hotkey_SaveStateSlot2_ExtraData" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot3_InputType:
setting = {"", "Hotkey_SaveStateSlot3_InputType" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot3_Name:
setting = {"", "Hotkey_SaveStateSlot3_Name" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot3_Data:
setting = {"", "Hotkey_SaveStateSlot3_Data" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot3_ExtraData:
setting = {"", "Hotkey_SaveStateSlot3_ExtraData" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot4_InputType:
setting = {"", "Hotkey_SaveStateSlot4_InputType" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot4_Name:
setting = {"", "Hotkey_SaveStateSlot4_Name" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot4_Data:
setting = {"", "Hotkey_SaveStateSlot4_Data" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot4_ExtraData:
setting = {"", "Hotkey_SaveStateSlot4_ExtraData" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot5_InputType:
setting = {"", "Hotkey_SaveStateSlot5_InputType" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot5_Name:
setting = {"", "Hotkey_SaveStateSlot5_Name" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot5_Data:
setting = {"", "Hotkey_SaveStateSlot5_Data" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot5_ExtraData:
setting = {"", "Hotkey_SaveStateSlot5_ExtraData" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot6_InputType:
setting = {"", "Hotkey_SaveStateSlot6_InputType" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot6_Name:
setting = {"", "Hotkey_SaveStateSlot6_Name" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot6_Data:
setting = {"", "Hotkey_SaveStateSlot6_Data" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot6_ExtraData:
setting = {"", "Hotkey_SaveStateSlot6_ExtraData" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot7_InputType:
setting = {"", "Hotkey_SaveStateSlot7_InputType" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot7_Name:
setting = {"", "Hotkey_SaveStateSlot7_Name" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot7_Data:
setting = {"", "Hotkey_SaveStateSlot7_Data" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot7_ExtraData:
setting = {"", "Hotkey_SaveStateSlot7_ExtraData" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot8_InputType:
setting = {"", "Hotkey_SaveStateSlot8_InputType" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot8_Name:
setting = {"", "Hotkey_SaveStateSlot8_Name" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot8_Data:
setting = {"", "Hotkey_SaveStateSlot8_Data" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot8_ExtraData:
setting = {"", "Hotkey_SaveStateSlot8_ExtraData" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot9_InputType:
setting = {"", "Hotkey_SaveStateSlot9_InputType" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot9_Name:
setting = {"", "Hotkey_SaveStateSlot9_Name" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot9_Data:
setting = {"", "Hotkey_SaveStateSlot9_Data" };
break;
case SettingsID::Input_Hotkey_SaveStateSlot9_ExtraData:
setting = {"", "Hotkey_SaveStateSlot9_ExtraData" };
break;
case SettingsID::Input_Hotkey_IncreaseSaveStateSlot_InputType:
setting = {"", "Hotkey_IncreaseSaveStateSlot_InputType"};
break;
case SettingsID::Input_Hotkey_IncreaseSaveStateSlot_Name:
setting = {"", "Hotkey_IncreaseSaveStateSlot_Name" };
break;
case SettingsID::Input_Hotkey_IncreaseSaveStateSlot_Data:
setting = {"", "Hotkey_IncreaseSaveStateSlot_Data" };
break;
case SettingsID::Input_Hotkey_IncreaseSaveStateSlot_ExtraData:
setting = {"", "Hotkey_IncreaseSaveStateSlot_ExtraData" };
break;
case SettingsID::Input_Hotkey_DecreaseSaveStateSlot_InputType:
setting = {"", "Hotkey_DecreaseSaveStateSlot_InputType"};
break;
case SettingsID::Input_Hotkey_DecreaseSaveStateSlot_Name:
setting = {"", "Hotkey_DecreaseSaveStateSlot_Name" };
break;
case SettingsID::Input_Hotkey_DecreaseSaveStateSlot_Data:
setting = {"", "Hotkey_DecreaseSaveStateSlot_Data" };
break;
case SettingsID::Input_Hotkey_DecreaseSaveStateSlot_ExtraData:
setting = {"", "Hotkey_DecreaseSaveStateSlot_ExtraData" };
break;
case SettingsID::Input_Hotkey_MemoryPak_InputType:
setting = {"", "Hotkey_MemoryPak_InputType" };
break;
case SettingsID::Input_Hotkey_MemoryPak_Name:
setting = {"", "Hotkey_MemoryPak_Name" };
break;
case SettingsID::Input_Hotkey_MemoryPak_Data:
setting = {"", "Hotkey_MemoryPak_Data" };
break;
case SettingsID::Input_Hotkey_MemoryPak_ExtraData:
setting = {"", "Hotkey_MemoryPak_ExtraData" };
break;
case SettingsID::Input_Hotkey_RumblePak_InputType:
setting = {"", "Hotkey_RumblePak_InputType" };
break;
case SettingsID::Input_Hotkey_RumblePak_Name:
setting = {"", "Hotkey_RumblePak_Name" };
break;
case SettingsID::Input_Hotkey_RumblePak_Data:
setting = {"", "Hotkey_RumblePak_Data" };
break;
case SettingsID::Input_Hotkey_RumblePak_ExtraData:
setting = {"", "Hotkey_RumblePak_ExtraData" };
break;
case SettingsID::Input_Hotkey_NoPak_InputType:
setting = {"", "Hotkey_NoPak_InputType" };
break;
case SettingsID::Input_Hotkey_NoPak_Name:
setting = {"", "Hotkey_NoPak_Name" };
break;
case SettingsID::Input_Hotkey_NoPak_Data:
setting = {"", "Hotkey_NoPak_Data" };
break;
case SettingsID::Input_Hotkey_NoPak_ExtraData:
setting = {"", "Hotkey_NoPak_ExtraData" };
break;
case SettingsID::Input_Hotkey_Fullscreen_InputType:
setting = {"", "Hotkey_Fullscreen_InputType" };
break;
case SettingsID::Input_Hotkey_Fullscreen_Name:
setting = {"", "Hotkey_Fullscreen_Name" };
break;
case SettingsID::Input_Hotkey_Fullscreen_Data:
setting = {"", "Hotkey_Fullscreen_Data" };
break;
case SettingsID::Input_Hotkey_Fullscreen_ExtraData:
setting = {"", "Hotkey_Fullscreen_ExtraData" };
break;
}
return setting;
@@ -1082,7 +1564,7 @@ static bool config_option_default_set(std::string section, std::string key, m64p
static bool int_list_to_string(std::vector<int> intList, std::string& string)
{
for (int i = 0; i < intList.size(); i++)
for (uint32_t i = 0; i < intList.size(); i++)
{
int num = intList.at(i);
string += std::to_string(num);
@@ -1126,7 +1608,7 @@ static bool string_list_to_string(std::vector<std::string> stringList, std::stri
{
std::string error;
for (int i = 0; i < stringList.size(); i++)
for (uint32_t i = 0; i < stringList.size(); i++)
{
std::string str = stringList.at(i);
@@ -1266,11 +1748,12 @@ bool CoreSettingsSetupDefaults(void)
{
case M64TYPE_STRING:
{
if (setting.ForceUseSetOnce && !hasForceUsedSetOnce)
if (setting.ForceUseSetAlways ||
(setting.ForceUseSetOnce && !hasForceUsedSetOnce))
{
ret = config_option_set(setting.Section, setting.Key, M64TYPE_STRING, (void*)setting.DefaultValue.stringValue.c_str());
}
else if (!setting.ForceUseSetOnce)
else if (!setting.ForceUseSetOnce && !setting.ForceUseSetAlways)
{
ret = config_option_default_set(setting.Section, setting.Key, M64TYPE_STRING, (void*)setting.DefaultValue.stringValue.c_str(), setting.Description.c_str());
}
+159
View File
@@ -20,6 +20,7 @@ enum class SettingsID
GUI_OnScreenDisplayOpacity,
GUI_OnScreenDisplayDuration,
GUI_Toolbar,
GUI_ToolbarArea,
GUI_StatusBar,
GUI_Theme,
GUI_IconTheme,
@@ -179,6 +180,12 @@ enum class SettingsID
Audio_Muted,
Audio_Synchronize,
// HLE RSP Plugin Settings
RSP_Version,
RSP_Fallback,
RSP_GraphicsHLE,
RSP_AudioHLE,
// Input Plugin Settings
Input_Profiles,
Input_UseProfile,
@@ -267,6 +274,158 @@ enum class SettingsID
Input_AnalogStickRight_Name,
Input_AnalogStickRight_Data,
Input_AnalogStickRight_ExtraData,
Input_Hotkey_Shutdown_InputType,
Input_Hotkey_Shutdown_Name,
Input_Hotkey_Shutdown_Data,
Input_Hotkey_Shutdown_ExtraData,
Input_Hotkey_Exit_InputType,
Input_Hotkey_Exit_Name,
Input_Hotkey_Exit_Data,
Input_Hotkey_Exit_ExtraData,
Input_Hotkey_SoftReset_InputType,
Input_Hotkey_SoftReset_Name,
Input_Hotkey_SoftReset_Data,
Input_Hotkey_SoftReset_ExtraData,
Input_Hotkey_HardReset_InputType,
Input_Hotkey_HardReset_Name,
Input_Hotkey_HardReset_Data,
Input_Hotkey_HardReset_ExtraData,
Input_Hotkey_Resume_InputType,
Input_Hotkey_Resume_Name,
Input_Hotkey_Resume_Data,
Input_Hotkey_Resume_ExtraData,
Input_Hotkey_Screenshot_InputType,
Input_Hotkey_Screenshot_Name,
Input_Hotkey_Screenshot_Data,
Input_Hotkey_Screenshot_ExtraData,
Input_Hotkey_LimitFPS_InputType,
Input_Hotkey_LimitFPS_Name,
Input_Hotkey_LimitFPS_Data,
Input_Hotkey_LimitFPS_ExtraData,
Input_Hotkey_SpeedFactor25_InputType,
Input_Hotkey_SpeedFactor25_Name,
Input_Hotkey_SpeedFactor25_Data,
Input_Hotkey_SpeedFactor25_ExtraData,
Input_Hotkey_SpeedFactor50_InputType,
Input_Hotkey_SpeedFactor50_Name,
Input_Hotkey_SpeedFactor50_Data,
Input_Hotkey_SpeedFactor50_ExtraData,
Input_Hotkey_SpeedFactor75_InputType,
Input_Hotkey_SpeedFactor75_Name,
Input_Hotkey_SpeedFactor75_Data,
Input_Hotkey_SpeedFactor75_ExtraData,
Input_Hotkey_SpeedFactor100_InputType,
Input_Hotkey_SpeedFactor100_Name,
Input_Hotkey_SpeedFactor100_Data,
Input_Hotkey_SpeedFactor100_ExtraData,
Input_Hotkey_SpeedFactor125_InputType,
Input_Hotkey_SpeedFactor125_Name,
Input_Hotkey_SpeedFactor125_Data,
Input_Hotkey_SpeedFactor125_ExtraData,
Input_Hotkey_SpeedFactor150_InputType,
Input_Hotkey_SpeedFactor150_Name,
Input_Hotkey_SpeedFactor150_Data,
Input_Hotkey_SpeedFactor150_ExtraData,
Input_Hotkey_SpeedFactor175_InputType,
Input_Hotkey_SpeedFactor175_Name,
Input_Hotkey_SpeedFactor175_Data,
Input_Hotkey_SpeedFactor175_ExtraData,
Input_Hotkey_SpeedFactor200_InputType,
Input_Hotkey_SpeedFactor200_Name,
Input_Hotkey_SpeedFactor200_Data,
Input_Hotkey_SpeedFactor200_ExtraData,
Input_Hotkey_SpeedFactor225_InputType,
Input_Hotkey_SpeedFactor225_Name,
Input_Hotkey_SpeedFactor225_Data,
Input_Hotkey_SpeedFactor225_ExtraData,
Input_Hotkey_SpeedFactor250_InputType,
Input_Hotkey_SpeedFactor250_Name,
Input_Hotkey_SpeedFactor250_Data,
Input_Hotkey_SpeedFactor250_ExtraData,
Input_Hotkey_SpeedFactor275_InputType,
Input_Hotkey_SpeedFactor275_Name,
Input_Hotkey_SpeedFactor275_Data,
Input_Hotkey_SpeedFactor275_ExtraData,
Input_Hotkey_SpeedFactor300_InputType,
Input_Hotkey_SpeedFactor300_Name,
Input_Hotkey_SpeedFactor300_Data,
Input_Hotkey_SpeedFactor300_ExtraData,
Input_Hotkey_SaveState_InputType,
Input_Hotkey_SaveState_Name,
Input_Hotkey_SaveState_Data,
Input_Hotkey_SaveState_ExtraData,
Input_Hotkey_LoadState_InputType,
Input_Hotkey_LoadState_Name,
Input_Hotkey_LoadState_Data,
Input_Hotkey_LoadState_ExtraData,
Input_Hotkey_GSButton_InputType,
Input_Hotkey_GSButton_Name,
Input_Hotkey_GSButton_Data,
Input_Hotkey_GSButton_ExtraData,
Input_Hotkey_SaveStateSlot0_InputType,
Input_Hotkey_SaveStateSlot0_Name,
Input_Hotkey_SaveStateSlot0_Data,
Input_Hotkey_SaveStateSlot0_ExtraData,
Input_Hotkey_SaveStateSlot1_InputType,
Input_Hotkey_SaveStateSlot1_Name,
Input_Hotkey_SaveStateSlot1_Data,
Input_Hotkey_SaveStateSlot1_ExtraData,
Input_Hotkey_SaveStateSlot2_InputType,
Input_Hotkey_SaveStateSlot2_Name,
Input_Hotkey_SaveStateSlot2_Data,
Input_Hotkey_SaveStateSlot2_ExtraData,
Input_Hotkey_SaveStateSlot3_InputType,
Input_Hotkey_SaveStateSlot3_Name,
Input_Hotkey_SaveStateSlot3_Data,
Input_Hotkey_SaveStateSlot3_ExtraData,
Input_Hotkey_SaveStateSlot4_InputType,
Input_Hotkey_SaveStateSlot4_Name,
Input_Hotkey_SaveStateSlot4_Data,
Input_Hotkey_SaveStateSlot4_ExtraData,
Input_Hotkey_SaveStateSlot5_InputType,
Input_Hotkey_SaveStateSlot5_Name,
Input_Hotkey_SaveStateSlot5_Data,
Input_Hotkey_SaveStateSlot5_ExtraData,
Input_Hotkey_SaveStateSlot6_InputType,
Input_Hotkey_SaveStateSlot6_Name,
Input_Hotkey_SaveStateSlot6_Data,
Input_Hotkey_SaveStateSlot6_ExtraData,
Input_Hotkey_SaveStateSlot7_InputType,
Input_Hotkey_SaveStateSlot7_Name,
Input_Hotkey_SaveStateSlot7_Data,
Input_Hotkey_SaveStateSlot7_ExtraData,
Input_Hotkey_SaveStateSlot8_InputType,
Input_Hotkey_SaveStateSlot8_Name,
Input_Hotkey_SaveStateSlot8_Data,
Input_Hotkey_SaveStateSlot8_ExtraData,
Input_Hotkey_SaveStateSlot9_InputType,
Input_Hotkey_SaveStateSlot9_Name,
Input_Hotkey_SaveStateSlot9_Data,
Input_Hotkey_SaveStateSlot9_ExtraData,
Input_Hotkey_IncreaseSaveStateSlot_InputType,
Input_Hotkey_IncreaseSaveStateSlot_Name,
Input_Hotkey_IncreaseSaveStateSlot_Data,
Input_Hotkey_IncreaseSaveStateSlot_ExtraData,
Input_Hotkey_DecreaseSaveStateSlot_InputType,
Input_Hotkey_DecreaseSaveStateSlot_Name,
Input_Hotkey_DecreaseSaveStateSlot_Data,
Input_Hotkey_DecreaseSaveStateSlot_ExtraData,
Input_Hotkey_MemoryPak_InputType,
Input_Hotkey_MemoryPak_Name,
Input_Hotkey_MemoryPak_Data,
Input_Hotkey_MemoryPak_ExtraData,
Input_Hotkey_RumblePak_InputType,
Input_Hotkey_RumblePak_Name,
Input_Hotkey_RumblePak_Data,
Input_Hotkey_RumblePak_ExtraData,
Input_Hotkey_NoPak_InputType,
Input_Hotkey_NoPak_Name,
Input_Hotkey_NoPak_Data,
Input_Hotkey_NoPak_ExtraData,
Input_Hotkey_Fullscreen_InputType,
Input_Hotkey_Fullscreen_Name,
Input_Hotkey_Fullscreen_Data,
Input_Hotkey_Fullscreen_ExtraData,
Invalid
};
+2 -2
View File
@@ -33,7 +33,7 @@ bool CoreUnzip(std::filesystem::path file, std::filesystem::path path)
unz_global_info zipInfo;
std::ofstream outputStream;
char* read_buffer = (char*)malloc(UNZIP_READ_SIZE);
size_t bytes_read = 0;
int bytes_read = 0;
if (read_buffer == nullptr)
{
@@ -60,7 +60,7 @@ bool CoreUnzip(std::filesystem::path file, std::filesystem::path path)
}
for (int i = 0; i < zipInfo.number_entry; i++)
for (uint64_t i = 0; i < zipInfo.number_entry; i++)
{
unz_file_info fileInfo;
char fileName[PATH_MAX];
+12
View File
@@ -17,21 +17,33 @@ set(RMG_INPUT_SOURCES
UserInterface/Widget/ControllerWidget.ui
UserInterface/Widget/ControllerWidget.cpp
UserInterface/Widget/ControllerImageWidget.cpp
UserInterface/Widget/HotkeyButton.cpp
UserInterface/Widget/MappingButton.cpp
UserInterface/Widget/AddMappingButton.cpp
UserInterface/Widget/RemoveMappingButton.cpp
UserInterface/EventFilter.cpp
UserInterface/OptionsDialog.ui
UserInterface/OptionsDialog.cpp
UserInterface/HotkeysDialog.ui
UserInterface/HotkeysDialog.cpp
UserInterface/MainDialog.ui
UserInterface/MainDialog.cpp
UserInterface/UIResources.qrc
Utilities/QtKeyToSdl2Key.cpp
Utilities/InputDevice.cpp
Thread/SDLThread.cpp
Thread/HotkeysThread.cpp
main.cpp
)
if (VRU)
list(APPEND RMG_INPUT_SOURCES
VRU.cpp
VRUwords.cpp
)
add_definitions(-DVRU)
endif(VRU)
add_library(RMG-Input SHARED ${RMG_INPUT_SOURCES})
target_link_libraries(RMG-Input RMG-Core ${SDL2_LIBRARIES})
+65
View File
@@ -0,0 +1,65 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "HotkeysThread.hpp"
#include <RMG-Core/Core.hpp>
using namespace Thread;
HotkeysThread::HotkeysThread(std::function<void(int)> checkHotkeysFunc, QObject *parent) : QThread(parent)
{
this->checkHotkeysFunc = checkHotkeysFunc;
}
HotkeysThread::~HotkeysThread()
{
if (this->isRunning())
{
this->StopLoop();
}
}
void HotkeysThread::SetState(HotkeysThreadState state)
{
this->state = state;
}
void HotkeysThread::StopLoop(void)
{
this->keepLoopRunning = false;
while (this->isRunning())
{
// wait until we're not running anymore
}
}
void HotkeysThread::run(void)
{
while (this->keepLoopRunning)
{
// sleep for 300ms when no ROM is opened
if (this->state == HotkeysThreadState::RomClosed)
{
QThread::msleep(300);
continue;
}
if (CoreIsEmulationPaused())
{
for (int i = 0; i < 4; i++)
{
this->checkHotkeysFunc(i);
}
}
// sleep for 100ms
QThread::msleep(100);
}
}
+44
View File
@@ -0,0 +1,44 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef HOTKEYSTHREAD_HPP
#define HOTKEYSTHREAD_HPP
#include <QThread>
enum class HotkeysThreadState
{
RomOpened,
RomClosed,
};
namespace Thread
{
class HotkeysThread : public QThread
{
Q_OBJECT
public:
HotkeysThread(std::function<void(int)> checkHotkeysFunc, QObject *parent);
~HotkeysThread(void);
void run(void) override;
void SetState(HotkeysThreadState state);
void StopLoop(void);
private:
bool keepLoopRunning = true;
std::function<void(int)> checkHotkeysFunc;
HotkeysThreadState state = HotkeysThreadState::RomClosed;
};
} // namespace Thread
#endif // HOTKEYSTHREAD_HPP
@@ -0,0 +1,360 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "HotkeysDialog.hpp"
#include "common.hpp"
#include <RMG-Core/Core.hpp>
#include <iostream>
using namespace UserInterface;
HotkeysDialog::HotkeysDialog(QWidget* parent, QList<HotkeySettingMapping> hotkeySettingMappings,
bool isGameController, SDL_JoystickID joystickId,
bool filterEvents, bool removeDuplicates) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
{
this->setupUi(this);
this->currentJoystickId = joystickId;
this->isCurrentJoystickGameController = isGameController;
this->filterEventsForButtons = filterEvents;
this->removeDuplicates = removeDuplicates;
this->hotkeySettingMappings.append(
{
{ this->shutdownKeyButton, SettingsID::Input_Hotkey_Shutdown_InputType, SettingsID::Input_Hotkey_Shutdown_Name, SettingsID::Input_Hotkey_Shutdown_Data, SettingsID::Input_Hotkey_Shutdown_ExtraData },
{ this->exitKeyButton, SettingsID::Input_Hotkey_Exit_InputType, SettingsID::Input_Hotkey_Exit_Name, SettingsID::Input_Hotkey_Exit_Data, SettingsID::Input_Hotkey_Exit_ExtraData },
{ this->softResetKeyButton, SettingsID::Input_Hotkey_SoftReset_InputType, SettingsID::Input_Hotkey_SoftReset_Name, SettingsID::Input_Hotkey_SoftReset_Data, SettingsID::Input_Hotkey_SoftReset_ExtraData },
{ this->hardResetKeyButton, SettingsID::Input_Hotkey_HardReset_InputType, SettingsID::Input_Hotkey_HardReset_Name, SettingsID::Input_Hotkey_HardReset_Data, SettingsID::Input_Hotkey_HardReset_ExtraData },
{ this->pauseKeyButton, SettingsID::Input_Hotkey_Resume_InputType, SettingsID::Input_Hotkey_Resume_Name, SettingsID::Input_Hotkey_Resume_Data, SettingsID::Input_Hotkey_Resume_ExtraData },
{ this->generateBitmapKeyButton, SettingsID::Input_Hotkey_Screenshot_InputType, SettingsID::Input_Hotkey_Screenshot_Name, SettingsID::Input_Hotkey_Screenshot_Data, SettingsID::Input_Hotkey_Screenshot_ExtraData },
{ this->limitFPSKeyButton, SettingsID::Input_Hotkey_LimitFPS_InputType, SettingsID::Input_Hotkey_LimitFPS_Name, SettingsID::Input_Hotkey_LimitFPS_Data, SettingsID::Input_Hotkey_LimitFPS_ExtraData },
{ this->speedFactor25KeyButton, SettingsID::Input_Hotkey_SpeedFactor25_InputType, SettingsID::Input_Hotkey_SpeedFactor25_Name, SettingsID::Input_Hotkey_SpeedFactor25_Data, SettingsID::Input_Hotkey_SpeedFactor25_ExtraData },
{ this->speedFactor50KeyButton, SettingsID::Input_Hotkey_SpeedFactor50_InputType, SettingsID::Input_Hotkey_SpeedFactor50_Name, SettingsID::Input_Hotkey_SpeedFactor50_Data, SettingsID::Input_Hotkey_SpeedFactor50_ExtraData },
{ this->speedFactor75KeyButton, SettingsID::Input_Hotkey_SpeedFactor75_InputType, SettingsID::Input_Hotkey_SpeedFactor75_Name, SettingsID::Input_Hotkey_SpeedFactor75_Data, SettingsID::Input_Hotkey_SpeedFactor75_ExtraData },
{ this->speedFactor100KeyButton, SettingsID::Input_Hotkey_SpeedFactor100_InputType, SettingsID::Input_Hotkey_SpeedFactor100_Name, SettingsID::Input_Hotkey_SpeedFactor100_Data, SettingsID::Input_Hotkey_SpeedFactor100_ExtraData },
{ this->speedFactor125KeyButton, SettingsID::Input_Hotkey_SpeedFactor125_InputType, SettingsID::Input_Hotkey_SpeedFactor125_Name, SettingsID::Input_Hotkey_SpeedFactor125_Data, SettingsID::Input_Hotkey_SpeedFactor125_ExtraData },
{ this->speedFactor150KeyButton, SettingsID::Input_Hotkey_SpeedFactor150_InputType, SettingsID::Input_Hotkey_SpeedFactor150_Name, SettingsID::Input_Hotkey_SpeedFactor150_Data, SettingsID::Input_Hotkey_SpeedFactor150_ExtraData },
{ this->speedFactor175KeyButton, SettingsID::Input_Hotkey_SpeedFactor175_InputType, SettingsID::Input_Hotkey_SpeedFactor175_Name, SettingsID::Input_Hotkey_SpeedFactor175_Data, SettingsID::Input_Hotkey_SpeedFactor175_ExtraData },
{ this->speedFactor200KeyButton, SettingsID::Input_Hotkey_SpeedFactor200_InputType, SettingsID::Input_Hotkey_SpeedFactor200_Name, SettingsID::Input_Hotkey_SpeedFactor200_Data, SettingsID::Input_Hotkey_SpeedFactor200_ExtraData },
{ this->speedFactor225KeyButton, SettingsID::Input_Hotkey_SpeedFactor225_InputType, SettingsID::Input_Hotkey_SpeedFactor225_Name, SettingsID::Input_Hotkey_SpeedFactor225_Data, SettingsID::Input_Hotkey_SpeedFactor225_ExtraData },
{ this->speedFactor250KeyButton, SettingsID::Input_Hotkey_SpeedFactor250_InputType, SettingsID::Input_Hotkey_SpeedFactor250_Name, SettingsID::Input_Hotkey_SpeedFactor250_Data, SettingsID::Input_Hotkey_SpeedFactor250_ExtraData },
{ this->speedFactor275KeyButton, SettingsID::Input_Hotkey_SpeedFactor275_InputType, SettingsID::Input_Hotkey_SpeedFactor275_Name, SettingsID::Input_Hotkey_SpeedFactor275_Data, SettingsID::Input_Hotkey_SpeedFactor275_ExtraData },
{ this->speedFactor300KeyButton, SettingsID::Input_Hotkey_SpeedFactor300_InputType, SettingsID::Input_Hotkey_SpeedFactor300_Name, SettingsID::Input_Hotkey_SpeedFactor300_Data, SettingsID::Input_Hotkey_SpeedFactor300_ExtraData },
{ this->saveStateKeyButton, SettingsID::Input_Hotkey_SaveState_InputType, SettingsID::Input_Hotkey_SaveState_Name, SettingsID::Input_Hotkey_SaveState_Data, SettingsID::Input_Hotkey_SaveState_ExtraData },
{ this->loadStateKeyButton, SettingsID::Input_Hotkey_LoadState_InputType, SettingsID::Input_Hotkey_LoadState_Name, SettingsID::Input_Hotkey_LoadState_Data, SettingsID::Input_Hotkey_LoadState_ExtraData },
{ this->gsButtonKeyButton, SettingsID::Input_Hotkey_GSButton_InputType, SettingsID::Input_Hotkey_GSButton_Name, SettingsID::Input_Hotkey_GSButton_Data, SettingsID::Input_Hotkey_GSButton_ExtraData },
{ this->saveState0KeyButton, SettingsID::Input_Hotkey_SaveStateSlot0_InputType, SettingsID::Input_Hotkey_SaveStateSlot0_Name, SettingsID::Input_Hotkey_SaveStateSlot0_Data, SettingsID::Input_Hotkey_SaveStateSlot0_ExtraData },
{ this->saveState1KeyButton, SettingsID::Input_Hotkey_SaveStateSlot1_InputType, SettingsID::Input_Hotkey_SaveStateSlot1_Name, SettingsID::Input_Hotkey_SaveStateSlot1_Data, SettingsID::Input_Hotkey_SaveStateSlot1_ExtraData },
{ this->saveState2KeyButton, SettingsID::Input_Hotkey_SaveStateSlot2_InputType, SettingsID::Input_Hotkey_SaveStateSlot2_Name, SettingsID::Input_Hotkey_SaveStateSlot2_Data, SettingsID::Input_Hotkey_SaveStateSlot2_ExtraData },
{ this->saveState3KeyButton, SettingsID::Input_Hotkey_SaveStateSlot3_InputType, SettingsID::Input_Hotkey_SaveStateSlot3_Name, SettingsID::Input_Hotkey_SaveStateSlot3_Data, SettingsID::Input_Hotkey_SaveStateSlot3_ExtraData },
{ this->saveState4KeyButton, SettingsID::Input_Hotkey_SaveStateSlot4_InputType, SettingsID::Input_Hotkey_SaveStateSlot4_Name, SettingsID::Input_Hotkey_SaveStateSlot4_Data, SettingsID::Input_Hotkey_SaveStateSlot4_ExtraData },
{ this->saveState5KeyButton, SettingsID::Input_Hotkey_SaveStateSlot5_InputType, SettingsID::Input_Hotkey_SaveStateSlot5_Name, SettingsID::Input_Hotkey_SaveStateSlot5_Data, SettingsID::Input_Hotkey_SaveStateSlot5_ExtraData },
{ this->saveState6KeyButton, SettingsID::Input_Hotkey_SaveStateSlot6_InputType, SettingsID::Input_Hotkey_SaveStateSlot6_Name, SettingsID::Input_Hotkey_SaveStateSlot6_Data, SettingsID::Input_Hotkey_SaveStateSlot6_ExtraData },
{ this->saveState7KeyButton, SettingsID::Input_Hotkey_SaveStateSlot7_InputType, SettingsID::Input_Hotkey_SaveStateSlot7_Name, SettingsID::Input_Hotkey_SaveStateSlot7_Data, SettingsID::Input_Hotkey_SaveStateSlot7_ExtraData },
{ this->saveState8KeyButton, SettingsID::Input_Hotkey_SaveStateSlot8_InputType, SettingsID::Input_Hotkey_SaveStateSlot8_Name, SettingsID::Input_Hotkey_SaveStateSlot8_Data, SettingsID::Input_Hotkey_SaveStateSlot8_ExtraData },
{ this->saveState9KeyButton, SettingsID::Input_Hotkey_SaveStateSlot9_InputType, SettingsID::Input_Hotkey_SaveStateSlot9_Name, SettingsID::Input_Hotkey_SaveStateSlot9_Data, SettingsID::Input_Hotkey_SaveStateSlot9_ExtraData },
{ this->increaseSaveSlotKeyButton, SettingsID::Input_Hotkey_IncreaseSaveStateSlot_InputType, SettingsID::Input_Hotkey_IncreaseSaveStateSlot_Name, SettingsID::Input_Hotkey_IncreaseSaveStateSlot_Data, SettingsID::Input_Hotkey_IncreaseSaveStateSlot_ExtraData },
{ this->decreaseSaveSlotKeyButton, SettingsID::Input_Hotkey_DecreaseSaveStateSlot_InputType, SettingsID::Input_Hotkey_DecreaseSaveStateSlot_Name, SettingsID::Input_Hotkey_DecreaseSaveStateSlot_Data, SettingsID::Input_Hotkey_DecreaseSaveStateSlot_ExtraData },
{ this->memPakKeyButton, SettingsID::Input_Hotkey_MemoryPak_InputType, SettingsID::Input_Hotkey_MemoryPak_Name, SettingsID::Input_Hotkey_MemoryPak_Data, SettingsID::Input_Hotkey_MemoryPak_ExtraData },
{ this->rumblePakKeyButton, SettingsID::Input_Hotkey_RumblePak_InputType, SettingsID::Input_Hotkey_RumblePak_Name, SettingsID::Input_Hotkey_RumblePak_Data, SettingsID::Input_Hotkey_RumblePak_ExtraData },
{ this->noPakKeyButton, SettingsID::Input_Hotkey_NoPak_InputType, SettingsID::Input_Hotkey_NoPak_Name, SettingsID::Input_Hotkey_NoPak_Data, SettingsID::Input_Hotkey_NoPak_ExtraData },
{ this->fullscreenKeyButton, SettingsID::Input_Hotkey_Fullscreen_InputType, SettingsID::Input_Hotkey_Fullscreen_Name, SettingsID::Input_Hotkey_Fullscreen_Data, SettingsID::Input_Hotkey_Fullscreen_ExtraData },
});
// initialize buttons
for (auto& mapping : this->hotkeySettingMappings)
{
mapping.button->Initialize(this);
}
// initialize icons
this->infoIconLabel->setPixmap(QIcon::fromTheme("information-line").pixmap(16, 16));
this->infoIconLabel_2->setPixmap(QIcon::fromTheme("information-line").pixmap(16, 16));
this->infoIconLabel_3->setPixmap(QIcon::fromTheme("information-line").pixmap(16, 16));
this->infoIconLabel_4->setPixmap(QIcon::fromTheme("information-line").pixmap(16, 16));
this->infoIconLabel_5->setPixmap(QIcon::fromTheme("information-line").pixmap(16, 16));
// load settings from given mappings
for (int i = 0; i < hotkeySettingMappings.size(); i++)
{
auto& buttonMapping = this->hotkeySettingMappings.at(i);
auto& givenMapping = hotkeySettingMappings.at(i);
for (int y = 0; y < givenMapping.inputTypes.size(); y++)
{
buttonMapping.button->AddInputData(
(InputType)givenMapping.inputTypes.at(y),
givenMapping.inputData.at(y),
givenMapping.extraInputData.at(y),
QString::fromStdString(givenMapping.inputText.at(y))
);
}
buttonMapping.button->FinishState();
}
}
void HotkeysDialog::on_MainDialog_SdlEvent(SDL_Event* event)
{
switch (event->type)
{
default:
break;
case SDL_CONTROLLERBUTTONDOWN:
case SDL_JOYBUTTONDOWN:
{
SDL_JoystickID joystickId = -1;
InputType inputType = InputType::Invalid;
int sdlButton = 0;
QString sdlButtonName;
if (event->type == SDL_CONTROLLERBUTTONDOWN)
{ // gamepad button
if (!this->isCurrentJoystickGameController &&
this->filterEventsForButtons)
{
return;
}
joystickId = event->cbutton.which;
inputType = InputType::GamepadButton;
sdlButton = event->cbutton.button;
sdlButtonName = SDL_GameControllerGetStringForButton((SDL_GameControllerButton)sdlButton);
}
else
{ // joystick button
if (this->isCurrentJoystickGameController &&
this->filterEventsForButtons)
{
return;
}
joystickId = event->jbutton.which;
inputType = InputType::JoystickButton;
sdlButton = event->jbutton.button;
sdlButtonName = "button " + QString::number(sdlButton);
}
// make sure we have the right joystick
if (joystickId != this->currentJoystickId)
{
break;
}
if (this->currentHotkeyButton != nullptr)
{
this->currentHotkeyButton->AddInputData(
inputType,
sdlButton,
0,
sdlButtonName
);
}
} break;
case SDL_CONTROLLERBUTTONUP:
case SDL_JOYBUTTONUP:
{
SDL_JoystickID joystickId = -1;
if (event->type == SDL_CONTROLLERBUTTONUP)
{ // gamepad button
if (!this->isCurrentJoystickGameController &&
this->filterEventsForButtons)
{
return;
}
joystickId = event->cbutton.which;
}
else
{ // joystick button
if (this->isCurrentJoystickGameController &&
this->filterEventsForButtons)
{
return;
}
joystickId = event->jbutton.which;
}
// make sure we have the right joystick
if (joystickId != this->currentJoystickId)
{
break;
}
if (this->currentHotkeyButton != nullptr)
{
this->currentHotkeyButton->StopTimer();
this->currentHotkeyButton->FinishState();
this->currentHotkeyButton->clearFocus();
this->currentHotkeyButton = nullptr;
}
} break;
case SDL_CONTROLLERAXISMOTION:
case SDL_JOYAXISMOTION:
{ // gamepad & joystick axis
SDL_JoystickID joystickId = -1;
InputType inputType = InputType::Invalid;
int sdlAxis = 0;
int sdlAxisValue = 0;
QString sdlAxisName;
if (event->type == SDL_CONTROLLERAXISMOTION)
{ // gamepad axis
if (!this->isCurrentJoystickGameController &&
this->filterEventsForButtons)
{
return;
}
joystickId = event->caxis.which;
inputType = InputType::GamepadAxis;
sdlAxis = event->caxis.axis;
sdlAxisValue = event->caxis.value;
sdlAxisName = SDL_GameControllerGetStringForAxis((SDL_GameControllerAxis)sdlAxis);
sdlAxisName += sdlAxisValue > 0 ? "+" : "-";
}
else
{ // joystick axis
if (this->isCurrentJoystickGameController &&
this->filterEventsForButtons)
{
return;
}
joystickId = event->jaxis.which;
inputType = InputType::JoystickAxis;
sdlAxis = event->jaxis.axis;
sdlAxisValue = event->jaxis.value;
sdlAxisName = "axis " + QString::number(sdlAxis);
sdlAxisName += sdlAxisValue > 0 ? "+" : "-";
}
// make sure the user presses the axis
// more than 50%, otherwise we might detect
// an accidental axis movement (due to i.e deadzone)
const bool sdlAxisButtonPressed = (abs(sdlAxisValue) >= (SDL_AXIS_PEAK / 2));
const int sdlAxisDirection = (sdlAxisValue > 0 ? 1 : 0);
// make sure we have the right joystick
if (joystickId != this->currentJoystickId)
{
break;
}
if (this->currentHotkeyButton != nullptr)
{
// when the axis has been pressed for more
// than 50%, add it to the hotkey, if it isn't
// but if the current hotkey button contains
// that axis, then we can stop watching
// for input
if (sdlAxisButtonPressed)
{
this->currentHotkeyButton->AddInputData(
inputType,
sdlAxis,
sdlAxisDirection,
sdlAxisName
);
}
else if (this->currentHotkeyButton->HasInputData(inputType, sdlAxis, sdlAxisDirection))
{
this->currentHotkeyButton->StopTimer();
this->currentHotkeyButton->FinishState();
this->currentHotkeyButton->clearFocus();
this->currentHotkeyButton = nullptr;
}
}
} break;
}
}
void HotkeysDialog::on_HotkeyButton_Released(Widget::HotkeyButton* button)
{
if (this->currentHotkeyButton != nullptr)
{
this->currentHotkeyButton->StopTimer();
this->currentHotkeyButton->RestoreState();
}
this->currentHotkeyButton = button;
button->SaveState();
button->StartTimer();
}
void HotkeysDialog::on_HotkeyButton_TimerFinished(Widget::HotkeyButton* button)
{
if (this->currentHotkeyButton == button)
{
this->currentHotkeyButton = nullptr;
}
button->RestoreState();
button->clearFocus();
}
void HotkeysDialog::on_HotkeyButton_StateFinished(Widget::HotkeyButton* button)
{
// do nothing when the user
// doesn't want us to remove
// duplicates
if (!this->removeDuplicates)
{
return;
}
std::vector<int> inputType = button->GetInputType();
std::vector<int> inputData = button->GetInputData();
std::vector<int> extraInputData = button->GetExtraInputData();
for (auto& mapping : this->hotkeySettingMappings)
{
// skip ourselves
if (mapping.button == button)
{
continue;
}
if (inputType == mapping.button->GetInputType() &&
inputData == mapping.button->GetInputData() &&
extraInputData == mapping.button->GetExtraInputData())
{
mapping.button->Clear();
}
}
}
QList<HotkeySettingMapping> HotkeysDialog::GetSettingMappings()
{
QList<HotkeySettingMapping> mappings;
for (auto& mapping : this->hotkeySettingMappings)
{
mappings.append({
mapping.button->GetInputType(),
mapping.button->GetInputData(),
mapping.button->GetExtraInputData(),
mapping.button->GetInputText(),
mapping.inputTypeSettingsId,
mapping.nameSettingsId,
mapping.dataSettingsId,
mapping.extraDataSettingsId
});
}
return mappings;
}
@@ -0,0 +1,77 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef HOTKEYSDIALOG_HPP
#define HOTKEYSDIALOG_HPP
#include <QDialog>
#include <string>
#include <SDL.h>
#include <RMG-Core/Core.hpp>
#include "ui_HotkeysDialog.h"
namespace UserInterface
{
struct HotkeySettingMapping
{
std::vector<int> inputTypes;
std::vector<int> inputData;
std::vector<int> extraInputData;
std::vector<std::string> inputText;
SettingsID inputTypeSettingsId;
SettingsID nameSettingsId;
SettingsID dataSettingsId;
SettingsID extraDataSettingsId;
};
class HotkeysDialog : public QDialog, private Ui::HotkeysDialog
{
Q_OBJECT
private:
SDL_JoystickID currentJoystickId = -1;
bool isCurrentJoystickGameController = false;
bool filterEventsForButtons = false;
bool removeDuplicates = false;
struct hotkeySettingMapping
{
Widget::HotkeyButton* button;
SettingsID inputTypeSettingsId;
SettingsID nameSettingsId;
SettingsID dataSettingsId;
SettingsID extraDataSettingsId;
};
QList<hotkeySettingMapping> hotkeySettingMappings;
Widget::HotkeyButton* currentHotkeyButton = nullptr;
public:
HotkeysDialog(QWidget *parent, QList<HotkeySettingMapping> hotkeySettingMappings,
bool isGameController, SDL_JoystickID joystickId,
bool filterEvents, bool removeDuplicates);
QList<HotkeySettingMapping> GetSettingMappings();
public slots:
void on_MainDialog_SdlEvent(SDL_Event* event);
void on_HotkeyButton_Released(Widget::HotkeyButton* button);
void on_HotkeyButton_TimerFinished(Widget::HotkeyButton* button);
void on_HotkeyButton_StateFinished(Widget::HotkeyButton* button);
};
}
#endif // HOTKEYSDIALOG_HPP
File diff suppressed because it is too large Load Diff
+12 -3
View File
@@ -59,9 +59,18 @@ MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread, bool romCo
// always add keyboard device
for (auto& controllerWidget : this->controllerWidgets)
{
controllerWidget->AddInputDevice("None", (int)InputDeviceType::None);
controllerWidget->AddInputDevice("Automatic", (int)InputDeviceType::Automatic);
controllerWidget->AddInputDevice("Keyboard", (int)InputDeviceType::Keyboard);
#ifdef VRU
// both games which support the VRU,
// require the VRU to be in port #4,
// so we only have to expose it there
if (controllerWidget == this->controllerWidgets.last())
{
controllerWidget->AddInputDevice("Voice Recognition Unit", (int)InputDeviceType::EmulateVRU);
}
#endif // VRU
controllerWidget->AddInputDevice("None", (int)InputDeviceType::None);
controllerWidget->AddInputDevice("Automatic", (int)InputDeviceType::Automatic);
controllerWidget->AddInputDevice("Keyboard", (int)InputDeviceType::Keyboard);
controllerWidget->SetInitialized(true);
}
@@ -33,11 +33,6 @@ OptionsDialog::OptionsDialog(QWidget* parent, OptionsDialogSettings settings) :
}
}
bool OptionsDialog::HasSaved()
{
return this->hasSaved;
}
OptionsDialogSettings OptionsDialog::GetSettings()
{
return this->settings;
@@ -72,24 +67,16 @@ void OptionsDialog::hideEmulationInfoText(void)
}
}
void OptionsDialog::on_buttonBox_clicked(QAbstractButton *button)
void OptionsDialog::accept()
{
this->settings.ControllerPak = this->controllerPakComboBox->currentIndex();
this->settings.GameboyRom = this->gameboyRomLineEdit->text().toStdString();
this->settings.GameboySave = this->gameboySaveLineEdit->text().toStdString();
this->settings.RemoveDuplicateMappings = this->removeDuplicateMappingsCheckbox->isChecked();
this->settings.FilterEventsForButtons = this->filterEventsForButtonsCheckBox->isChecked();
this->settings.FilterEventsForAxis = this->filterEventsForAxisCheckBox->isChecked();
QPushButton *pushButton = (QPushButton *)button;
QPushButton *okButton = this->buttonBox->button(QDialogButtonBox::Ok);
if (pushButton == okButton)
{
this->hasSaved = true;
this->settings.ControllerPak = this->controllerPakComboBox->currentIndex();
this->settings.GameboyRom = this->gameboyRomLineEdit->text().toStdString();
this->settings.GameboySave = this->gameboySaveLineEdit->text().toStdString();
this->settings.RemoveDuplicateMappings = this->removeDuplicateMappingsCheckbox->isChecked();
this->settings.FilterEventsForButtons = this->filterEventsForButtonsCheckBox->isChecked();
this->settings.FilterEventsForAxis = this->filterEventsForAxisCheckBox->isChecked();
}
this->accept();
QDialog::accept();
}
void OptionsDialog::on_changeGameboyRomButton_clicked()
@@ -37,19 +37,17 @@ Q_OBJECT
public:
OptionsDialog(QWidget *parent, OptionsDialogSettings settings);
bool HasSaved();
OptionsDialogSettings GetSettings();
protected:
void accept() Q_DECL_OVERRIDE;
private:
bool hasSaved = false;
OptionsDialogSettings settings;
void setIconsForEmulationInfoText(void);
void hideEmulationInfoText(void);
private slots:
void on_buttonBox_clicked(QAbstractButton *);
void on_changeGameboyRomButton_clicked();
void on_changeGameboySaveButton_clicked();
};
@@ -248,5 +248,38 @@
<resources>
<include location="UIResources.qrc"/>
</resources>
<connections/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>OptionsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>OptionsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -175,7 +175,7 @@ void ControllerImageWidget::paintEvent(QPaintEvent *event)
double offsetDeadzone = this->deadzoneValue * sensitivityFactor * offsetSlope;
int offsetx = this->xAxisState * sensitivityFactor * offsetSlope;
int offsety = this->yAxisState * sensitivityFactor * offsetSlope;
const double offsetDist = sqrt(pow(offsetx, 2) + pow(offsety, 2));
const double offsetDist = std::hypot(offsetx, offsety);
// take deadzone into account
// deadzone grows with sensitivity such that the deadzone
@@ -92,6 +92,48 @@ ControllerWidget::ControllerWidget(QWidget* parent, EventFilter* eventFilter) :
{ this->analogStickRightButton, SettingsID::Input_AnalogStickRight_InputType, SettingsID::Input_AnalogStickRight_Name, SettingsID::Input_AnalogStickRight_Data, SettingsID::Input_AnalogStickRight_ExtraData },
});
this->hotkeySettingMappings.append(
{
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_Shutdown_InputType, SettingsID::Input_Hotkey_Shutdown_Name, SettingsID::Input_Hotkey_Shutdown_Data, SettingsID::Input_Hotkey_Shutdown_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_Exit_InputType, SettingsID::Input_Hotkey_Exit_Name, SettingsID::Input_Hotkey_Exit_Data, SettingsID::Input_Hotkey_Exit_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SoftReset_InputType, SettingsID::Input_Hotkey_SoftReset_Name, SettingsID::Input_Hotkey_SoftReset_Data, SettingsID::Input_Hotkey_SoftReset_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_HardReset_InputType, SettingsID::Input_Hotkey_HardReset_Name, SettingsID::Input_Hotkey_HardReset_Data, SettingsID::Input_Hotkey_HardReset_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_Resume_InputType, SettingsID::Input_Hotkey_Resume_Name, SettingsID::Input_Hotkey_Resume_Data, SettingsID::Input_Hotkey_Resume_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_Screenshot_InputType, SettingsID::Input_Hotkey_Screenshot_Name, SettingsID::Input_Hotkey_Screenshot_Data, SettingsID::Input_Hotkey_Screenshot_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_LimitFPS_InputType, SettingsID::Input_Hotkey_LimitFPS_Name, SettingsID::Input_Hotkey_LimitFPS_Data, SettingsID::Input_Hotkey_LimitFPS_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SpeedFactor25_InputType, SettingsID::Input_Hotkey_SpeedFactor25_Name, SettingsID::Input_Hotkey_SpeedFactor25_Data, SettingsID::Input_Hotkey_SpeedFactor25_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SpeedFactor50_InputType, SettingsID::Input_Hotkey_SpeedFactor50_Name, SettingsID::Input_Hotkey_SpeedFactor50_Data, SettingsID::Input_Hotkey_SpeedFactor50_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SpeedFactor75_InputType, SettingsID::Input_Hotkey_SpeedFactor75_Name, SettingsID::Input_Hotkey_SpeedFactor75_Data, SettingsID::Input_Hotkey_SpeedFactor75_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SpeedFactor100_InputType, SettingsID::Input_Hotkey_SpeedFactor100_Name, SettingsID::Input_Hotkey_SpeedFactor100_Data, SettingsID::Input_Hotkey_SpeedFactor100_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SpeedFactor125_InputType, SettingsID::Input_Hotkey_SpeedFactor125_Name, SettingsID::Input_Hotkey_SpeedFactor125_Data, SettingsID::Input_Hotkey_SpeedFactor125_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SpeedFactor150_InputType, SettingsID::Input_Hotkey_SpeedFactor150_Name, SettingsID::Input_Hotkey_SpeedFactor150_Data, SettingsID::Input_Hotkey_SpeedFactor150_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SpeedFactor175_InputType, SettingsID::Input_Hotkey_SpeedFactor175_Name, SettingsID::Input_Hotkey_SpeedFactor175_Data, SettingsID::Input_Hotkey_SpeedFactor175_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SpeedFactor200_InputType, SettingsID::Input_Hotkey_SpeedFactor200_Name, SettingsID::Input_Hotkey_SpeedFactor200_Data, SettingsID::Input_Hotkey_SpeedFactor200_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SpeedFactor225_InputType, SettingsID::Input_Hotkey_SpeedFactor225_Name, SettingsID::Input_Hotkey_SpeedFactor225_Data, SettingsID::Input_Hotkey_SpeedFactor225_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SpeedFactor250_InputType, SettingsID::Input_Hotkey_SpeedFactor250_Name, SettingsID::Input_Hotkey_SpeedFactor250_Data, SettingsID::Input_Hotkey_SpeedFactor250_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SpeedFactor275_InputType, SettingsID::Input_Hotkey_SpeedFactor275_Name, SettingsID::Input_Hotkey_SpeedFactor275_Data, SettingsID::Input_Hotkey_SpeedFactor275_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SpeedFactor300_InputType, SettingsID::Input_Hotkey_SpeedFactor300_Name, SettingsID::Input_Hotkey_SpeedFactor300_Data, SettingsID::Input_Hotkey_SpeedFactor300_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SaveState_InputType, SettingsID::Input_Hotkey_SaveState_Name, SettingsID::Input_Hotkey_SaveState_Data, SettingsID::Input_Hotkey_SaveState_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_LoadState_InputType, SettingsID::Input_Hotkey_LoadState_Name, SettingsID::Input_Hotkey_LoadState_Data, SettingsID::Input_Hotkey_LoadState_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_GSButton_InputType, SettingsID::Input_Hotkey_GSButton_Name, SettingsID::Input_Hotkey_GSButton_Data, SettingsID::Input_Hotkey_GSButton_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SaveStateSlot0_InputType, SettingsID::Input_Hotkey_SaveStateSlot0_Name, SettingsID::Input_Hotkey_SaveStateSlot0_Data, SettingsID::Input_Hotkey_SaveStateSlot0_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SaveStateSlot1_InputType, SettingsID::Input_Hotkey_SaveStateSlot1_Name, SettingsID::Input_Hotkey_SaveStateSlot1_Data, SettingsID::Input_Hotkey_SaveStateSlot1_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SaveStateSlot2_InputType, SettingsID::Input_Hotkey_SaveStateSlot2_Name, SettingsID::Input_Hotkey_SaveStateSlot2_Data, SettingsID::Input_Hotkey_SaveStateSlot2_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SaveStateSlot3_InputType, SettingsID::Input_Hotkey_SaveStateSlot3_Name, SettingsID::Input_Hotkey_SaveStateSlot3_Data, SettingsID::Input_Hotkey_SaveStateSlot3_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SaveStateSlot4_InputType, SettingsID::Input_Hotkey_SaveStateSlot4_Name, SettingsID::Input_Hotkey_SaveStateSlot4_Data, SettingsID::Input_Hotkey_SaveStateSlot4_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SaveStateSlot5_InputType, SettingsID::Input_Hotkey_SaveStateSlot5_Name, SettingsID::Input_Hotkey_SaveStateSlot5_Data, SettingsID::Input_Hotkey_SaveStateSlot5_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SaveStateSlot6_InputType, SettingsID::Input_Hotkey_SaveStateSlot6_Name, SettingsID::Input_Hotkey_SaveStateSlot6_Data, SettingsID::Input_Hotkey_SaveStateSlot6_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SaveStateSlot7_InputType, SettingsID::Input_Hotkey_SaveStateSlot7_Name, SettingsID::Input_Hotkey_SaveStateSlot7_Data, SettingsID::Input_Hotkey_SaveStateSlot7_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SaveStateSlot8_InputType, SettingsID::Input_Hotkey_SaveStateSlot8_Name, SettingsID::Input_Hotkey_SaveStateSlot8_Data, SettingsID::Input_Hotkey_SaveStateSlot8_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_SaveStateSlot9_InputType, SettingsID::Input_Hotkey_SaveStateSlot9_Name, SettingsID::Input_Hotkey_SaveStateSlot9_Data, SettingsID::Input_Hotkey_SaveStateSlot9_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_IncreaseSaveStateSlot_InputType, SettingsID::Input_Hotkey_IncreaseSaveStateSlot_Name, SettingsID::Input_Hotkey_IncreaseSaveStateSlot_Data, SettingsID::Input_Hotkey_IncreaseSaveStateSlot_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_DecreaseSaveStateSlot_InputType, SettingsID::Input_Hotkey_DecreaseSaveStateSlot_Name, SettingsID::Input_Hotkey_DecreaseSaveStateSlot_Data, SettingsID::Input_Hotkey_DecreaseSaveStateSlot_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_MemoryPak_InputType, SettingsID::Input_Hotkey_MemoryPak_Name, SettingsID::Input_Hotkey_MemoryPak_Data, SettingsID::Input_Hotkey_MemoryPak_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_RumblePak_InputType, SettingsID::Input_Hotkey_RumblePak_Name, SettingsID::Input_Hotkey_RumblePak_Data, SettingsID::Input_Hotkey_RumblePak_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_NoPak_InputType, SettingsID::Input_Hotkey_NoPak_Name, SettingsID::Input_Hotkey_NoPak_Data, SettingsID::Input_Hotkey_NoPak_ExtraData },
{ {}, {}, {}, {}, SettingsID::Input_Hotkey_Fullscreen_InputType, SettingsID::Input_Hotkey_Fullscreen_Name, SettingsID::Input_Hotkey_Fullscreen_Data, SettingsID::Input_Hotkey_Fullscreen_ExtraData },
});
MappingButton* buttonList[] =
{
// dpad
@@ -196,6 +238,7 @@ void ControllerWidget::initializeMiscButtons()
this->inputDeviceRefreshButton->setIcon(QIcon::fromTheme("refresh-line"));
this->resetButton->setIcon(QIcon::fromTheme("restart-line"));
this->optionsButton->setIcon(QIcon::fromTheme("settings-3-line"));
this->hotkeysButton->setIcon(QIcon::fromTheme("gamepad-line"));
}
bool ControllerWidget::isCurrentDeviceKeyboard()
@@ -255,6 +298,10 @@ void ControllerWidget::removeDuplicates(MappingButton* button)
return;
}
std::vector<int> inputType = button->GetInputType();
std::vector<int> inputData = button->GetInputData();
std::vector<int> extraInputData = button->GetExtraInputData();
for (auto& buttonWidget : this->setupButtonWidgets)
{
// skip ourselfes
@@ -263,14 +310,6 @@ void ControllerWidget::removeDuplicates(MappingButton* button)
continue;
}
std::vector<int> inputType;
std::vector<int> inputData;
std::vector<int> extraInputData;
inputType = button->GetInputType();
inputData = button->GetInputData();
extraInputData = button->GetExtraInputData();
for (int i = 0; i < inputType.size(); i++)
{
if (buttonWidget->HasInputData((InputType)inputType.at(i), inputData.at(i), extraInputData.at(i)))
@@ -344,7 +383,8 @@ void ControllerWidget::setPluggedIn(bool value)
this->deadZoneGroupBox,
this->deadZoneSlider,
this->optionsButton,
this->resetButton
this->resetButton,
this->hotkeysButton,
};
for (auto& widget : widgetList)
@@ -623,7 +663,8 @@ void ControllerWidget::on_inputDeviceComboBox_currentIndexChanged(int value)
}
// set plugged in state
this->setPluggedIn(deviceNum != (int)InputDeviceType::None);
this->setPluggedIn(deviceNum != (int)InputDeviceType::None &&
deviceNum != (int)InputDeviceType::EmulateVRU);
emit this->CurrentInputDeviceChanged(this, deviceName, deviceNum);
}
@@ -775,15 +816,39 @@ void ControllerWidget::on_resetButton_clicked()
void ControllerWidget::on_optionsButton_clicked()
{
OptionsDialog dialog(this, this->optionsDialogSettings);
dialog.exec();
int ret = dialog.exec();
// when saved, store settings for later
if (dialog.HasSaved())
if (ret == QDialog::Accepted)
{
this->optionsDialogSettings = dialog.GetSettings();
}
}
void ControllerWidget::on_hotkeysButton_clicked()
{
HotkeysDialog dialog(this, this->hotkeySettingMappings,
this->isCurrentJoystickGameController,
this->currentJoystickId,
this->optionsDialogSettings.FilterEventsForButtons,
this->optionsDialogSettings.RemoveDuplicateMappings);
// clear our UI state
this->controllerImageWidget->ClearControllerState();
this->currentHotkeysDialog = &dialog;
int ret = dialog.exec();
this->currentHotkeysDialog = nullptr;
// when saved, store settings for later
if (ret == QDialog::Accepted)
{
this->hotkeySettingMappings = dialog.GetSettingMappings();
}
}
void ControllerWidget::on_MappingButton_Released(MappingButton* button)
{
if (this->currentButton != nullptr)
@@ -795,7 +860,7 @@ void ControllerWidget::on_MappingButton_Released(MappingButton* button)
this->currentButton = button;
button->SaveState();
button->StartTimer();
this->disableAllChildren();
}
@@ -833,6 +898,13 @@ void ControllerWidget::on_MappingButton_DataSet(MappingButton* button)
void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
{
// pass to hotkeys dialog when it's active
if (this->currentHotkeysDialog != nullptr)
{
this->currentHotkeysDialog->on_MainDialog_SdlEvent(event);
return;
}
switch (event->type)
{
case SDL_CONTROLLERBUTTONDOWN:
@@ -1390,6 +1462,14 @@ void ControllerWidget::LoadSettings(QString sectionQString, bool loadUserProfile
}
}
for (auto& hotkeySetting : this->hotkeySettingMappings)
{
hotkeySetting.inputTypes = CoreSettingsGetIntListValue(hotkeySetting.inputTypeSettingsId, section);
hotkeySetting.inputText = CoreSettingsGetStringListValue(hotkeySetting.nameSettingsId, section);
hotkeySetting.inputData = CoreSettingsGetIntListValue(hotkeySetting.dataSettingsId, section);
hotkeySetting.extraInputData = CoreSettingsGetIntListValue(hotkeySetting.extraDataSettingsId, section);
}
// force refresh some UI elements
this->CheckInputDeviceSettings();
this->on_deadZoneSlider_valueChanged(this->deadZoneSlider->value());
@@ -1529,6 +1609,14 @@ void ControllerWidget::SaveSettings(QString section)
CoreSettingsSetValue(buttonSetting.dataSettingsId, sectionStr, buttonSetting.button->GetInputData());
CoreSettingsSetValue(buttonSetting.extraDataSettingsId, sectionStr, buttonSetting.button->GetExtraInputData());
}
for (auto& hotkeySetting : this->hotkeySettingMappings)
{
CoreSettingsSetValue(hotkeySetting.inputTypeSettingsId, sectionStr, hotkeySetting.inputTypes);
CoreSettingsSetValue(hotkeySetting.nameSettingsId, sectionStr, hotkeySetting.inputText);
CoreSettingsSetValue(hotkeySetting.dataSettingsId, sectionStr, hotkeySetting.inputData);
CoreSettingsSetValue(hotkeySetting.extraDataSettingsId, sectionStr, hotkeySetting.extraInputData);
}
}
void ControllerWidget::RevertSettings()
@@ -15,6 +15,7 @@
#include "UserInterface/EventFilter.hpp"
#include "UserInterface/OptionsDialog.hpp"
#include "UserInterface/HotkeysDialog.hpp"
using namespace UserInterface::Widget;
@@ -72,6 +73,7 @@ private:
QList<buttonWidgetMapping> buttonWidgetMappings;
QList<axisWidgetMapping> joystickWidgetMappings;
QList<buttonSettingMapping> buttonSettingMappings;
QList<HotkeySettingMapping> hotkeySettingMappings;
QList<MappingButton*> setupButtonWidgets;
void initializeMappingButtons();
@@ -106,6 +108,8 @@ private:
bool onlyLoadGameProfile = false;
HotkeysDialog* currentHotkeysDialog = nullptr;
public:
ControllerWidget(QWidget* parent, EventFilter* eventFilter);
~ControllerWidget();
@@ -156,6 +160,7 @@ private slots:
void on_resetButton_clicked();
void on_optionsButton_clicked();
void on_hotkeysButton_clicked();
public slots:
void on_MappingButton_Released(MappingButton* button);
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>1239</width>
<height>562</height>
<height>601</height>
</rect>
</property>
<property name="sizePolicy">
@@ -1254,6 +1254,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="hotkeysButton">
<property name="text">
<string>Hotkeys</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
@@ -0,0 +1,221 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "HotkeyButton.hpp"
#include "UserInterface/HotkeysDialog.hpp"
#include <QMouseEvent>
using namespace UserInterface::Widget;
HotkeyButton::HotkeyButton(QWidget* parent) : QPushButton(parent)
{
this->countDownTimer = new QTimer(this);
connect(this->countDownTimer, &QTimer::timeout, this, &HotkeyButton::on_countDownTimer_triggered);
this->initialSize = this->size();
}
HotkeyButton::~HotkeyButton()
{
}
void HotkeyButton::Initialize(HotkeysDialog* dialog)
{
this->hotkeysDialog = dialog;
connect(this, &QPushButton::released, [=]
{
emit this->hotkeysDialog->on_HotkeyButton_Released(this);
});
this->setText(" ");
}
void HotkeyButton::Clear()
{
this->inputData.clear();
this->savedInputData.clear();
this->setText("");
}
void HotkeyButton::StartTimer()
{
// clear current state
this->inputData.clear();
this->currentCountDownNum = 5;
this->on_countDownTimer_triggered();
this->countDownTimer->start(1000);
}
void HotkeyButton::StopTimer()
{
this->countDownTimer->stop();
}
void HotkeyButton::AddInputData(enum InputType type, int value, int extraValue, QString name)
{
// don't add stub
if (name.simplified().isEmpty())
{
return;
}
if (!this->HasInputData(type, value, extraValue))
{
this->inputData.push_back(
{
type,
value,
extraValue,
name
}
);
}
}
bool HotkeyButton::HasInputData(enum InputType type, int value, int extraValue)
{
return this->getInputDataIter(type, value, extraValue) != this->inputData.end();
}
std::vector<int> HotkeyButton::GetInputType()
{
std::vector<int> inputTypeList;
for (const auto& data : this->inputData)
{
inputTypeList.push_back((int)data.Type);
}
return inputTypeList;
}
std::vector<int> HotkeyButton::GetInputData()
{
std::vector<int> inputDataList;
for (const auto& data : this->inputData)
{
inputDataList.push_back(data.Data);
}
return inputDataList;
}
std::vector<int> HotkeyButton::GetExtraInputData()
{
std::vector<int> extraInputDataList;
for (const auto& data : this->inputData)
{
extraInputDataList.push_back(data.ExtraData);
}
return extraInputDataList;
}
std::vector<std::string> HotkeyButton::GetInputText()
{
std::vector<std::string> inputTextList;
for (const auto& data : this->inputData)
{
inputTextList.push_back(data.Text.toStdString());
}
return inputTextList;
}
void HotkeyButton::SaveState()
{
this->savedInputData = this->inputData;
}
void HotkeyButton::RestoreState()
{
this->inputData = this->savedInputData;
this->reloadText();
}
void HotkeyButton::FinishState()
{
this->reloadText();
emit this->hotkeysDialog->on_HotkeyButton_StateFinished(this);
}
void HotkeyButton::mousePressEvent(QMouseEvent* event)
{
if (event->button() == Qt::RightButton)
{
this->Clear();
return;
}
QPushButton::mousePressEvent(event);
}
void HotkeyButton::on_countDownTimer_triggered()
{
this->setText(QString::number(this->currentCountDownNum));
if (this->currentCountDownNum == 0)
{
this->setText("");
this->currentCountDownNum = 5;
this->countDownTimer->stop();
emit this->hotkeysDialog->on_HotkeyButton_TimerFinished(this);
}
this->currentCountDownNum--;
}
void HotkeyButton::reloadText()
{
QString text;
QFontMetrics fontMetrics(this->font());
int size = this->inputData.size();
for (int i = 0; i < size; i++)
{
text += this->inputData.at(i).Text;
// only add comma when
// not at the last item
if (i < (size - 1))
{
text += "+";
}
}
QString elidedText = fontMetrics.elidedText(text, Qt::ElideRight, this->initialSize.width());
// needed for spacing
if (elidedText.isEmpty())
{
elidedText = " ";
}
this->setToolTip(text);
this->setText(elidedText);
}
std::vector<HotkeyButtonInputDataType>::iterator HotkeyButton::getInputDataIter(InputType type, int value, int extraValue)
{
auto predicate = [type, value, extraValue](const auto& entry)
{
return entry.Type == type &&
(value == -1 || entry.Data == value) &&
(extraValue == -1 || entry.ExtraData == extraValue);
};
return std::find_if(this->inputData.begin(), this->inputData.end(), predicate);
}
@@ -0,0 +1,86 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef HOTKEYBUTTON_HPP
#define HOTKEYBUTTON_HPP
#include <QPushButton>
#include <QTimer>
#include "common.hpp"
namespace UserInterface
{
// we can't include HotkeysDialog.hpp
// because that header includes this header,
// so forward-declare it to prevent issues
class HotkeysDialog;
namespace Widget
{
struct HotkeyButtonInputDataType
{
InputType Type;
int Data;
int ExtraData;
QString Text;
};
class HotkeyButton : public QPushButton
{
private:
QSize initialSize;
QTimer* countDownTimer = nullptr;
HotkeysDialog* hotkeysDialog = nullptr;
int currentCountDownNum = 0;
std::vector<HotkeyButtonInputDataType> inputData;
std::vector<HotkeyButtonInputDataType> savedInputData;
void reloadText();
std::vector<HotkeyButtonInputDataType>::iterator getInputDataIter(InputType type, int value, int extraValue);
public:
HotkeyButton(QWidget* parent);
~HotkeyButton();
void Initialize(HotkeysDialog* dialog);
void Clear();
void StartTimer();
void StopTimer();
void AddInputData(InputType type, int value, int extraValue, QString name);
bool HasInputData(InputType type, int value = -1, int extraValue = -1);
std::vector<int> GetInputType();
std::vector<int> GetInputData();
std::vector<int> GetExtraInputData();
std::vector<std::string> GetInputText();
void SaveState();
void RestoreState();
void FinishState();
protected:
void mousePressEvent(QMouseEvent* event);
private slots:
void on_countDownTimer_triggered();
};
}
}
#endif // HOTKEYBUTTON_HPP
+603
View File
@@ -0,0 +1,603 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#define CORE_PLUGIN
#define M64P_PLUGIN_PROTOTYPES 1
#include <RMG-Core/Core.hpp>
#include <RMG-Core/osal/osal_dynlib.hpp>
#include <../3rdParty/vosk-api/include/vosk_api.h>
#include <iostream>
#include <QByteArray>
#include <QStringDecoder>
#include <QStringList>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <SDL.h>
#include "VRU.hpp"
#include "VRUwords.hpp"
//
// Local Enums
//
enum Language
{
English = 0,
JapaneseOrDemo = 1
};
//
// Local Variables
//
// vosk-api library variables
//
typedef VoskModel* (*ptr_vosk_model_new)(const char *);
typedef void (*ptr_vosk_model_free)(VoskModel *);
typedef VoskRecognizer* (*ptr_vosk_recognizer_new_grm)(VoskModel *, float, const char *);
typedef void (*ptr_vosk_recognizer_free)(VoskRecognizer *);
typedef int (*ptr_vosk_recognizer_accept_waveform)(VoskRecognizer *, const char *, int );
typedef const char * (*ptr_vosk_recognizer_final_result)(VoskRecognizer *);
typedef void (*ptr_vosk_set_log_level)(int);
typedef void (*ptr_vosk_recognizer_set_max_alternatives)(VoskRecognizer *, int);
static ptr_vosk_model_new l_vosk_model_new = nullptr;
static ptr_vosk_model_free l_vosk_model_free = nullptr;
static ptr_vosk_recognizer_new_grm l_vosk_recognizer_new_grm = nullptr;
static ptr_vosk_recognizer_free l_vosk_recognizer_free = nullptr;
static ptr_vosk_recognizer_accept_waveform l_vosk_recognizer_accept_waveform = nullptr;
static ptr_vosk_recognizer_final_result l_vosk_recognizer_final_result = nullptr;
static ptr_vosk_set_log_level l_vosk_set_log_level = nullptr;
static ptr_vosk_recognizer_set_max_alternatives l_vosk_recognizer_set_max_alternatives = nullptr;
static osal_dynlib_lib_handle l_VoskLibHandle = nullptr;
static VoskModel* l_VoskModel = nullptr;
static VoskRecognizer* l_VoskRecognizer = nullptr;
// VRU implementation variables
//
static bool l_Initialized = false;
static std::vector<VRUWordEntry> l_WordEntries;
static int l_MicState = 0;
static int l_WordListSize = 0;
static int l_WordListCount = 0;
static QStringList l_RegisteredWords;
static QList<int> l_RegisteredWordsIndex;
static SDL_AudioDeviceID l_AudioDevice = 0;
static SDL_AudioSpec l_AudioDeviceSpec;
//
// Local Functions
//
static bool hook_vosk(void)
{
std::string debugMessage;
std::filesystem::path voskApiPath;
voskApiPath = CoreGetLibraryDirectory();
voskApiPath += "/libvosk" OSAL_DYNLIB_LIB_EXT_STR;
l_VoskLibHandle = osal_dynlib_open(voskApiPath);
if (l_VoskLibHandle == nullptr)
{
debugMessage = "VRU: Failed to open library \"";
debugMessage += voskApiPath.string().c_str();
debugMessage += "\": ";
debugMessage += osal_dynlib_strerror();
CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage);
return false;
}
l_vosk_model_new = (ptr_vosk_model_new) osal_dynlib_sym(l_VoskLibHandle, "vosk_model_new");
l_vosk_model_free = (ptr_vosk_model_free) osal_dynlib_sym(l_VoskLibHandle, "vosk_model_free");
l_vosk_recognizer_new_grm = (ptr_vosk_recognizer_new_grm) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_new_grm");
l_vosk_recognizer_free = (ptr_vosk_recognizer_free) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_free");
l_vosk_recognizer_accept_waveform = (ptr_vosk_recognizer_accept_waveform) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_accept_waveform");
l_vosk_recognizer_final_result = (ptr_vosk_recognizer_final_result) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_final_result");
l_vosk_set_log_level = (ptr_vosk_set_log_level) osal_dynlib_sym(l_VoskLibHandle, "vosk_set_log_level");
l_vosk_recognizer_set_max_alternatives = (ptr_vosk_recognizer_set_max_alternatives) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_set_max_alternatives");
if (l_vosk_model_new == nullptr ||
l_vosk_model_free == nullptr ||
l_vosk_recognizer_new_grm == nullptr ||
l_vosk_recognizer_free == nullptr ||
l_vosk_recognizer_accept_waveform == nullptr ||
l_vosk_recognizer_final_result == nullptr ||
l_vosk_set_log_level == nullptr ||
l_vosk_recognizer_set_max_alternatives == nullptr)
{
debugMessage = "VRU: Failed to open library: missing functions";
CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage);
return false;
}
return true;
}
static void unhook_vosk(void)
{
l_vosk_model_new = nullptr;
l_vosk_model_free = nullptr;
l_vosk_recognizer_new_grm = nullptr;
l_vosk_recognizer_free = nullptr;
l_vosk_recognizer_accept_waveform = nullptr;
l_vosk_recognizer_final_result = nullptr;
l_vosk_set_log_level = nullptr;
l_vosk_recognizer_set_max_alternatives = nullptr;
osal_dynlib_close(l_VoskLibHandle);
}
static bool setup_vosk_model(void)
{
std::string debugMessage;
std::filesystem::path voskModelPath;
voskModelPath = CoreGetSharedDataDirectory();
voskModelPath += "/vosk-model-small-en-us-0.15.zip";
bool missingModelFile = false;
std::filesystem::path voskModelFiles[] =
{
"vosk-model-small-en-us-0.15/am/final.mdl",
"vosk-model-small-en-us-0.15/conf/mfcc.conf",
"vosk-model-small-en-us-0.15/conf/model.conf",
"vosk-model-small-en-us-0.15/graph/disambig_tid.int",
"vosk-model-small-en-us-0.15/graph/Gr.fst",
"vosk-model-small-en-us-0.15/graph/HCLr.fst",
"vosk-model-small-en-us-0.15/graph/phones/word_boundary.int",
"vosk-model-small-en-us-0.15/ivector/final.dubm",
"vosk-model-small-en-us-0.15/ivector/final.ie",
"vosk-model-small-en-us-0.15/ivector/final.mat",
"vosk-model-small-en-us-0.15/ivector/global_cmvn.stats",
"vosk-model-small-en-us-0.15/ivector/online_cmvn.conf",
"vosk-model-small-en-us-0.15/ivector/splice.conf",
};
for (std::filesystem::path& file : voskModelFiles)
{
std::filesystem::path fullFilePath;
fullFilePath = CoreGetUserDataDirectory();
fullFilePath += "/";
fullFilePath += file;
if (!std::filesystem::exists(fullFilePath))
{
missingModelFile = true;
break;
}
}
// all required files exist,
// so we don't need to extract the zip again
if (!missingModelFile)
{
return true;
}
if (!std::filesystem::is_regular_file(voskModelPath))
{
debugMessage = "VRU: vosk model file \"";
debugMessage += voskModelPath.string().c_str();
debugMessage += "\" doesn't exist!";
CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage);
return false;
}
if (!CoreUnzip(voskModelPath, CoreGetUserDataDirectory()))
{
debugMessage = "VRU: Failed to extract vosk model file \"";
debugMessage += voskModelPath.string().c_str();
debugMessage += "\": ";
debugMessage += CoreGetError();
CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage);
return false;
}
return true;
}
static bool init_vosk(void)
{
std::filesystem::path voskModelPath;
voskModelPath = CoreGetUserDataDirectory();
voskModelPath += "/vosk-model-small-en-us-0.15";
l_vosk_set_log_level(-1);
l_VoskModel = l_vosk_model_new(voskModelPath.string().c_str());
if (l_VoskModel == nullptr)
{
CoreDebugCallbackMessage(CoreDebugMessageType::Error, "VRU: vosk_model_new failed");
return false;
}
return true;
}
static void quit_vosk(void)
{
if (l_VoskModel != nullptr)
{
l_vosk_model_free(l_VoskModel);
l_VoskModel = nullptr;
}
if (l_VoskRecognizer != nullptr)
{
l_vosk_recognizer_free(l_VoskRecognizer);
l_VoskRecognizer = nullptr;
}
}
static bool init_mic(void)
{
std::string debugMessage;
SDL_AudioSpec desiredAudioSpec;
desiredAudioSpec.freq = 44100;
desiredAudioSpec.format = AUDIO_S16SYS;
desiredAudioSpec.channels = 1;
desiredAudioSpec.samples = 1024;
desiredAudioSpec.callback = nullptr;
desiredAudioSpec.userdata = nullptr;
l_AudioDevice = SDL_OpenAudioDevice(nullptr, 1, &desiredAudioSpec, &l_AudioDeviceSpec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
if (l_AudioDevice == 0)
{
debugMessage = "VRU: SDL_OpenAudioDevice Failed: ";
debugMessage += SDL_GetError();
CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage);
return false;
}
return true;
}
static void quit_mic(void)
{
if (l_AudioDevice != 0)
{
SDL_CloseAudioDevice(l_AudioDevice);
}
}
static QByteArray words_to_byte_array(uint16_t* words, uint16_t size)
{
QByteArray byte_array;
uint8_t* bytes = (uint8_t*)words;
for (int i = 0; i < (size * 2); i += 2)
{
byte_array.push_back(bytes[i + 1]);
byte_array.push_back(bytes[i]);
}
return byte_array;
}
static bool find_word_from_hex(std::string hex, std::string& word)
{
auto predicate = [hex](const VRUWordEntry& entry)
{
return entry.hex == hex;
};
auto iter = std::find_if(l_WordEntries.begin(), l_WordEntries.end(), predicate);
if (iter != l_WordEntries.end())
{
word = (*iter).words;
}
return iter != l_WordEntries.end();
}
//
// Exported Functions
//
bool InitVRU(void)
{
if (l_Initialized)
{
return true;
}
if (!hook_vosk())
{
return false;
}
if (!setup_vosk_model())
{
return false;
}
if (!init_vosk())
{
return false;
}
if (!init_mic())
{
return false;
}
l_MicState = 0;
if (l_WordEntries.empty())
{
l_WordEntries = GetVRUWordEntries();
}
l_Initialized = true;
return true;
}
bool IsVRUInit(void)
{
return l_Initialized;
}
bool QuitVRU(void)
{
if (!l_Initialized)
{
return false;
}
quit_mic();
quit_vosk();
unhook_vosk();
l_Initialized = false;
return true;
}
int GetVRUMicState(void)
{
return l_MicState;
}
//
// VRU Plugin Functions
//
EXPORT void CALL SendVRUWord(uint16_t length, uint16_t* word, uint8_t lang)
{
if (!l_Initialized)
{
return;
}
QByteArray byte_array = words_to_byte_array(word, length);
std::string debugMessage;
std::string word_str;
if (find_word_from_hex(byte_array.toHex().toUpper().toStdString(), word_str))
{ // found word
l_RegisteredWords.append(QString::fromStdString(word_str));
l_RegisteredWordsIndex.append(l_WordListCount);
}
else
{ // not found
QStringDecoder utf8_decoder = QStringDecoder(QStringDecoder::Utf8);
QString encoded_string = utf8_decoder.decode(byte_array);
if (utf8_decoder.hasError())
{
debugMessage = "VRU: unknown word: ";
debugMessage += encoded_string.toStdString();
CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage);
}
else
{
l_RegisteredWords.append(encoded_string);
l_RegisteredWordsIndex.append(l_WordListCount);
}
}
l_WordListCount++;
// we've reached the end of the list
if (l_WordListCount == l_WordListSize)
{
// needed for vosk-api, see vosk_api.h
l_RegisteredWords.append("[unk]");
l_RegisteredWordsIndex.append(l_WordListCount);
QJsonDocument json_document;
json_document.setArray(QJsonArray::fromStringList(l_RegisteredWords));
// free existing recognizer if needed
if (l_VoskRecognizer)
{
l_vosk_recognizer_free(l_VoskRecognizer);
l_VoskRecognizer = nullptr;
}
// try to create a new recognizer
l_VoskRecognizer = l_vosk_recognizer_new_grm(l_VoskModel, (float)l_AudioDeviceSpec.freq, json_document.toJson().constData());
if (l_VoskRecognizer != nullptr)
{
l_vosk_recognizer_set_max_alternatives(l_VoskRecognizer, 3);
}
}
}
EXPORT void CALL SetMicState(int state)
{
if (!l_Initialized)
{
return;
}
if (state)
{
SDL_ClearQueuedAudio(l_AudioDevice);
SDL_PauseAudioDevice(l_AudioDevice, 0);
}
else
{
SDL_PauseAudioDevice(l_AudioDevice, 1);
}
l_MicState = state;
}
EXPORT void CALL ReadVRUResults(uint16_t* error_flags, uint16_t* num_results, uint16_t* mic_level, uint16_t* voice_level, uint16_t* voice_length, uint16_t* matches)
{
if (!l_Initialized || l_VoskRecognizer == nullptr)
{
return;
}
// initialize result data
*num_results = 0;
*mic_level = 0xBB8;
*voice_level = 0xBB8;
*voice_length = 0x8004;
for (int i = 0; i < 10; i += 2)
{
matches[i] = 0x7FFF;
matches[i + 1] = 0;
}
// retrieve audio data from device
SDL_PauseAudioDevice(l_AudioDevice, 1);
void* audio_buf = nullptr;
uint32_t audio_size = SDL_GetQueuedAudioSize(l_AudioDevice);
audio_buf = malloc(audio_size);
if (audio_buf == nullptr)
{
*error_flags = 0x8000;
return;
}
audio_size = SDL_DequeueAudio(l_AudioDevice, audio_buf, audio_size);
// hand audio data to vosk and retrieve results
int ret = l_vosk_recognizer_accept_waveform(l_VoskRecognizer, (const char*)audio_buf, audio_size);
if (ret == -1)
{
*error_flags = 0x8000;
free(audio_buf);
return;
}
QJsonDocument json_document = QJsonDocument::fromJson(l_vosk_recognizer_final_result(l_VoskRecognizer));
// parse results from vosk
QJsonArray alternatives_array = json_document.object().value("alternatives").toArray();
QStringList alternative_words;
QStringList found_words;
std::string debugMessage;
// parse words
for (int i = 0; i < alternatives_array.size(); i++)
{
QString word = alternatives_array.at(i).toObject().value("text").toString();
if (!word.isEmpty())
{
alternative_words.append(word);
}
}
// check the registered words,
// and see if any matches with the recognized words
for (const QString& word : l_RegisteredWords)
{
if (word != "[unk]" &&
!found_words.contains(word) &&
alternative_words.filter(word).size() > 0)
{
found_words.append(word);
if (found_words.size() == 5)
{
break;
}
}
}
// sort found words by length
std::sort(found_words.begin(), found_words.end(), [](QString& a, QString& b)
{
return a.size() > b.size();
});
int matches_index = 0;
for (int i = 0; i < found_words.size(); i++)
{
matches[matches_index++] = l_RegisteredWordsIndex.at(l_RegisteredWords.indexOf(found_words.at(i)));
matches[matches_index++] = i * 256;
debugMessage = "VRU: found match ";
debugMessage += std::to_string(i);
debugMessage += ": ";
debugMessage += found_words.at(i).toStdString();
CoreDebugCallbackMessage(CoreDebugMessageType::Info, debugMessage);
}
if (found_words.size() == 0 && alternative_words.size() > 0)
{
// heard something but it didn't match anything
*error_flags = 0x4000;
matches[0] = 0;
found_words.append("0");
debugMessage = "VRU: heard something but it didn't match anything";
CoreDebugCallbackMessage(CoreDebugMessageType::Info, debugMessage);
}
*num_results = found_words.size();
free(audio_buf);
}
EXPORT void CALL ClearVRUWords(uint8_t length)
{
if (!l_Initialized)
{
return;
}
l_WordListCount = 0;
l_WordListSize = length;
l_RegisteredWords.clear();
l_RegisteredWordsIndex.clear();
if (l_VoskRecognizer != nullptr)
{
l_vosk_recognizer_free(l_VoskRecognizer);
l_VoskRecognizer = nullptr;
}
}
EXPORT void CALL SetVRUWordMask(uint8_t length, uint8_t* mask)
{
}
+24
View File
@@ -0,0 +1,24 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef VRU_HPP
#define VRU_HPP
// attempts to initialize VRU capabilities
bool InitVRU(void);
// returns whether VRU has been initialized
bool IsVRUInit(void);
// attempts to de-initialize VRY capabilities
bool QuitVRU(void);
int GetVRUMicState(void);
#endif // VRU_HPP
+739
View File
@@ -0,0 +1,739 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "VRUwords.hpp"
//
// Exported Functions
//
std::vector<VRUWordEntry> GetVRUWordEntries(void)
{
std::vector<VRUWordEntry> entries;
entries.push_back({"03A50024000303CF00A80003036000EA", "pikachu"});
entries.push_back({"03A50045000303CF00A80003036000EA", "pikachu" });
entries.push_back({"03A50024000303C900450003036000EA", "pikachu" });
entries.push_back({"03A8018F000303CF00A80003036000EA", "pikachu" });
entries.push_back({"03B101B0000303CF00A80003036000EA", "pikachu" });
entries.push_back({"03CF00A80003036000EA", "pikachu" });
entries.push_back({"03A80066000303CF00A80003036000F900EA", "pikachu" });
entries.push_back({"03A50024000303CF00A80003035D001200F900EA", "pikachu" });
entries.push_back({"040801740024", "hey" });
entries.push_back({"03CF00C603360405000F0234", "come here" });
entries.push_back({"0369004803FC0318018F", "this way" });
entries.push_back({"039C010B000603900006037B01B0", "good bye" });
entries.push_back({"039900A80006037B01B0", "good bye" });
entries.push_back({"03F900090309009F02E2018F000303BD0234", "see you later" });
entries.push_back({"037B01B00006037B01B0", "bye bye" });
entries.push_back({"03FC000303C30255000303C6", "start" });
entries.push_back({"02E2006903FC000303B402E2018F", "lets play" });
entries.push_back({"040B00C002EB0213", "hello" });
entries.push_back({"043B0213000303AB00A5034803FC006903FC00A503270024", "open sesame" });
entries.push_back({"043B0213000303A80063034803FC006903FC00A503270024", "open sesame" });
entries.push_back({"039F01FE00990318018F", "go away" });
entries.push_back({"039C010B00060390033302D603390042035A", "good morning" });
entries.push_back({"039900A5033302D603390042035A", "good morning" });
entries.push_back({"042F01AD033603FC023A0024", "im sorry" });
entries.push_back({"042F01AD033603FC012602F10024", "im sorry" });
entries.push_back({"03FC023A0024", "sorry" });
entries.push_back({"03FC012602F10024", "sorry" });
entries.push_back({"042F01B00003036000ED03DB030C00EA", "i choose you" });
entries.push_back({"04080174030C00EA000303A50024000303CF00A80003036000EA", "hey you pikachu" });
entries.push_back({"03A50024000303CF00A8000303A50024000303CF00A80003036000EA", "pika pikachu" });
entries.push_back({"03A50024000303CF00A8000303A50024000303CF00A8000303A50024", "pika pika pi" });
entries.push_back({"03A50024000303A50024000303CF00A80003036000EA", "pi pikachu" });
entries.push_back({"03A50024000303A50024000303CF00A8000303A50024", "pi pika pi" });
entries.push_back({"03A50024000303D8000303CF00C9", "pika" });
entries.push_back({"03A50024000303CF00A8", "pika" });
entries.push_back({"03A50024000303CF00A8000303A50024000303CF00A8", "pika pika" });
entries.push_back({"03A503030024000303CF00A8", "pi ka" });
entries.push_back({"03A50024000303CF00C9000303CF00C9", "pi ka ka" });
entries.push_back({"03A50024000303CF00A8000303CF00A8000303A50024", "pi ka ka pi" });
entries.push_back({"037E02F10042035A036C0087000303C604050297", "bring that here" });
entries.push_back({"039F0213000603960066000303B70045000303C6", "go get it" });
entries.push_back({"0393004803E70045000303C6000303C000E703270024", "give it to me" });
entries.push_back({"0393004203270027036C0087000303C6", "gimme that" });
entries.push_back({"03F600C603480006038702370402014D000303D8", "thunder shock" });
entries.push_back({"03F600C603480006038702340006037B020A02EE000303C6", "thunderbolt" });
entries.push_back({"03F600C60348000603870234", "thunder" });
entries.push_back({"03F600C6033F0234", "thunder" });
entries.push_back({"0432009F02E20066000303D8000303C602F10045000303D802F40087000303C6", "electric rat" });
entries.push_back({"0426001B02E20066000303D8000303C602F10045000303D802F40087000303C6", "electric rat" });
entries.push_back({"0432009F02E20066000303C602F10045000303D802F40087000303C6", "electric rat" });
entries.push_back({"042F01A40408018F000303B7030C00EA", "i hate you" });
entries.push_back({"03A202F4018F000303C600060366014D0006037E", "great job" });
entries.push_back({"036C0087000303C3031B00AB03DE000603A202F4018F000303C6", "that was great" });
entries.push_back({"0309023703FC0213000303C9030C00EA000303C6", "you're so cute" });
entries.push_back({"03BD00A202F1004803ED0045000303D8", "terrific" });
entries.push_back({"037500C9000303BD023703F002F10024", "butter free" });
entries.push_back({"043200C603360006037E02F4005D02E500A8", "am brel a" });
entries.push_back({"037B01CE035A0006037B01CE035A", "boing boing" });
entries.push_back({"043801290348000303C000ED036C00A5033C0066000303D803FC000303C603FC000303BA018F00060366", "on to the next stage" });
entries.push_back({"042F0087000303AB009F02EE", "apple" });
entries.push_back({"043200A8000303AB009F02EE", "apple" });
entries.push_back({"0426000C0087000303B402EE", "apple" });
entries.push_back({"03A202F10021033C0087000303AB009F02EE", "green apple" });
entries.push_back({"0372018F000303D8000303BA0087000303AB009F02EE", "baked apple" });
entries.push_back({"039F020A02EE0006038700A5033C0087000303AB009F02EE", "golden apple" });
entries.push_back({"03A5002400030360", "peach" });
entries.push_back({"03FC000303C602FD012C00060372029D0024", "strawberry" });
entries.push_back({"03FC000303BD0225012C00060372029D0024", "strawberry" });
entries.push_back({"02F4008A03DE00060372029D0024", "raspberry" });
entries.push_back({"02F4008A03FC0006037E02F10024", "raspberry" });
entries.push_back({"037500A5033C0084033F00A8", "banana" });
entries.push_back({"036F0042033C0084033F00C9", "banana" });
entries.push_back({"037500C6033C0084033F00A8", "banana" });
entries.push_back({"03CC0087000303C6000303BA018602EE", "cat tail" });
entries.push_back({"032101A702EE00060390040B02340006037E", "wild herb" });
entries.push_back({"03D502D60348", "corn" });
entries.push_back({"03B1014D000303B4000303D502D60348", "popcorn" });
entries.push_back({"03AB00C60336000303B4000303C900420348", "pumpkin" });
entries.push_back({"03AB00C60336000303C900420348", "pumpkin" });
entries.push_back({"03AB00C6035A000303CF00A50348", "pumpkin" });
entries.push_back({"03C00273033F00A8000303B4", "turnip" });
entries.push_back({"03C0027303390045000303B4", "turnip" });
entries.push_back({"03CC00870006036F004500060366", "cabbage" });
entries.push_back({"03CC008102F700A8000303C6", "carrot" });
entries.push_back({"03CC02A300A8000303C6", "carrot" });
entries.push_back({"043200C60339030900A50348", "onion" });
entries.push_back({"043200A5033F00A50348", "onion" });
entries.push_back({"043501080339030900A50348", "onion" });
entries.push_back({"03FC031500240006037500C9000303BA018F0006038D0213", "sweet potato" });
entries.push_back({"03FC03150024000303C6000303AB00A8000303C3016E0006038D0213", "sweet potato" });
entries.push_back({"03FC03150024000303B4000303BA018F0006038700A8", "sweet potato" });
entries.push_back({"0411014D000303C603FC03150024000303C6000303AB00C9000303BA018F0006038D0213", "hot sweet potato" });
entries.push_back({"03FC032A005D02DF002703F002FA00EA000303C6", "smelly fruit" });
entries.push_back({"03FC000303B70045000303C9002703F002FA00EA000303C6", "sticky fruit" });
entries.push_back({"02FD021603FC000303BD00A80006039003F002FA00EA000303C6", "roasted fruit" });
entries.push_back({"0321012302EE033F00A8000303C6", "walnut" });
entries.push_back({"03D802F40087000303D50321012302EE033F00A8000303C6", "cracked walnut" });
entries.push_back({"03FC000303B101B0000303C900270402005D02EE", "spiky shell" });
entries.push_back({"03FC000303B101AD033900270402005D02EE", "spiny shell" });
entries.push_back({"0360006903FC033F00A8000303C6", "chestnut" });
entries.push_back({"036F002400030360033F00C9000303C6", "beach nut" });
entries.push_back({"03D50213000303CF00A5033F00C9000303C6", "coconut" });
entries.push_back({"042C018F000303D502D60348", "acorn" });
entries.push_back({"03C3021603FC000303BD00A800060384018F000303D502D60348", "toasted acorn" });
entries.push_back({"03F002EB01950042034E018F000303D502D60348", "flying acorn" });
entries.push_back({"042C018F000303D502D60348000303C3014D000303B4", "acorn top" });
entries.push_back({"036600C603360006037B0216040202FA00E70336", "jumbo mushroom" });
entries.push_back({"02FD021603FC000303BD00A8000603900006036600A503360006037B0213", "roasted jumbo" });
entries.push_back({"039002F1002103270027040202FA00E70336", "dreamy mushroom" });
entries.push_back({"03C602F700CC03F0009F02EE000303C3014D000303B4", "truffle top" });
entries.push_back({"037E02E800ED040202FA00E70336", "blue mushroom" });
entries.push_back({"0411014D000303C6040202FA00E70336", "hot mushroom" });
entries.push_back({"02F4006600060390040202FA00E70336", "red mushroom" });
entries.push_back({"03FC00C603390027040202FA00E70336", "sunny mushroom" });
entries.push_back({"032D00CC040202FA00E70336", "mushroom" });
entries.push_back({"0411014D000303C6032D00CC040202FA00E70336", "hot mushroom" });
entries.push_back({"02EB01B0000303C60006037500C002EE0006037E", "light bulb" });
entries.push_back({"02EB01B0000303C600060378010202EE0006037E", "light bulb" });
entries.push_back({"03CF00C9000303B4000303CC018F000303D8", "cupcake" });
entries.push_back({"03840174002703DB0024", "daisy" });
entries.push_back({"03A50045000303C000E70339030900A8", "petunia" });
entries.push_back({"03C000E102E500A8000303B4", "tulip" });
entries.push_back({"03C000E102DF0045000303B4", "tulip" });
entries.push_back({"03840084034800060387009F02EB019B00A50348", "dandelion" });
entries.push_back({"03840084034800060381001B02EB019B00A50348", "dandelion" });
entries.push_back({"037E02E800EA00060372005D02EE", "bluebell" });
entries.push_back({"03FC000303CF00C60348000303D80006037E02EB015003FC00A50336", "skunk blossom" });
entries.push_back({"03FC00C6034803F002EB01DD0234", "sunflower" });
entries.push_back({"02DF003C02DF0024", "lily" });
entries.push_back({"02FD021603DE0006037500C900060390", "rose bud" });
entries.push_back({"02F400660006039002FD021603DE", "red rose" });
entries.push_back({"0375009F02E800E70348", "balloon" });
entries.push_back({"03B10213000303CC018F00060381004803FC000303D8", "poke disc" });
entries.push_back({"036F0024000303600006037B012302EE", "beach ball" });
entries.push_back({"0321012C000303BD02190042035A000303CC00840348", "watering can" });
entries.push_back({"0321012C000303BD02190042035A0006036600C9000603A2", "watering jug" });
entries.push_back({"0306005D02EB02130006037B012302EE", "yellow ball" });
entries.push_back({"03600255000303D5020A02EE", "charcoal" });
entries.push_back({"02DF002703F004110315004803FC009F02EE", "leaf whistle" });
entries.push_back({"041102520333014A03390045000303CF00A8", "harmonica" });
entries.push_back({"03C602F700C60336000303A80066", "trumpet" });
entries.push_back({"03C602FA01080336000303AB00A8000303C6", "trumpet" });
entries.push_back({"037500A5033C0084033F00A8000303A5000F009F02EE", "banana peel" });
entries.push_back({"032A018F0006039900AB03F002100348", "megaphone" });
entries.push_back({"039F020A02EE00060390000303D501CE0348", "gold coin" });
entries.push_back({"0360014D000303CF009F02E500A8000303C6000303D501CE0348", "chocolate coin" });
entries.push_back({"0402014D000303D802E500A8000303C6000303D501CE0348", "chocolate coin" });
entries.push_back({"03F9003C02EE03EA0234000303D501CE0348", "silver coin" });
entries.push_back({"03D5014D000303AB0234000303D501CE0348", "copper coin" });
entries.push_back({"02FA00EA0006036F0024", "ruby" });
entries.push_back({"03FC008A03F001AA0300", "sapphire" });
entries.push_back({"03FC008A03F0019B0234", "sapphire" });
entries.push_back({"03C30213000303A8008A03DE", "topaz" });
entries.push_back({"02F40066000603900333025500060375009F02EE", "red marble" });
entries.push_back({"037E02E800E70333025500060375009F02EE", "blue marble" });
entries.push_back({"0306005D02EB02100333025500060375009F02EE", "yellow marble" });
entries.push_back({"02FA00EA0006036F001E02F10042035A", "ruby ring" });
entries.push_back({"037B014D00060387009F02EE000303CC0087000303B402F10042035A", "bottle cap ring" });
entries.push_back({"03B101AA02F700A8000303C603FC02D900060390", "pirate sword" });
entries.push_back({"03B101AA02F10045000303C603FC02D900060390", "pirate sword" });
entries.push_back({"03C301D403FC0126030000060390", "toy sword" });
entries.push_back({"037502340006039003F00069036C0234", "bird feather" });
entries.push_back({"037B020A02EE000303C6", "bolt" });
entries.push_back({"032A0087000603A203390045000303C6", "magnet" });
entries.push_back({"032A018F000603A203390045000303C6", "magnet" });
entries.push_back({"0333025500060375009F02EE", "marble" });
entries.push_back({"03D802F4018F000303C6", "crate" });
entries.push_back({"03D50255000603900006037B02D9000603900006037B014D000303D803FC", "cardboard box" });
entries.push_back({"03CF00A503360405000F0234", "come here" });
entries.push_back({"043B021603EA022804050297", "over here" });
entries.push_back({"040B009F02EB0213", "hello" });
entries.push_back({"039C010B00060390034501950024000303C6", "good night" });
entries.push_back({"039900A5034501B0000303C6", "good night" });
entries.push_back({"03F6018C035A000303C9030C00EA", "thank you" });
entries.push_back({"038A00ED03FC00C6033603F30042035A", "do something" });
entries.push_back({"02DF004803FC00A50348000303BD00A503270024", "listen to me" });
entries.push_back({"03A500090024000303CF00A8", "pi ka" });
entries.push_back({"039F0213000603930045000303BD00A8000303C6", "go get it" });
entries.push_back({"036C0087000303C603FC03F001AD0348", "thats fine" });
entries.push_back({"043B0213000303CC01740024", "ok" });
entries.push_back({"04020276", "sure" });
entries.push_back({"02FD01B0000303C6", "right" });
entries.push_back({"02E2006903FC0006038A00ED036C0087000303C6", "lets do that" });
entries.push_back({"0345014D000303C6036C0087000303C3031B00C60348", "not that one" });
entries.push_back({"036C0087000303C603DE02FD0129035A", "thats wrong" });
entries.push_back({"0372008700060390000303B10213000303CC018C0333014A0348", "bad pokemon" });
entries.push_back({"038D02100348000303C60006038A00ED036C0087000303C6", "dont do that" });
entries.push_back({"042900420348000303CF021C0066000303D8000303C6", "incorrect" });
entries.push_back({"03CF00C9000303BD00A8000303C301F2000303C6", "cut it out" });
entries.push_back({"03450213", "no" });
entries.push_back({"0318018F0006038700A80006039F0213", "way to go" });
entries.push_back({"03F002EB01DD0234", "flower" });
entries.push_back({"038400840348000303C603FC", "dance" });
entries.push_back({"03F602FD01F80045000303C6", "throw it" });
entries.push_back({"03C3015003F90045000303C6", "toss it" });
entries.push_back({"030C00EA000303CC008403390024000303C6036C0087000303C6", "you can eat that" });
entries.push_back({"03BA019203FC000303B70045000303C6", "taste it" });
entries.push_back({"041101F503DB0045000303C6000303BA019203FC000303C6", "hows it taste" });
entries.push_back({"041101F503DB0045000303C603FC032A005D02EE", "hows it smell" });
entries.push_back({"041101F503DB0045000303C603FC01EF034800060390", "hows it sound" });
entries.push_back({"0411031B00A8000303C60006038700AB03DB0045000303C60006038A00EA", "what does it do" });
entries.push_back({"03B402E201830411031B00A8000303C6", "play what" });
entries.push_back({"03C602FD01950045000303C6", "try it" });
entries.push_back({"03B402E201740045000303C6", "play it" });
entries.push_back({"039002FD014D000303A50045000303C6", "drop it" });
entries.push_back({"03A80066000303CF00A80003036000EA", "pikachu" });
entries.push_back({"030C00EA000303CC00840348000303BA019203FC000303B70045000303C6", "you can taste it" });
entries.push_back({"041101F503DB0045000303C603FC01EF0348", "hows it sound" });
entries.push_back({"03AE010B000303C6036C0087000303C6000603720087000303D8", "put that back" });
entries.push_back({"03FC000303BA018003150048036C03270024", "stay with me" });
entries.push_back({"03FC000303BA01770087000303C6033301A4041101F503FC", "stay at my house" });
entries.push_back({"03F90009030C00E102E2018F000303BD0234", "see you later" });
entries.push_back({"03F90009030C00EA", "see you" });
entries.push_back({"037B01B0", "bye" });
entries.push_back({"0411031B00A8000303BD0219030900A80006038A00CF0042035A", "what are you doing" });
entries.push_back({"0411031B00A8000303C603FC00C9000303B4", "whats up" });
entries.push_back({"0411031B00A8000303C603FC00C9000303B4036C02B8", "whats up there" });
entries.push_back({"042F0087000303AB009F02EE", "apple" });
entries.push_back({"033C006903EA0231033301AD034800060390", "never mind" });
entries.push_back({"039C010B00060390034501B0000303C6", "good night" });
entries.push_back({"03F60084035A000303C9030C00EA", "thank you" });
entries.push_back({"04290045000303C603DE02F700C603390042035100990318018F", "its running away" });
entries.push_back({"03F002EB01DD02340006037500C900060390", "flower bud" });
entries.push_back({"03BA008700060393030902190045000303C6", "tag you're it" });
entries.push_back({"039F01FE00BA0318018F", "go away" });
entries.push_back({"02E8010B000303D5021603EA0237036C02B8", "look over there" });
entries.push_back({"04290045000303C603FC021603EA0237036C02B8", "its over there" });
entries.push_back({"02DF003C02DF0024", "lily" });
entries.push_back({"03FC00C6034803F002EB01DD0234", "sunflower" });
entries.push_back({"03FC000303CF00C60348000303D80006037E02EB015003FC014A0336", "skunk blossom" });
entries.push_back({"03FC000303C602FD016E00060372029D0024", "strawberry" });
entries.push_back({"02F4008A03FC000303B402F10024", "raspberry" });
entries.push_back({"0438012C0006038100480402", "odd ish" });
entries.push_back({"03A202E800E70336", "gloom" });
entries.push_back({"03EA01A702EE000303B402E800E70336", "vile plume" });
entries.push_back({"042F01AD033603FC02BE0024", "im sorry" });
entries.push_back({"03FC02BE0024", "sorry" });
entries.push_back({"03CC0084033F00A50348", "cannon" });
entries.push_back({"03810045000603930045000303C301F2000303C6", "dig it out" });
entries.push_back({"03810045000603A2036C017A0234", "dig there" });
entries.push_back({"03810045000603A2", "dig" });
entries.push_back({"03AE010202EE", "pull" });
entries.push_back({"033F00C9000303C6", "nut" });
entries.push_back({"03780108033C0084033F00C9", "banana" });
entries.push_back({"03C602F4006903E4023400030360006903FC000303C6", "treasure chest" });
entries.push_back({"03C602F4006903E40234", "treasure" });
entries.push_back({"0372029D002400060390000303C602F4006903E40234", "buried treasure" });
entries.push_back({"0408005D02EB0213", "hello" });
entries.push_back({"042F01A702E500CC03E7030C00EA", "i love you" });
entries.push_back({"04080084035701290348", "hang on" });
entries.push_back({"03C602F40066000603660234", "treasure" });
entries.push_back({"03960066000303C602EB015003FC000303C6", "get lost" });
entries.push_back({"03A50024000303CF00BD040B00A8", "pee ka" });
entries.push_back({"03A500090024000303CF00C9", "pi ka" });
entries.push_back({"0375009C041101AD034800060381030C00EA", "behind you" });
entries.push_back({"036F0018041101AD03480006036600EA", "behind you" });
entries.push_back({"041101EF032A006303390024", "how many" });
entries.push_back({"041101EF032A0063033900150258036C02B8", "how many are there" });
entries.push_back({"03B1020A02DF001503180087000603A2", "poly wag" });
entries.push_back({"03B1014402DF001503180087000603A2", "poly wag" });
entries.push_back({"03B1020A02DF0015031B022B02EE", "poliwhirl" });
entries.push_back({"03FC000303D5031B0234000303BD009F02EE", "squirt el" });
entries.push_back({"0396008A03FC000303C602DF0024", "ghastly" });
entries.push_back({"041101290348000303BD0234", "haunt er" });
entries.push_back({"02FD0129035A", "wrong" });
entries.push_back({"036C0087000303C603DE02FD0129035A", "thats wrong" });
entries.push_back({"03D503150045000303C6", "quit" });
entries.push_back({"03CF00C9000303B700450006038D01F2000303C6", "cut it out" });
entries.push_back({"03CF00A503270297", "come here" });
entries.push_back({"03CF00A5033604050297", "come here" });
entries.push_back({"02E8010B000303D5021603EA022804050297", "look over here" });
entries.push_back({"02E8010B000303D501F2000303C6", "look out" });
entries.push_back({"0321012C0003036001F2000303C6", "watch out" });
entries.push_back({"036C02B8", "there" });
entries.push_back({"03FC03150042035A034501F2", "swing now" });
entries.push_back({"03FC03150042035A", "swing" });
entries.push_back({"039F020D02FD01B0000303C6", "go right" });
entries.push_back({"02FD01B0000303C6", "right" });
entries.push_back({"03F00258036C022E02FD01B0000303C6", "farther right" });
entries.push_back({"039F020A02E2006903F0000303C6", "go left" });
entries.push_back({"02E2006903F0000303C6", "left" });
entries.push_back({"03F00258036C022B02E2006903F0000303C6", "farther left" });
entries.push_back({"03FC000303C3014D000303B4", "stop" });
entries.push_back({"03FC000303C3014D000303B4034501F2", "stop now" });
entries.push_back({"03FC000303C3014D000303B4036C02B8", "stop there" });
entries.push_back({"03FC000303A50042033F00A202FD01EF034800060390", "spin around" });
entries.push_back({"02FD012903570318018F", "wrong way" });
entries.push_back({"03BD0231033F00A202FD01EF034800060390", "turn around" });
entries.push_back({"03720087000303CF00C9000303B4", "back up" });
entries.push_back({"03C90024000303B40006039F01F80042035A", "keep going" });
entries.push_back({"03FC000303C602F4018F00060387009C0408006600060390", "straight ahead" });
entries.push_back({"037500C002EE0006037500AB03FC02D9", "bulb a saur" });
entries.push_back({"03E70021033F00AB03FC02D9", "venus are" });
entries.push_back({"03FC02EB0213000303B10213000303D8", "slowpoke" });
entries.push_back({"03FC000303D5031B0234000303BD009F02EE", "squirt el" });
entries.push_back({"03600252032A00840348000603870234", "charmander" });
entries.push_back({"03C903060087000303BD0234000303A50024", "cater pie" });
entries.push_back({"02EB014D000303B402F700AB03FC", "lapras" });
entries.push_back({"02E20087000303B402F700AB03FC", "lapras" });
entries.push_back({"03C302130006039900A8000303A50024", "togepi" });
entries.push_back({"03C30213000603930045000303A500090024", "togepi" });
entries.push_back({"03A500420339030F012C0006038700A8", "pinata" });
entries.push_back({"03A500210339030F014D000303BD00A8", "pinata" });
entries.push_back({"02DF004803F900420348000303BD00A503270024", "listen to me" });
entries.push_back({"03F002FA00EA000303C6", "fruit" });
entries.push_back({"03450213000303C6000303A8008700060390", "notepad" });
entries.push_back({"042900420348000603A202F1002400060381000F00A50348000303C603FC", "ingredients" });
entries.push_back({"02F4006903FC00A8000303A50024", "recipe" });
entries.push_back({"02F4006903F90045000303A50024", "recipe" });
entries.push_back({"0411014D000303C603FC03150024000303AB00C9000303BA018F0006038D0213", "hot sweet potato" });
entries.push_back({"0411014D000303C603FC03150024000303B4000303BA018F0006038D0213", "hot sweet potato" });
entries.push_back({"03D200E102EE", "cool" });
entries.push_back({"03F001AD0348", "fine" });
entries.push_back({"0309023703FC0213000303C9030C00EA000303C6", "youre so cute" });
entries.push_back({"0393004803E70045000303C6000303C000E703270024", "give it to me" });
entries.push_back({"0393004203270027036C0087000303C6", "gimme that" });
entries.push_back({"03F602FD01F80045000303C6", "throw it" });
entries.push_back({"03FC000303C000EA000303A5004500060390", "stupid" });
entries.push_back({"02E20066000303C603FC000303B402E2018F", "lets play" });
entries.push_back({"039C0108033302D603390042035A", "good morning" });
entries.push_back({"0318018F000303CF00C9000303B4", "wake up" });
entries.push_back({"03960066000303BD00C9000303B4", "get up" });
entries.push_back({"04260024000303CF00A5034803DE", "e cans" });
entries.push_back({"042C0066000303CF00A5034803DE", "e cans" });
entries.push_back({"037E02F10042034B0045000303C604050297", "bring it here" });
entries.push_back({"030C00EA000303CF00A503390024000303C6036C0087000303C6", "you can eat that" });
entries.push_back({"03BA019203FC000303BD00A8000303C6", "taste it" });
entries.push_back({"04260024000303B70045000303C6", "eat it" });
entries.push_back({"032A0087000603A2033F00A8000303C6", "magnet" });
entries.push_back({"03D501CE0348", "coin" });
entries.push_back({"036600D5009F02EE", "jewel" });
entries.push_back({"0333025500060375009F02EE", "marble" });
entries.push_back({"03B101AA02F10045000303C603FC01", "pirate sword" });
entries.push_back({"039C0108034501B0000303C6", "good night" });
entries.push_back({"03D50315004803DE000303C301AD0336", "quiz time" });
entries.push_back({"03B7002703E70024", "tv" });
entries.push_back({"042F01B0000303D503150045000303C6", "i quit" });
entries.push_back({"042F01AD03360006038700C60348", "im done" });
entries.push_back({"030C00EA000303CF00A50348000303B402E2018F", "you can play" });
entries.push_back({"03150024000303CF00A50348000303B402E2018F", "we can play" });
entries.push_back({"0372008700060390", "bad" });
entries.push_back({"0345014D000303C90045000303C3012F03F0", "knock it off" });
entries.push_back({"03450213000303B402E201740042035A", "no playing" });
entries.push_back({"03FC000303C3014D000303B4000303B402E201740042035A", "stop playing" });
entries.push_back({"042F01AD03360345014D000303C6000303B402E201740042035A", "im not playing" });
entries.push_back({"03D503150045000303C6", "quit" });
entries.push_back({"03FC000303C3014D000303B4036C0087000303C6", "stop that" });
entries.push_back({"03D802DF002103390045000303BD00C9000303B4", "clean it up" });
entries.push_back({"03AE010B000303B70045000303BD00990318018F", "put it away" });
entries.push_back({"03D802DF0021033F00C9000303B4", "clean up" });
entries.push_back({"03D802DF00210348036C0087000303BD00C9000303B4", "clean that up" });
entries.push_back({"03B70048040200EA", "tissue" });
entries.push_back({"037500C002EE0006037500AB03FC02D9", "bulb a saur" });
entries.push_back({"042F01B303E7002703FC02D9", "ivy saur" });
entries.push_back({"042F01B303EA00AB03FC02D9", "ivy saur" });
entries.push_back({"03E70021033F00AB03FC02D9", "venus are" });
entries.push_back({"03600252032A00840348000603870234", "char mander" });
entries.push_back({"036002520327001B02DF0009030900A50348", "char me leon" });
entries.push_back({"0360025803DE025500060390", "chari z ard" });
entries.push_back({"0360024000AB03DE025500060390", "chari z ard" });
entries.push_back({"03FC000303D5031B0234000303BD009F02EE", "squirt el" });
entries.push_back({"03210255000303BD0234000303BD009F02EE", "war tor tell" });
entries.push_back({"03210255000303C302D9000303BD009F02EE", "war tor tell" });
entries.push_back({"037E02E2008A03FC000303C301D403FC", "blast oise" });
entries.push_back({"03CC0087000303BD0234000303A50024", "cater pie" });
entries.push_back({"032A0066000303BD00A8000303B1014D00060390", "meta pod" });
entries.push_back({"037500C9000303BD023703F002F10024", "butter free" });
entries.push_back({"0315002400060387009F02EE", "weed el" });
entries.push_back({"03D2010B000303D200E7033F00A8", "ka kuna" });
entries.push_back({"03C90045000303D200E7033F00A8", "ka kuna" });
entries.push_back({"036F00240006039002F1003C02EE", "bee drill" });
entries.push_back({"036F00240006039002F7009F02EE", "bee drill" });
entries.push_back({"03A5004500060366014D000303C6", "pid gee ot" });
entries.push_back({"02F40087000303BD00A8000303BD00A8", "rat tata" });
entries.push_back({"02F700A8000303BA00870006038700A8", "rat tata" });
entries.push_back({"02F40087000303BA00870006038700A8", "rat tata" });
entries.push_back({"02F40087000303B70045000303CC018F000303C6", "rat i cat" });
entries.push_back({"03FC000303A502880213", "spear ow" });
entries.push_back({"03ED02880213", "fear ow" });
entries.push_back({"04260024000303CF00A5034803DE", "e cans" });
entries.push_back({"042C0066000303CF00A5034803DE", "e cans" });
entries.push_back({"043802550006037B014D000303D8", "ar bok" });
entries.push_back({"03A50024000303CF00A80003036000EA", "pikachu" });
entries.push_back({"02FD01B00003036000EA", "rye chu" });
entries.push_back({"03FC00840348040202FA00EA", "sand shrew" });
entries.push_back({"03FC0084034803FC02E2008A0402", "sand slash" });
entries.push_back({"0339004500060387021F00A5034803ED0021032A018602EE", "ni doran female" });
entries.push_back({"033900450006038D020D02F700A5034803ED0021032A017A009F02EE", "ni doran female" });
entries.push_back({"033900450006038702190021033F00A8", "ni door ina" });
entries.push_back({"033900240006038D0213000303D5031500210348", "nido queen" });
entries.push_back({"033900450006038D020D02F700A50348032A018602EE", "ni doran male" });
entries.push_back({"0339004500060387021F00A50348032A017A009F02EE", "ni doran male" });
entries.push_back({"033900450006038D02BE002103450213", "ni dor ino" });
entries.push_back({"033900240006038D020D02F1002103450213", "ni dor ino" });
entries.push_back({"033900240006038D0213000303C90042035A", "ni do king" });
entries.push_back({"03D802E2006903F0008102F10024", "cle fairy" });
entries.push_back({"03D802E500AB03F0008102F10024", "cle fairy" });
entries.push_back({"03D802E2006903F0018F00060375009F02EE", "cle fable" });
entries.push_back({"03D802E500AB03F0018F00060375009F02EE", "cle fable" });
entries.push_back({"03EA009F02EE000303A50045000303D803FC", "vol pix" });
entries.push_back({"034501AD0348000303BA018602EE03DE", "nine tales" });
entries.push_back({"03630045000603A202DF0024000303AB00CC03F0", "jiggly puff" });
entries.push_back({"0363004500060399009F02DF0024000303AB00CC03F0", "jiggly puff" });
entries.push_back({"03150045000603A202DF0024000303BD00CC03F0", "wiggly tuff" });
entries.push_back({"03DE00EA000603720087000303C6", "zoo bat" });
entries.push_back({"039F020A02EE000603720087000303C6", "goal bat" });
entries.push_back({"0438012C0006038100480402", "odd ish" });
entries.push_back({"03A202E800E70336", "gloom" });
entries.push_back({"03EA01A702EE000303B402E800E70336", "vile plume" });
entries.push_back({"03B1024000AB03FC", "paras" });
entries.push_back({"03A802A300AB03FC", "paras" });
entries.push_back({"03B1024000AB03FC0066000303D8000303C6", "para sect" });
entries.push_back({"03A802A300AB03FC0066000303D8000303C6", "para sect" });
entries.push_back({"03EA006303450210033C0087000303C6", "ven on at" });
entries.push_back({"03EA0063034502100333012F03F6", "venom oth" });
entries.push_back({"03810045000603A202E500A8000303C6", "dig let" });
entries.push_back({"0327001501F503F6", "meow eth" });
entries.push_back({"03AB023703E400A50348", "persian" });
entries.push_back({"03FC01B00006038700C9000303D8", "psy duck" });
entries.push_back({"039C010202EE0006038700C9000303D8", "goal duck" });
entries.push_back({"032A0084035A000303C90024", "man key" });
entries.push_back({"03B402FD01AD032A018F000303B4", "prime ape" });
entries.push_back({"03A202FD020A02EB01B3036C", "growl ith" });
entries.push_back({"03A202FD01E902DF0048036C", "growl ith" });
entries.push_back({"04380255000303CC018C034501AD0348", "ar canine" });
entries.push_back({"04380255000303CF00A5034501AD0348", "ar canine" });
entries.push_back({"03B1020A02DF001503180087000603A2", "poly wag" });
entries.push_back({"03B1020A02DF0015031B022B02EE", "poly whirl" });
entries.push_back({"03B1020A02DF001E02F4008A03F6", "poly wrath" });
entries.push_back({"03B1014402DF001E02F4008A03F6", "poly wrath" });
entries.push_back({"042F00870006037E02F700A8", "abra" });
entries.push_back({"03CF00A80006038400870006037E02F700A8", "ka dab ra" });
entries.push_back({"042F007E02E500A8000303CF00AB03DE00840336", "ala ka zam" });
entries.push_back({"032D00A800030360014D000303B4", "ma chop" });
entries.push_back({"032D00A8000303600213000303D8", "ma choke" });
entries.push_back({"032D00A80003036000840336000303B4", "ma champ" });
entries.push_back({"0372005D02EE03FC000303B402FD01F2000303C6", "bell sprout" });
entries.push_back({"03BA0063033F00A8000303CF00C002EE", "ten ta cool" });
entries.push_back({"03BA0063033F00A8000303D802FA00E102EE", "ten ta cruel" });
entries.push_back({"03630009030F02130006038A00EA00060390", "geo dude" });
entries.push_back({"03A202F4008A03EA009F02E50234", "gravel er" });
entries.push_back({"03A202F4008A03EA02E50234", "gravel er" });
entries.push_back({"039F020A02E500A50336", "golem" });
entries.push_back({"039F014402EE0336", "golem" });
entries.push_back({"03B1021003390024000303BD00A8", "pony ta" });
entries.push_back({"03B1021003390024000303C3016E", "pony ta" });
entries.push_back({"02F40087000303A5004500060384008A0402", "rap e dash" });
entries.push_back({"03FC02EB0213000303B10213000303D8", "slowpoke" });
entries.push_back({"03FC02EB02130006037E02FD0213", "slow bro" });
entries.push_back({"032A0087000603A2033F00A5033301B0000303C6", "mag ne mite" });
entries.push_back({"032A0087000603A2033F00A8000303C3014A0348", "mag ne ton" });
entries.push_back({"03F0025803F0006600030360000303C6", "far fetched" });
entries.push_back({"038D02130006039002F100150213", "dod rio" });
entries.push_back({"03F9001B02EE", "seel" });
entries.push_back({"038A00EA0006039F014A035A", "dew gong" });
entries.push_back({"038A00EA0006039F014A0348", "dew gong" });
entries.push_back({"03A202FD01AD032D0234", "grim er" });
entries.push_back({"032D00C9000303D8", "muck" });
entries.push_back({"0402005D02EE000603870234", "shell der" });
entries.push_back({"03D802EB01D403FC000303BD0234", "cloy ster" });
entries.push_back({"0396008A03FC000303C602DF00", "ghastly" });
entries.push_back({"0396008A03FC02DF0024", "ghastly" });
entries.push_back({"041101290348000303BD0234", "haunt er" });
entries.push_back({"03960084035A0006039F0255", "gen gar" });
entries.push_back({"0396006303480006039F0255", "gen gar" });
entries.push_back({"0438014A03390045000303D803FC", "on ix" });
entries.push_back({"039002FD01F503DB0024", "drowsy" });
entries.push_back({"039002FD021603DB0024", "drowsy" });
entries.push_back({"04050045000303B403450213", "hip no" });
entries.push_back({"03D802F400870006036F00", "crabby" });
entries.push_back({"03C90042035A02E50234", "king ler" });
entries.push_back({"03EA020A02EE000303C302D90006037E", "volt orb" });
entries.push_back({"0426001B02E20066000303D8000303C602FD021300060390", "electrode" });
entries.push_back({"0432009F02E20066000303D8000303C602FD021300060390", "electrode" });
entries.push_back({"042C0066000603A203DE000303C9030C00EA000303C6", "execute" });
entries.push_back({"042C0066000603A203DE0066000303C9030C00EA000303C302D9", "executor" });
entries.push_back({"042C0066000603A203FC00A8000303C9030C00EA000603870234", "executor" });
entries.push_back({"03C9030C00EA0006037B02100348", "cue bone" });
entries.push_back({"032A02A9020403180087000303D8", "mar oh wack" });
entries.push_back({"03330246020403180087000303D8", "mar oh wack" });
entries.push_back({"04050045000303C603330210034802DF0024", "hit mon lee" });
entries.push_back({"04050045000303C60333014A034802DF0024", "hit mon lee" });
entries.push_back({"04050045000303C60333021003480003036000840348", "hit mon chan" });
entries.push_back({"02DF0045000303C90024000303BD00A5035A", "lick eh tung" });
entries.push_back({"02DF0045000303C90045000303BD00A5035A", "lick i tung" });
entries.push_back({"02DF0045000303C90045000303C00108035A", "lick a tung" });
entries.push_back({"03D5015003ED0042035A", "coughing" });
entries.push_back({"0315002703DB0042035A", "wheezing" });
entries.push_back({"02FD01A4041102D60348", "rye horn" });
entries.push_back({"02FD01B00006038D01290348", "rye don" });
entries.push_back({"03600084034803F90024", "chance e" });
entries.push_back({"03BA0084034800060366005D02E500A8", "tangela" });
entries.push_back({"03BA018C034800060396005D02E500A8", "tangela" });
entries.push_back({"03CC018C035A0006039900AB03FC000303D5014A0348", "kang as khan" });
entries.push_back({"041102DC03F90024", "horse sea" });
entries.push_back({"03F900240006039002F700A8", "sea dra" });
entries.push_back({"039F020A02EE0006038100210348", "gold een" });
entries.push_back({"03F90024000303C90042035A", "seeking" });
entries.push_back({"03FC000303C3023A030C00EA", "starry you" });
entries.push_back({"03FC000303C3025203270024", "star me" });
entries.push_back({"0327004803FC000303BD0231033301AD0336", "mister mime" });
entries.push_back({"03FC01B3036C0234", "sigh ther" });
entries.push_back({"03630042035A000303D803FC", "jynx" });
entries.push_back({"0426001B02E20066000303D8000303BD00A80006037500CC03DE", "elect tra buzz" });
entries.push_back({"0432009F02E20066000303D8000303BD00A80006037500CC03DE", "elect tra buzz" });
entries.push_back({"032A0087000603A203330255", "mag mar" });
entries.push_back({"03A50042034803FC0234", "pin sir" });
entries.push_back({"03C3020D02FD012F03FC", "tar os" });
entries.push_back({"03C30246021603FC", "tar os" });
entries.push_back({"032A0087000603630045000303D50255000303B4", "magi karp" });
entries.push_back({"039602A300A80006038D015003FC", "guy a rad os" });
entries.push_back({"039602A300A80006038D021603FC", "guy a rad os" });
entries.push_back({"02EB014D000303B402F700AB03FC", "lap ras" });
entries.push_back({"02E20087000303B402F700AB03FC", "lap ras" });
entries.push_back({"03810045000303C30213", "ditto" });
entries.push_back({"0426002703E70024", "e v" });
entries.push_back({"03EA018F000303B102BE0015014A0348", "vapor eon" });
entries.push_back({"03EA00A8000303B102BE000F00A50348", "vapor eon" });
entries.push_back({"0366020A02EE000303B70015014A0348", "jolt eon" });
entries.push_back({"03F002E2029D0015014A0348", "flare eon" });
entries.push_back({"03B1020D02F100240006039F014A0348", "por e gon" });
entries.push_back({"03B1020D02F100240006039900A50348", "por e gon" });
entries.push_back({"043B0210032D00C6034501B0000303C6", "oman ite" });
entries.push_back({"04380129032D00A5034501B0000303C6", "oman ite" });
entries.push_back({"043B0210032D00CC03FC000303C30255", "oma star" });
entries.push_back({"04380129032D00AB03FC000303C30255", "oma star" });
entries.push_back({"03CF00C90006037800EA0006038D0213", "ka boo tow" });
entries.push_back({"03D5012C0006037800EA000303C3014D000303B403FC", "ka bu tops" });
entries.push_back({"03D5012C0006037500A8000303C3014D000303B403FC", "ka bu tops" });
entries.push_back({"03D5012C0006037500A8000303C3015003FC", "ka bu tops" });
entries.push_back({"042C02A90213000603840087000303D8000303BD00C002EE", "aero dac tell" });
entries.push_back({"03FC034502D002E20087000303D803FC", "snore lax" });
entries.push_back({"04380255000303B70045000303D200E703450213", "art eh cuno" });
entries.push_back({"03DE0087000303B40006038D015003FC", "zap dos" });
entries.push_back({"03DE0087000303B40006038D021603FC", "zap dos" });
entries.push_back({"0333020A02EE000303C602F4006903FC", "mol tres" });
entries.push_back({"039002F700A8000303B7002103390024", "duh rat ini" });
entries.push_back({"039002F400870006039900A5033C02B8", "dragonair" });
entries.push_back({"039002F400870006039900A5034501B0000303C6", "dragon ite" });
entries.push_back({"0327030C00EA000303C000EA", "mew two" });
entries.push_back({"0327030C00EA", "mew" });
entries.push_back({"03C3014D000303AB00AB03EA000603630045000603A202DF0024000303AB00AB03F0", "top of jiggly puff" });
entries.push_back({"03C302130006039900A8000303A50024", "toge pi" });
entries.push_back({"03C302130006039C010B000303A50024", "toge pi" });
entries.push_back({"03C30213000603930045000303A500090024", "toge pi" });
entries.push_back({"03B1014402DF001503180087000603A2", "poly wag" });
entries.push_back({"03150024000303A50042034800060372005D02EE", "weeping bell" });
entries.push_back({"03E70045000303D8000303C602F1002400060372005D02EE", "vic tree bell" });
entries.push_back({"03BA0063033F00A8000303D200E102EE", "ten ta cool" });
entries.push_back({"038700C9000603A2000303C602F100150213", "dug trio" });
entries.push_back({"03A50045000603630024", "pid gee" });
entries.push_back({"038D02130006038A00DB0213", "do duo" });
entries.push_back({"03A50045000603660213000303C30213", "pid gee otto" });
entries.push_back({"03CF00C9000303D200E7033F00A8", "ka kuna" });
entries.push_back({"03BA00630348000303BD00A8000303D200E102EE", "ten ta cool" });
entries.push_back({"03CC018C035A00060396008A03FC000303D5014A0348", "kang as khan" });
entries.push_back({"043B0210032D00AB03FC000303C30255", "oma star" });
entries.push_back({"03CF00A80006037800EA000303C3014D000303B403FC", "ka boo tops" });
entries.push_back({"036C0087000303C603FC02FD01B0000303C6", "thats right" });
entries.push_back({"036C0087000303C603FC0006039C010B00060390", "thats good" });
entries.push_back({"036C0087000303C3031B00C60348", "that one" });
entries.push_back({"036C008A03FC03F001AD0348", "thats fine" });
entries.push_back({"036C0087000303C603DE03F001AD0348", "thats fine" });
entries.push_back({"03CF021C0066000303D8000303C6", "correct" });
entries.push_back({"03CF00A202F40066000303D8000303C6", "correct" });
entries.push_back({"036F0042035A0006039F0213", "bingo" });
entries.push_back({"03D5012302DF0045000303C6", "call it" });
entries.push_back({"02E2006903FC000303B402E2018F", "lets play" });
entries.push_back({"02FD0129035A", "wrong" });
entries.push_back({"0372008700060390000303A50024000303CF00A80003036000EA", "bad pikachu" });
entries.push_back({"0327004803FC", "miss" });
entries.push_back({"038D02100348000303C6000303D5012302DF0045000303C6", "dont call it" });
entries.push_back({"041101F503FC", "house" });
entries.push_back({"041102100336", "home" });
entries.push_back({"03EA00A202F1004500060381000F00C60348", "viridian" });
entries.push_back({"03EA00A202F1004500060381000F00C6034803F002C400AB03FC000303C6", "viridian forest" });
entries.push_back({"043B0213000303CF0234", "ochre" });
entries.push_back({"043B0213000303CF0225031E010B0006039003DE", "ochre woods" });
entries.push_back({"043B0213000303CF023703ED004803FF0042035A0411020A02EE", "ochre fishing hole" });
entries.push_back({"03FC000303B402F10042035A02DF002703F0", "spring leaf" });
entries.push_back({"03FC000303B402F10042035A02DF002703F003ED000F00C002EE00060390", "spring leaf field" });
entries.push_back({"0438014402E500AB03EA01AD0348", "olivine" });
entries.push_back({"0438014402E500AB03EA01AD034802E2018F000303D8", "olivine lake" });
entries.push_back({"0438014402E500AB03EA01AD034803ED004803FF0042035A0411020A02EE", "olivine fishing hole" });
entries.push_back({"03D502130006037B012302EE000303C6", "cobalt" });
entries.push_back({"03D502130006037B012302EE000303C301A702E500C6034800060390", "cobalt island" });
entries.push_back({"03D502130006037E03ED004803FF0042035A0411020A02EE", "cobalt fishing hole" });
entries.push_back({"03D5021603FC000303C6", "coast" });
entries.push_back({"03D502130006037B012302EE000303C6000303D5021603FC000303C6", "cobalt coast" });
entries.push_back({"03FC000303A80069040200C002EE000303C602F4018C03390042035A", "special training" });
entries.push_back({"03BD0231033F00A8000303B4", "turnip" });
entries.push_back({"03BD02310348000303B4", "turnip" });
entries.push_back({"03FC03150024000303C6000303AB00A8000303BA018F0006038D0213", "sweet potato" });
entries.push_back({"0411014D000303C603FC03150024000303C6000303AE010B000303BA018F0006038D0213", "hot sweet potato" });
entries.push_back({"03D501470300000603900006037B02D9000603900006037B014D000303D803FC", "cardboard box" });
entries.push_back({"04080084034B00420348036C02B8", "hang in there" });
entries.push_back({"03AE010202EE", "pull" });
entries.push_back({"02F1001B02DF0045000303B700420348", "reel it in" });
entries.push_back({"034501F2", "now" });
entries.push_back({"03CC00870003035D0045000303C6", "catch it" });
entries.push_back({"03960066000303B70045000303C6", "get it" });
entries.push_back({"03AE010202DF0045000303C6", "pull it" });
entries.push_back({"03AE010202EE04110255000603870234", "pull harder" });
entries.push_back({"02E20066000303B70045000303C60006039F0213", "let it go" });
entries.push_back({"02F1003C02DF002703F90045000303C6", "release it" });
entries.push_back({"02E500C6034800030360", "lunch" });
entries.push_back({"03FC033C0087000303D8", "snack" });
entries.push_back({"02E2006903F90024000303C6", "lets eat" });
entries.push_back({"03CF00C9000303B4000303CC018F000303D8", "cupcake" });
entries.push_back({"042F019B00C6034800060387023703FC000303BA0084034800060390", "i understand" });
entries.push_back({"042F01B0000603930045000303B70045000303C6", "i get it" });
entries.push_back({"0411032101B0", "why" });
entries.push_back({"041101F2000303CF00C60336", "how come" });
entries.push_back({"039C010B0006037B01B0", "good bye" });
entries.push_back({"03BA018F000303D8000303CC02B8", "take care" });
entries.push_back({"042F019B009F02EE0327004803F9030C00EA", "ill miss you" });
entries.push_back({"0438016502EE0327004803F9030C00EA", "ill miss you" });
entries.push_back({"03FC000303C3014D000303B4036C0087000303C6", "stop that" });
entries.push_back({"03D503150045000303C6", "quit" });
entries.push_back({"03CF00C9000303B70045000303C301F2000303C6", "cut it out" });
entries.push_back({"03CF00A503330129034802E20066000303C603DE0006039F0213", "come on lets go" });
entries.push_back({"02E20066000303C603DE0006039F0213", "lets go" });
entries.push_back({"031B0225012F03F0", "we re off" });
entries.push_back({"03BA008700060393030902190045000303C6", "tag youre it" });
entries.push_back({"03CF00C9000303B70045000303C301F2000303C6", "cut it out" });
entries.push_back({"0411031B00A8000303C603FC02FD0129035A", "whats wrong" });
entries.push_back({"0411031B00A8000303B7004803F90045000303C6", "what is it" });
entries.push_back({"03CF00C603330129034802E20066000303C603DE0006039F0213", "come on lets go" });
entries.push_back({"031502970006039F01F80042035A034501F2", "were going now" });
entries.push_back({"02E20066000303C603FC000303600066000303C90045000303C301F2000303C6", "lets check it out" });
entries.push_back({"03F600C6033F02370402014D000303D8", "thunder shock" });
entries.push_back({"03F600C6033F02340006037B020A02EE000303C6", "thunderbolt" });
entries.push_back({"043801290339030300420348", "onion" });
entries.push_back({"03FC02DF0024000303B4000303C301B0000303C6", "sleep tight" });
entries.push_back({"03F90009030C00EA000303C000E7033302460213", "see you tomorrow" });
entries.push_back({"03F90009030C00CF00420348036C00C6033302D603390042035A", "see you in the morning" });
entries.push_back({"039F0213000303BD00C6033302460213", "go tomorrow" });
entries.push_back({"02FD014D000303D8", "rock" });
entries.push_back({"03F9004803DE023703FC", "scissors" });
entries.push_back({"03A8018F000303AB0234", "paper" });
entries.push_back({"0381002A000303B10255000303C6", "depart" });
entries.push_back({"02F10006038100EA03DE00030384002A000303B10255000303C6", "reduced depart" });
entries.push_back({"03D5012F035D0063034800030381002A000303B10255000303C6", "caution depart" });
entries.push_back({"02DF03FC03BD023A000603D8000303B700060381002A000303B10255000303C6", "restricted depart" });
entries.push_back({"03B1008A03FC0042035A", "passing" });
entries.push_back({"03FC000303C3014D000303AB0042035A", "stopping" });
entries.push_back({"031E02DC03390042035A", "warning" });
entries.push_back({"03AB02FA021603F9000900060390", "proceed" });
entries.push_back({"02F10006038100EA03DE00060390", "reduced" });
entries.push_back({"03D5012F035D00630348", "caution" });
entries.push_back({"02DF03FC03BD023A000603D8000303B700060390", "restricted" });
entries.push_back({"042C0066000603A203FC000303AB021C005A03DE", "express" });
entries.push_back({"02E50042032A002A000303C6", "limit" });
entries.push_back({"03450213000602E50042032A002A000303C6", "no limit" });
entries.push_back({"03B7005A0348", "ten" });
entries.push_back({"03E7002A03F6000303B700090348", "fifteen" });
entries.push_back({"03C30318004B0339038A0024", "twenty" });
entries.push_back({"03C30318004B0339038A002403EA019E03EA", "twenty five" });
entries.push_back({"036C02AC03BA0027", "thirty" });
entries.push_back({"036C02AC03BA002703EA019E03EA", "thirty five" });
entries.push_back({"03EA02D6000603900048", "forty" });
entries.push_back({"03EA02D600060390004803EA019E03EA", "forty five" });
entries.push_back({"03F3005A03F0000303B70042", "fifty" });
entries.push_back({"03F3005A03F0000303B7004203EA019E03EA", "fifty five" });
entries.push_back({"03F9002A000303D803FC000303C00009", "sixty" });
entries.push_back({"03F9002A000303D803FC000303C0000903EA019E03EA", "sixty five" });
entries.push_back({"03FC004B036C00630348000303B70009", "seventy" });
entries.push_back({"03FC004B036C00630348000303B7000903EA019E03EA", "seventy five" });
entries.push_back({"042C018C03B70009", "eighty" });
entries.push_back({"042C018C03B7000903EA019E03EA", "eighty five" });
entries.push_back({"034501A103480006038A0048", "ninety" });
entries.push_back({"034501A103480006038A004803EA019E03EA", "ninety five" });
entries.push_back({"031B00C60348040B00BD0348038702F100060390", "one hundred" });
entries.push_back({"031B00C60348021303F001AD03E7", "one oh five" });
entries.push_back({"031B00C60348000303B7005A0348", "one ten" });
entries.push_back({"031B00C60348000303E7002A03F6000303B700090348", "one fifteen" });
entries.push_back({"031B00C60348000303C303180348000303B70024", "one twenty" });
entries.push_back({"031B00C60348000303C303180348000303B7002403EA019E03EA", "one twenty five" });
entries.push_back({"82B582E382C182CF82C282B582F182B182A4", "depart" });
entries.push_back({"82B582E382C182CF82C282B082F182BB82AD", "reduced depart" });
entries.push_back({"82B582E382C182CF82C282BF82E382A482A2", "caution depart" });
entries.push_back({"82B582E382C182CF82C282AF82A282A982A2", "restricted depart" });
entries.push_back({"82C282A482A9", "passing" });
entries.push_back({"82C482A282B582E1", "stopping" });
entries.push_back({"82AF82A282D982A482A082A9", "warning" });
entries.push_back({"82B582F182B182A4", "proceed" });
entries.push_back({"82B082F182BB82AD", "reduced" });
entries.push_back({"82BF82E382A482A2", "caution" });
entries.push_back({"82AF82A282A982A2", "restricted" });
entries.push_back({"82C482A282B5", "stop" });
entries.push_back({"82B182A482BB82AD", "no limit" });
entries.push_back({"82B982A282B082F1", "limit" });
entries.push_back({"82A982A282B682E5", "cancel" });
entries.push_back({"82B682E382A4", "ten" });
entries.push_back({"82B682E382A482B2", "fifteen" });
entries.push_back({"82C982B682E382A4", "twenty" });
entries.push_back({"82C982B682E382A482B2", "twenty five" });
entries.push_back({"82B382F182B682E382A4", "thirty" });
entries.push_back({"82B382F182B682E382A482B2", "thirty five" });
entries.push_back({"82E682F182B682E382A4", "forty" });
entries.push_back({"82E682F182B682E382A482B2", "forty five" });
entries.push_back({"82B282B682E382A4", "fifty" });
entries.push_back({"82B282B682E382A482B2", "fifty five" });
entries.push_back({"82EB82AD82B682E382A4", "sixty" });
entries.push_back({"82EB82AD82B682E382A482B2", "sixty five" });
entries.push_back({"82C882C882B682E382A4", "seventy" });
entries.push_back({"82C882C882B682E382A482B2", "seventy five" });
entries.push_back({"82CD82BF82B682E382A4", "eighty" });
entries.push_back({"82CD82BF82B682E382A482B2", "eighty five" });
entries.push_back({"82AB82E382A482B682E382A4", "ninety" });
entries.push_back({"82AB82E382A482B682E382A482B2", "ninety five" });
entries.push_back({"82D082E182AD", "one hundred" });
entries.push_back({"82D082E182AD82B2", "one oh five" });
entries.push_back({"82D082E182AD82B682E382A4", "one ten" });
entries.push_back({"82D082E182AD82B682E382A482B2", "one fifteen" });
entries.push_back({"82D082E182AD82C982B682E382A4", "one twenty" });
entries.push_back({"82D082E182AD82C982B682E382A482B2", "one twenty five" });
return entries;
}
+24
View File
@@ -0,0 +1,24 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef VRU_WORDS_HPP
#define VRU_WORDS_HPP
#include <string>
#include <vector>
struct VRUWordEntry
{
std::string hex;
std::string words;
};
std::vector<VRUWordEntry> GetVRUWordEntries(void);
#endif // VRU_WORDS_HPP
+4 -3
View File
@@ -33,9 +33,10 @@ enum class N64ControllerButton
enum class InputDeviceType
{
None = -3,
Automatic = -2,
Keyboard = -1
EmulateVRU = -4,
None = -3,
Automatic = -2,
Keyboard = -1,
};
enum class InputType
+357 -52
View File
@@ -13,16 +13,22 @@
#include <UserInterface/MainDialog.hpp>
#include "Thread/SDLThread.hpp"
#include "Thread/HotkeysThread.hpp"
#include "Utilities/InputDevice.hpp"
#include "common.hpp"
#ifdef VRU
#include "VRU.hpp"
#endif // VRU
#include <RMG-Core/Core.hpp>
#include <QGuiApplication>
#include <QApplication>
#include <SDL.h>
#include <algorithm>
#include <chrono>
#include <cmath>
//
// Local Defines
@@ -31,7 +37,6 @@
#define NUM_CONTROLLERS 4
#define N64_AXIS_PEAK 85
#define MAX_DIAGONAL_VALUE 69
#define DEADZONE_VALUE 7
#define RD_GETSTATUS 0x00 // get status
#define RD_READKEYS 0x01 // read button values
@@ -97,6 +102,64 @@ struct InputProfile
InputMapping AnalogStick_Down;
InputMapping AnalogStick_Left;
InputMapping AnalogStick_Right;
// hotkeys
bool Hotkey_Shutdown_Pressed = false;
InputMapping Hotkey_Shutdown;
bool Hotkey_Exit_Pressed = false;
InputMapping Hotkey_Exit;
bool Hotkey_SoftReset_Pressed = false;
InputMapping Hotkey_SoftReset;
bool Hotkey_HardReset_Pressed = false;
InputMapping Hotkey_HardReset;
bool Hotkey_Resume_Pressed = false;
InputMapping Hotkey_Resume;
bool Hotkey_Screenshot_Pressed = false;
InputMapping Hotkey_Screenshot;
bool Hotkey_LimitFPS_Pressed = false;
InputMapping Hotkey_LimitFPS;
bool Hotkey_SpeedFactor_Pressed = false;
InputMapping Hotkey_SpeedFactor25;
InputMapping Hotkey_SpeedFactor50;
InputMapping Hotkey_SpeedFactor75;
InputMapping Hotkey_SpeedFactor100;
InputMapping Hotkey_SpeedFactor125;
InputMapping Hotkey_SpeedFactor150;
InputMapping Hotkey_SpeedFactor175;
InputMapping Hotkey_SpeedFactor200;
InputMapping Hotkey_SpeedFactor225;
InputMapping Hotkey_SpeedFactor250;
InputMapping Hotkey_SpeedFactor275;
InputMapping Hotkey_SpeedFactor300;
bool Hotkey_SaveState_Pressed = false;
InputMapping Hotkey_SaveState;
bool Hotkey_LoadState_Pressed = false;
InputMapping Hotkey_LoadState;
bool Hotkey_GSButton_Pressed = false;
InputMapping Hotkey_GSButton;
bool Hotkey_SaveStateSlot_Pressed = false;
InputMapping Hotkey_SaveStateSlot0;
InputMapping Hotkey_SaveStateSlot1;
InputMapping Hotkey_SaveStateSlot2;
InputMapping Hotkey_SaveStateSlot3;
InputMapping Hotkey_SaveStateSlot4;
InputMapping Hotkey_SaveStateSlot5;
InputMapping Hotkey_SaveStateSlot6;
InputMapping Hotkey_SaveStateSlot7;
InputMapping Hotkey_SaveStateSlot8;
InputMapping Hotkey_SaveStateSlot9;
bool Hotkey_IncreaseSaveStateSlot_Pressed = false;
InputMapping Hotkey_IncreaseSaveStateSlot;
bool Hotkey_DecreaseSaveStateSlot_Pressed = false;
InputMapping Hotkey_DecreaseSaveStateSlot;
bool Hotkey_MemoryPak_Pressed = false;
InputMapping Hotkey_MemoryPak;
bool Hotkey_RumblePak_Pressed = false;
InputMapping Hotkey_RumblePak;
bool Hotkey_NoPak_Pressed = false;
InputMapping Hotkey_NoPak;
bool Hotkey_Fullscreen_Pressed = false;
InputMapping Hotkey_Fullscreen;
};
//
@@ -106,6 +169,9 @@ struct InputProfile
// SDL thread
static Thread::SDLThread *l_SDLThread = nullptr;
// Hotkeys thread (for when paused)
static Thread::HotkeysThread *l_HotkeysThread = nullptr;
// input profiles
static InputProfile l_InputProfiles[NUM_CONTROLLERS];
@@ -253,6 +319,46 @@ static void load_settings(void)
load_inputmapping_settings(&profile->AnalogStick_Down, section, SettingsID::Input_AnalogStickDown_Name, SettingsID::Input_AnalogStickDown_InputType, SettingsID::Input_AnalogStickDown_Data, SettingsID::Input_AnalogStickDown_ExtraData);
load_inputmapping_settings(&profile->AnalogStick_Left, section, SettingsID::Input_AnalogStickLeft_Name, SettingsID::Input_AnalogStickLeft_InputType, SettingsID::Input_AnalogStickLeft_Data, SettingsID::Input_AnalogStickLeft_ExtraData);
load_inputmapping_settings(&profile->AnalogStick_Right, section, SettingsID::Input_AnalogStickRight_Name, SettingsID::Input_AnalogStickRight_InputType, SettingsID::Input_AnalogStickRight_Data, SettingsID::Input_AnalogStickRight_ExtraData);
// load hotkeys settings
load_inputmapping_settings(&profile->Hotkey_Shutdown, section, SettingsID::Input_Hotkey_Shutdown_Name, SettingsID::Input_Hotkey_Shutdown_InputType, SettingsID::Input_Hotkey_Shutdown_Data, SettingsID::Input_Hotkey_Shutdown_ExtraData);
load_inputmapping_settings(&profile->Hotkey_Exit, section, SettingsID::Input_Hotkey_Exit_Name, SettingsID::Input_Hotkey_Exit_InputType, SettingsID::Input_Hotkey_Exit_Data, SettingsID::Input_Hotkey_Exit_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SoftReset, section, SettingsID::Input_Hotkey_SoftReset_Name, SettingsID::Input_Hotkey_SoftReset_InputType, SettingsID::Input_Hotkey_SoftReset_Data, SettingsID::Input_Hotkey_SoftReset_ExtraData);
load_inputmapping_settings(&profile->Hotkey_HardReset, section, SettingsID::Input_Hotkey_HardReset_Name, SettingsID::Input_Hotkey_HardReset_InputType, SettingsID::Input_Hotkey_HardReset_Data, SettingsID::Input_Hotkey_HardReset_ExtraData);
load_inputmapping_settings(&profile->Hotkey_Resume, section, SettingsID::Input_Hotkey_Resume_Name, SettingsID::Input_Hotkey_Resume_InputType, SettingsID::Input_Hotkey_Resume_Data, SettingsID::Input_Hotkey_Resume_ExtraData);
load_inputmapping_settings(&profile->Hotkey_Screenshot, section, SettingsID::Input_Hotkey_Screenshot_Name, SettingsID::Input_Hotkey_Screenshot_InputType, SettingsID::Input_Hotkey_Screenshot_Data, SettingsID::Input_Hotkey_Screenshot_ExtraData);
load_inputmapping_settings(&profile->Hotkey_LimitFPS, section, SettingsID::Input_Hotkey_LimitFPS_Name, SettingsID::Input_Hotkey_LimitFPS_InputType, SettingsID::Input_Hotkey_LimitFPS_Data, SettingsID::Input_Hotkey_LimitFPS_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SpeedFactor25, section, SettingsID::Input_Hotkey_SpeedFactor25_Name, SettingsID::Input_Hotkey_SpeedFactor25_InputType, SettingsID::Input_Hotkey_SpeedFactor25_Data, SettingsID::Input_Hotkey_SpeedFactor25_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SpeedFactor50, section, SettingsID::Input_Hotkey_SpeedFactor50_Name, SettingsID::Input_Hotkey_SpeedFactor50_InputType, SettingsID::Input_Hotkey_SpeedFactor50_Data, SettingsID::Input_Hotkey_SpeedFactor50_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SpeedFactor75, section, SettingsID::Input_Hotkey_SpeedFactor75_Name, SettingsID::Input_Hotkey_SpeedFactor75_InputType, SettingsID::Input_Hotkey_SpeedFactor75_Data, SettingsID::Input_Hotkey_SpeedFactor75_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SpeedFactor100, section, SettingsID::Input_Hotkey_SpeedFactor100_Name, SettingsID::Input_Hotkey_SpeedFactor100_InputType, SettingsID::Input_Hotkey_SpeedFactor100_Data, SettingsID::Input_Hotkey_SpeedFactor100_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SpeedFactor125, section, SettingsID::Input_Hotkey_SpeedFactor125_Name, SettingsID::Input_Hotkey_SpeedFactor125_InputType, SettingsID::Input_Hotkey_SpeedFactor125_Data, SettingsID::Input_Hotkey_SpeedFactor125_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SpeedFactor150, section, SettingsID::Input_Hotkey_SpeedFactor150_Name, SettingsID::Input_Hotkey_SpeedFactor150_InputType, SettingsID::Input_Hotkey_SpeedFactor150_Data, SettingsID::Input_Hotkey_SpeedFactor150_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SpeedFactor175, section, SettingsID::Input_Hotkey_SpeedFactor175_Name, SettingsID::Input_Hotkey_SpeedFactor175_InputType, SettingsID::Input_Hotkey_SpeedFactor175_Data, SettingsID::Input_Hotkey_SpeedFactor175_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SpeedFactor200, section, SettingsID::Input_Hotkey_SpeedFactor200_Name, SettingsID::Input_Hotkey_SpeedFactor200_InputType, SettingsID::Input_Hotkey_SpeedFactor200_Data, SettingsID::Input_Hotkey_SpeedFactor200_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SpeedFactor225, section, SettingsID::Input_Hotkey_SpeedFactor225_Name, SettingsID::Input_Hotkey_SpeedFactor225_InputType, SettingsID::Input_Hotkey_SpeedFactor225_Data, SettingsID::Input_Hotkey_SpeedFactor225_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SpeedFactor250, section, SettingsID::Input_Hotkey_SpeedFactor250_Name, SettingsID::Input_Hotkey_SpeedFactor250_InputType, SettingsID::Input_Hotkey_SpeedFactor250_Data, SettingsID::Input_Hotkey_SpeedFactor250_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SpeedFactor275, section, SettingsID::Input_Hotkey_SpeedFactor275_Name, SettingsID::Input_Hotkey_SpeedFactor275_InputType, SettingsID::Input_Hotkey_SpeedFactor275_Data, SettingsID::Input_Hotkey_SpeedFactor275_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SpeedFactor300, section, SettingsID::Input_Hotkey_SpeedFactor300_Name, SettingsID::Input_Hotkey_SpeedFactor300_InputType, SettingsID::Input_Hotkey_SpeedFactor300_Data, SettingsID::Input_Hotkey_SpeedFactor300_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SaveState, section, SettingsID::Input_Hotkey_SaveState_Name, SettingsID::Input_Hotkey_SaveState_InputType, SettingsID::Input_Hotkey_SaveState_Data, SettingsID::Input_Hotkey_SaveState_ExtraData);
load_inputmapping_settings(&profile->Hotkey_LoadState, section, SettingsID::Input_Hotkey_LoadState_Name, SettingsID::Input_Hotkey_LoadState_InputType, SettingsID::Input_Hotkey_LoadState_Data, SettingsID::Input_Hotkey_LoadState_ExtraData);
load_inputmapping_settings(&profile->Hotkey_GSButton, section, SettingsID::Input_Hotkey_GSButton_Name, SettingsID::Input_Hotkey_GSButton_InputType, SettingsID::Input_Hotkey_GSButton_Data, SettingsID::Input_Hotkey_GSButton_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SaveStateSlot0, section, SettingsID::Input_Hotkey_SaveStateSlot0_Name, SettingsID::Input_Hotkey_SaveStateSlot0_InputType, SettingsID::Input_Hotkey_SaveStateSlot0_Data, SettingsID::Input_Hotkey_SaveStateSlot0_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SaveStateSlot1, section, SettingsID::Input_Hotkey_SaveStateSlot1_Name, SettingsID::Input_Hotkey_SaveStateSlot1_InputType, SettingsID::Input_Hotkey_SaveStateSlot1_Data, SettingsID::Input_Hotkey_SaveStateSlot1_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SaveStateSlot2, section, SettingsID::Input_Hotkey_SaveStateSlot2_Name, SettingsID::Input_Hotkey_SaveStateSlot2_InputType, SettingsID::Input_Hotkey_SaveStateSlot2_Data, SettingsID::Input_Hotkey_SaveStateSlot2_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SaveStateSlot3, section, SettingsID::Input_Hotkey_SaveStateSlot3_Name, SettingsID::Input_Hotkey_SaveStateSlot3_InputType, SettingsID::Input_Hotkey_SaveStateSlot3_Data, SettingsID::Input_Hotkey_SaveStateSlot3_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SaveStateSlot4, section, SettingsID::Input_Hotkey_SaveStateSlot4_Name, SettingsID::Input_Hotkey_SaveStateSlot4_InputType, SettingsID::Input_Hotkey_SaveStateSlot4_Data, SettingsID::Input_Hotkey_SaveStateSlot4_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SaveStateSlot5, section, SettingsID::Input_Hotkey_SaveStateSlot5_Name, SettingsID::Input_Hotkey_SaveStateSlot5_InputType, SettingsID::Input_Hotkey_SaveStateSlot5_Data, SettingsID::Input_Hotkey_SaveStateSlot5_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SaveStateSlot6, section, SettingsID::Input_Hotkey_SaveStateSlot6_Name, SettingsID::Input_Hotkey_SaveStateSlot6_InputType, SettingsID::Input_Hotkey_SaveStateSlot6_Data, SettingsID::Input_Hotkey_SaveStateSlot6_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SaveStateSlot7, section, SettingsID::Input_Hotkey_SaveStateSlot7_Name, SettingsID::Input_Hotkey_SaveStateSlot7_InputType, SettingsID::Input_Hotkey_SaveStateSlot7_Data, SettingsID::Input_Hotkey_SaveStateSlot7_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SaveStateSlot8, section, SettingsID::Input_Hotkey_SaveStateSlot8_Name, SettingsID::Input_Hotkey_SaveStateSlot8_InputType, SettingsID::Input_Hotkey_SaveStateSlot8_Data, SettingsID::Input_Hotkey_SaveStateSlot8_ExtraData);
load_inputmapping_settings(&profile->Hotkey_SaveStateSlot9, section, SettingsID::Input_Hotkey_SaveStateSlot9_Name, SettingsID::Input_Hotkey_SaveStateSlot9_InputType, SettingsID::Input_Hotkey_SaveStateSlot9_Data, SettingsID::Input_Hotkey_SaveStateSlot9_ExtraData);
load_inputmapping_settings(&profile->Hotkey_IncreaseSaveStateSlot, section, SettingsID::Input_Hotkey_IncreaseSaveStateSlot_Name, SettingsID::Input_Hotkey_IncreaseSaveStateSlot_InputType, SettingsID::Input_Hotkey_IncreaseSaveStateSlot_Data, SettingsID::Input_Hotkey_IncreaseSaveStateSlot_ExtraData);
load_inputmapping_settings(&profile->Hotkey_DecreaseSaveStateSlot, section, SettingsID::Input_Hotkey_DecreaseSaveStateSlot_Name, SettingsID::Input_Hotkey_DecreaseSaveStateSlot_InputType, SettingsID::Input_Hotkey_DecreaseSaveStateSlot_Data, SettingsID::Input_Hotkey_DecreaseSaveStateSlot_ExtraData);
load_inputmapping_settings(&profile->Hotkey_MemoryPak, section, SettingsID::Input_Hotkey_MemoryPak_Name, SettingsID::Input_Hotkey_MemoryPak_InputType, SettingsID::Input_Hotkey_MemoryPak_Data, SettingsID::Input_Hotkey_MemoryPak_ExtraData);
load_inputmapping_settings(&profile->Hotkey_RumblePak, section, SettingsID::Input_Hotkey_RumblePak_Name, SettingsID::Input_Hotkey_RumblePak_InputType, SettingsID::Input_Hotkey_RumblePak_Data, SettingsID::Input_Hotkey_RumblePak_ExtraData);
load_inputmapping_settings(&profile->Hotkey_NoPak, section, SettingsID::Input_Hotkey_NoPak_Name, SettingsID::Input_Hotkey_NoPak_InputType, SettingsID::Input_Hotkey_NoPak_Data, SettingsID::Input_Hotkey_NoPak_ExtraData);
load_inputmapping_settings(&profile->Hotkey_Fullscreen, section, SettingsID::Input_Hotkey_Fullscreen_Name, SettingsID::Input_Hotkey_Fullscreen_InputType, SettingsID::Input_Hotkey_Fullscreen_Data, SettingsID::Input_Hotkey_Fullscreen_ExtraData);
}
}
@@ -269,6 +375,7 @@ static void apply_controller_profiles(void)
{
InputProfile* profile = &l_InputProfiles[i];
int plugin = PLUGIN_NONE;
bool emulateVRU = (profile->DeviceNum == (int)InputDeviceType::EmulateVRU);
switch (profile->ControllerPak)
{
@@ -278,7 +385,7 @@ static void apply_controller_profiles(void)
case N64ControllerPak::RumblePak:
plugin = PLUGIN_RAW;
break;
case N64ControllerPak::TransferPak:
case N64ControllerPak::TransferPak:
plugin = PLUGIN_TRANSFER_PAK;
break;
default:
@@ -286,10 +393,47 @@ static void apply_controller_profiles(void)
break;
}
#ifdef VRU
// attempt to try initializing VRU when needed,
// if it fails, unplug the VRU
if (emulateVRU && !IsVRUInit() && !InitVRU())
{
profile->PluggedIn = false;
}
#else
// always unplug VRU when RMG-Input was built
// without VRU support
if (emulateVRU)
{
profile->PluggedIn = false;
}
#endif // VRU
l_ControlInfo.Controls[i].Present = profile->PluggedIn ? 1 : 0;
l_ControlInfo.Controls[i].Plugin = plugin;
l_ControlInfo.Controls[i].Plugin = emulateVRU ? PLUGIN_NONE : plugin;
l_ControlInfo.Controls[i].RawData = 0;
l_ControlInfo.Controls[i].Type = CONT_TYPE_STANDARD;
l_ControlInfo.Controls[i].Type = emulateVRU ? CONT_TYPE_VRU : CONT_TYPE_STANDARD;
}
}
static void switch_controller_pak(InputProfile* profile, const int Control, const int pak)
{
const int currentPak = l_ControlInfo.Controls[Control].Plugin;
// we don't need to do anything,
// when the current pak matches
if (currentPak == pak)
{
return;
}
l_ControlInfo.Controls[Control].Plugin = pak;
// when switching from rumble pak to a different pak,
// ensure that we stop the controller's rumble
if (currentPak == PLUGIN_RAW)
{
profile->InputDevice.StopRumble();
}
}
@@ -422,7 +566,7 @@ static void close_controllers(void)
}
}
static int get_button_state(InputProfile* profile, const InputMapping* inputMapping)
static int get_button_state(InputProfile* profile, const InputMapping* inputMapping, const bool allPressed = false)
{
int state = 0;
@@ -435,29 +579,70 @@ static int get_button_state(InputProfile* profile, const InputMapping* inputMapp
{
case InputType::GamepadButton:
{
state |= SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)data);
if (allPressed && i > 0)
{
state &= SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)data);
}
else
{
state |= SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)data);
}
} break;
case InputType::GamepadAxis:
{
int axis_value = SDL_GameControllerGetAxis(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerAxis)data);
state |= (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (extraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
if (allPressed && i > 0)
{
state &= (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (extraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
}
else
{
state |= (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (extraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
}
} break;
case InputType::JoystickButton:
{
state |= SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), data);
if (allPressed && i > 0)
{
state &= SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), data);
}
else
{
state |= SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), data);
}
} break;
case InputType::JoystickAxis:
{
int axis_value = SDL_JoystickGetAxis(profile->InputDevice.GetJoystickHandle(), data);
state |= (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (extraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
if (allPressed && i > 0)
{
state &= (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (extraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
}
else
{
state |= (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (extraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
}
} break;
case InputType::Keyboard:
{
state |= l_KeyboardState[data] ? 1 : 0;
if (allPressed && i > 0)
{
state &= l_KeyboardState[data] ? 1 : 0;
}
else
{
state |= l_KeyboardState[data] ? 1 : 0;
}
} break;
default:
break;
}
// early return when needed
if (allPressed && !state)
{
return state;
}
}
return state;
@@ -531,52 +716,51 @@ static double get_axis_state(InputProfile* profile, const InputMapping* inputMap
}
}
static double simulate_deadzone(const double n64InputAxis, const double maxAxis, const int deadzone, const double axisRange)
// maps a value in one range to a value in another
static double map_range_to_range(const double value, const double fromLower, const double fromUpper, const double toLower, const double toUpper)
{
double axisAbsolute = std::abs(n64InputAxis);
const double fromDelta = fromUpper - fromLower;
const double toDelta = toUpper - toLower;
const double toUnitsPerFromUnit = toDelta / fromDelta;
const double fromUnits = value - fromLower;
if (axisAbsolute <= deadzone)
{
axisAbsolute = 0; // No input when inside deadzone
}
else
{
// Create linear scaling factor from 0 at inner deadzone to MAX_AXIS at outer limit
axisAbsolute = (axisAbsolute - deadzone) * maxAxis / axisRange / axisAbsolute;
}
return axisAbsolute;
return toLower + fromUnits * toUnitsPerFromUnit;
}
// Credit: MerryMage & fzurita
static void simulate_octagon(const double inputX, const double inputY, const double deadzoneFactor, const double sensitivityFactor, int& outputX, int& outputY)
// applies square deadzone, then scales result such that the edge of the deadzone is 0
static double apply_deadzone(const double input, const double deadzone)
{
const double inputAbsolute = std::abs(input);
if (inputAbsolute <= deadzone)
{
return 0;
}
return std::copysign(map_range_to_range(inputAbsolute, deadzone, 1.0, 0.0, 1.0), input);
}
// Credit: MerryMage, fzurita & kev4cards
static void simulate_octagon(const double inputX, const double inputY, int& outputX, int& outputY)
{
// don't increase emulated range at higher than 100% sensitivity
const double maxAxis = N64_AXIS_PEAK * std::min(sensitivityFactor, 1.0);
const double maxDiagonal = MAX_DIAGONAL_VALUE * std::min(sensitivityFactor, 1.0);
const int deadzone = (int)(deadzoneFactor * N64_AXIS_PEAK * sensitivityFactor);
const double axisRange = maxAxis - deadzone;
const double maxAxis = N64_AXIS_PEAK;
const double maxDiagonal = MAX_DIAGONAL_VALUE;
// scale to [-maxAxis, maxAxis]
double ax = std::min(inputX * sensitivityFactor, 1.0) * maxAxis;
double ay = std::min(inputY * sensitivityFactor, 1.0) * maxAxis;
double ax = inputX * maxAxis;
double ay = inputY * maxAxis;
// check whether (ax, ay) is within the circle of radius MAX_AXIS
double len = std::sqrt(ax*ax + ay*ay);
if (len <= maxAxis)
{
// scale inputs
ax *= simulate_deadzone(ax, maxAxis, deadzone, axisRange);
ay *= simulate_deadzone(ay, maxAxis, deadzone, axisRange);
}
else
// check whether (ax, ay) is within the circle of radius maxAxis
const double distance = std::hypot(ax, ay);
if (distance > maxAxis)
{
// scale ax and ay to stay on the same line, but at the edge of the circle
len = maxAxis / len;
ax *= len;
ay *= len;
const double scale = maxAxis / distance;
ax *= scale;
ay *= scale;
}
// bound diagonals to an octagonal range [-69, 69]
// bound diagonals to an octagonal range [-maxDiagonal, maxDiagonal]
if (ax != 0.0 && ay != 0.0)
{
const double slope = ay / ax;
@@ -584,7 +768,7 @@ static void simulate_octagon(const double inputX, const double inputY, const dou
const double edgey = std::copysign(std::min(std::abs(edgex * slope), maxAxis / (1.0 / std::abs(slope) + (maxAxis - maxDiagonal) / maxDiagonal)), ay);
edgex = edgey / slope;
const double scale = std::sqrt(edgex*edgex + edgey*edgey) / maxAxis;
const double scale = std::hypot(edgex, edgey) / maxAxis;
ax *= scale;
ay *= scale;
}
@@ -617,11 +801,83 @@ static unsigned char data_crc(unsigned char *data, int length)
return remainder;
}
void sdl_init()
static bool check_hotkeys(int Control)
{
InputProfile* profile = &l_InputProfiles[Control];
int state = 0;
// we only have to check for hotkeys
// when there's a controller opened
if (!profile->InputDevice.HasOpenDevice())
{
return false;
}
#define DEFINE_HOTKEY(mapping, pressed, function, function2) \
state = get_button_state(profile, &profile->mapping, true); \
if (state) \
{ \
if (!profile->pressed) \
{ \
profile->pressed = true; \
function; \
} \
return true; \
} \
else if (!state && profile->pressed) \
{ \
function2; \
profile->pressed = false; \
}
DEFINE_HOTKEY(Hotkey_Shutdown, Hotkey_Shutdown_Pressed, CoreStopEmulation(), );
DEFINE_HOTKEY(Hotkey_Exit, Hotkey_Exit_Pressed, QGuiApplication::quit(), );
DEFINE_HOTKEY(Hotkey_SoftReset, Hotkey_SoftReset_Pressed, CoreResetEmulation(false), );
DEFINE_HOTKEY(Hotkey_Resume, Hotkey_Resume_Pressed, CoreIsEmulationPaused() ? CoreResumeEmulation() : CorePauseEmulation(), );
DEFINE_HOTKEY(Hotkey_Screenshot, Hotkey_Screenshot_Pressed, CoreTakeScreenshot(), );
DEFINE_HOTKEY(Hotkey_LimitFPS, Hotkey_LimitFPS_Pressed, CoreSetSpeedLimiterState(!CoreIsSpeedLimiterEnabled()), );
DEFINE_HOTKEY(Hotkey_SpeedFactor25, Hotkey_SpeedFactor_Pressed, CoreSetSpeedFactor(25), );
DEFINE_HOTKEY(Hotkey_SpeedFactor50, Hotkey_SpeedFactor_Pressed, CoreSetSpeedFactor(50), );
DEFINE_HOTKEY(Hotkey_SpeedFactor75, Hotkey_SpeedFactor_Pressed, CoreSetSpeedFactor(75), );
DEFINE_HOTKEY(Hotkey_SpeedFactor100, Hotkey_SpeedFactor_Pressed, CoreSetSpeedFactor(100), );
DEFINE_HOTKEY(Hotkey_SpeedFactor125, Hotkey_SpeedFactor_Pressed, CoreSetSpeedFactor(125), );
DEFINE_HOTKEY(Hotkey_SpeedFactor150, Hotkey_SpeedFactor_Pressed, CoreSetSpeedFactor(150), );
DEFINE_HOTKEY(Hotkey_SpeedFactor175, Hotkey_SpeedFactor_Pressed, CoreSetSpeedFactor(175), );
DEFINE_HOTKEY(Hotkey_SpeedFactor200, Hotkey_SpeedFactor_Pressed, CoreSetSpeedFactor(200), );
DEFINE_HOTKEY(Hotkey_SpeedFactor225, Hotkey_SpeedFactor_Pressed, CoreSetSpeedFactor(225), );
DEFINE_HOTKEY(Hotkey_SpeedFactor250, Hotkey_SpeedFactor_Pressed, CoreSetSpeedFactor(250), );
DEFINE_HOTKEY(Hotkey_SpeedFactor275, Hotkey_SpeedFactor_Pressed, CoreSetSpeedFactor(275), );
DEFINE_HOTKEY(Hotkey_SpeedFactor300, Hotkey_SpeedFactor_Pressed, CoreSetSpeedFactor(300), );
DEFINE_HOTKEY(Hotkey_SaveState, Hotkey_SaveState_Pressed, CoreSaveState(), );
DEFINE_HOTKEY(Hotkey_LoadState, Hotkey_LoadState_Pressed, CoreLoadSaveState(), );
DEFINE_HOTKEY(Hotkey_GSButton, Hotkey_GSButton_Pressed, CorePressGamesharkButton(true), CorePressGamesharkButton(false));
DEFINE_HOTKEY(Hotkey_SaveStateSlot0, Hotkey_SaveStateSlot_Pressed, CoreSetSaveStateSlot(0), );
DEFINE_HOTKEY(Hotkey_SaveStateSlot1, Hotkey_SaveStateSlot_Pressed, CoreSetSaveStateSlot(1), );
DEFINE_HOTKEY(Hotkey_SaveStateSlot2, Hotkey_SaveStateSlot_Pressed, CoreSetSaveStateSlot(2), );
DEFINE_HOTKEY(Hotkey_SaveStateSlot3, Hotkey_SaveStateSlot_Pressed, CoreSetSaveStateSlot(3), );
DEFINE_HOTKEY(Hotkey_SaveStateSlot4, Hotkey_SaveStateSlot_Pressed, CoreSetSaveStateSlot(4), );
DEFINE_HOTKEY(Hotkey_SaveStateSlot5, Hotkey_SaveStateSlot_Pressed, CoreSetSaveStateSlot(5), );
DEFINE_HOTKEY(Hotkey_SaveStateSlot6, Hotkey_SaveStateSlot_Pressed, CoreSetSaveStateSlot(6), );
DEFINE_HOTKEY(Hotkey_SaveStateSlot7, Hotkey_SaveStateSlot_Pressed, CoreSetSaveStateSlot(7), );
DEFINE_HOTKEY(Hotkey_SaveStateSlot8, Hotkey_SaveStateSlot_Pressed, CoreSetSaveStateSlot(8), );
DEFINE_HOTKEY(Hotkey_SaveStateSlot9, Hotkey_SaveStateSlot_Pressed, CoreSetSaveStateSlot(9), );
DEFINE_HOTKEY(Hotkey_IncreaseSaveStateSlot, Hotkey_IncreaseSaveStateSlot_Pressed, CoreIncreaseSaveStateSlot(), );
DEFINE_HOTKEY(Hotkey_DecreaseSaveStateSlot, Hotkey_DecreaseSaveStateSlot_Pressed, CoreDecreaseSaveStateSlot(), );
DEFINE_HOTKEY(Hotkey_MemoryPak, Hotkey_MemoryPak_Pressed, switch_controller_pak(profile, Control, PLUGIN_MEMPAK), );
DEFINE_HOTKEY(Hotkey_RumblePak, Hotkey_RumblePak_Pressed, switch_controller_pak(profile, Control, PLUGIN_RAW), );
DEFINE_HOTKEY(Hotkey_NoPak, Hotkey_NoPak_Pressed, switch_controller_pak(profile, Control, PLUGIN_NONE), );
DEFINE_HOTKEY(Hotkey_Fullscreen, Hotkey_Fullscreen_Pressed, CoreToggleFullscreen(), );
#undef DEFINE_HOTKEY
return false;
}
static void sdl_init()
{
std::filesystem::path gameControllerDbPath;
for (const int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_VIDEO, SDL_INIT_HAPTIC})
for (const int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_AUDIO, SDL_INIT_VIDEO, SDL_INIT_HAPTIC})
{
if (!SDL_WasInit(subsystem))
{
@@ -636,7 +892,7 @@ void sdl_init()
SDL_GameControllerAddMappingsFromFile(gameControllerDbPath.string().c_str());
}
void sdl_quit()
static void sdl_quit()
{
for (const int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_HAPTIC})
{
@@ -663,6 +919,8 @@ EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Con
return M64ERR_SYSTEM_FAIL;
}
CoreSetupDebugCallbackMessage(DebugCallback, Context);
sdl_init();
l_SDLThread = new Thread::SDLThread(nullptr);
@@ -673,6 +931,9 @@ EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Con
l_InputProfiles[i].InputDevice.SetSDLThread(l_SDLThread);
}
l_HotkeysThread = new Thread::HotkeysThread(check_hotkeys, nullptr);
l_HotkeysThread->start();
load_settings();
return M64ERR_SUCCESS;
@@ -691,6 +952,10 @@ EXPORT m64p_error CALL PluginShutdown(void)
l_SDLThread->deleteLater();
l_SDLThread = nullptr;
l_HotkeysThread->StopLoop();
l_HotkeysThread->deleteLater();
l_HotkeysThread = nullptr;
sdl_quit();
return M64ERR_SUCCESS;
@@ -795,7 +1060,7 @@ EXPORT void CALL ControllerCommand(int Control, unsigned char* Command)
case RD_READKEYS:
break;
case RD_READPAK:
if (profile->ControllerPak == N64ControllerPak::RumblePak)
if (l_ControlInfo.Controls[Control].Plugin == PLUGIN_RAW)
{
unsigned int dwAddress = (Command[3] << 8) + (Command[4] & 0xE0);
@@ -812,7 +1077,7 @@ EXPORT void CALL ControllerCommand(int Control, unsigned char* Command)
}
break;
case RD_WRITEPAK:
if (profile->ControllerPak == N64ControllerPak::RumblePak)
if (l_ControlInfo.Controls[Control].Plugin == PLUGIN_RAW)
{
unsigned int dwAddress = (Command[3] << 8) + (Command[4] & 0xE0);
if (dwAddress == PAK_IO_RUMBLE)
@@ -845,6 +1110,23 @@ EXPORT void CALL GetKeys(int Control, BUTTONS* Keys)
return;
}
#ifdef VRU
// when we're emulating the VRU,
// we need to check the mic state
if (profile->DeviceNum == (int)InputDeviceType::EmulateVRU)
{
if (GetVRUMicState())
{
Keys->Value = 0x0020;
}
else
{
Keys->Value = 0x0000;
}
return;
}
#endif // VRU
// check if device has been disconnected,
// if it has, try to open it again,
// only do this every 2 seconds to prevent lag
@@ -868,6 +1150,14 @@ EXPORT void CALL GetKeys(int Control, BUTTONS* Keys)
}
}
// when we've matched a hotkey,
// we don't need to check anything
// else
if(check_hotkeys(Control))
{
return;
}
Keys->A_BUTTON = get_button_state(profile, &profile->Button_A);
Keys->B_BUTTON = get_button_state(profile, &profile->Button_B);
Keys->START_BUTTON = get_button_state(profile, &profile->Button_Start);
@@ -890,12 +1180,22 @@ EXPORT void CALL GetKeys(int Control, BUTTONS* Keys)
inputX = get_axis_state(profile, &profile->AnalogStick_Left, -1, inputX, useButtonMapping);
inputX = get_axis_state(profile, &profile->AnalogStick_Right, 1, inputX, useButtonMapping);
// take deadzone into account
const double deadzone = profile->DeadzoneValue / 100.0;
inputX = apply_deadzone(inputX, deadzone);
inputY = apply_deadzone(inputY, deadzone);
// take sensitivity into account
const double sensitivityRatio = profile->SensitivityValue / 100.0;
const double lowerInputLimit = std::max(-1.0, -sensitivityRatio);
const double upperInputLimit = std::min(1.0, sensitivityRatio);
inputX = std::clamp(inputX * sensitivityRatio, lowerInputLimit, upperInputLimit);
inputY = std::clamp(inputY * sensitivityRatio, lowerInputLimit, upperInputLimit);
int octagonX = 0, octagonY = 0;
simulate_octagon(
inputX, // inputX
inputY, // inputY
profile->DeadzoneValue / 100.0, // deadzoneFactor
profile->SensitivityValue / 100.0, // sensitivityFactor
octagonX, // outputX
octagonY // outputY
);
@@ -930,13 +1230,18 @@ EXPORT void CALL ReadController(int Control, unsigned char *Command)
EXPORT int CALL RomOpen(void)
{
l_HotkeysThread->SetState(HotkeysThreadState::RomOpened);
return 1;
}
EXPORT void CALL RomClosed(void)
{
l_HotkeysThread->SetState(HotkeysThreadState::RomClosed);
l_HasControlInfo = false;
close_controllers();
#ifdef VRU
QuitVRU();
#endif // VRU
}
EXPORT void CALL SDL_KeyDown(int keymod, int keysym)
+5
View File
@@ -97,6 +97,11 @@ target_link_libraries(RMG
RMG-Core
)
# needed for dynamically linked RMG-Core
set_target_properties(RMG PROPERTIES
INSTALL_RPATH "$ORIGIN"
)
target_include_directories(RMG PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
@@ -66,7 +66,7 @@ void InstallUpdateDialog::install(void)
" echo == Attemping to kill PID " + appPid + outputToLogLine,
" taskkill /F /PID:" + appPid + outputToLogLine,
" echo == Attemping to start \'" + fullFilePath + "\'" + outputToLogLine,
" \"" + fullFilePath + "\" /CLOSEAPPLICATIONS /NOCANCEL /SILENT /DIR=\"" + appPath + "\"" + outputToLogLine,
" \"" + fullFilePath + "\" /CLOSEAPPLICATIONS /NOCANCEL /MERGETASKS=\"!desktopicon\" /SILENT /DIR=\"" + appPath + "\"" + outputToLogLine,
")",
"IF NOT ERRORLEVEL 0 (",
" start \"\" cmd /c \"echo Rosalie's Mupen GUI failed to update, check the updater.log file in the Cache directory for more information && pause\"",
+181 -62
View File
@@ -128,9 +128,13 @@ void MainWindow::closeEvent(QCloseEvent *event)
if (!this->ui_QuitAfterEmulation &&
!this->emulationThread->isRunning())
{
this->storeGeometry();
this->storeGeometry();
}
// store toolbar location to settings
Qt::ToolBarArea toolbarArea = this->toolBarArea(this->toolBar);
CoreSettingsSetValue(SettingsID::GUI_ToolbarArea, this->getToolbarSettingAreaFromArea(toolbarArea));
this->ui_NoSwitchToRomBrowser = true;
this->on_Action_System_Shutdown();
@@ -222,6 +226,15 @@ void MainWindow::configureUI(QApplication* app, bool showUI)
this->statusBar()->setVisible(this->ui_ShowStatusbar);
this->statusBar()->addPermanentWidget(this->ui_StatusBar_Label, 1);
// set toolbar position according to setting
int toolbarAreaSetting = CoreSettingsGetIntValue(SettingsID::GUI_ToolbarArea);
Qt::ToolBarArea toolbarArea = this->getToolbarAreaFromSettingArea(toolbarAreaSetting);
if (this->toolBarArea(this->toolBar) != toolbarArea)
{
this->removeToolBar(this->toolBar);
this->addToolBar(toolbarArea, this->toolBar);
}
this->ui_TimerTimeout = CoreSettingsGetIntValue(SettingsID::GUI_StatusbarMessageDuration);
this->ui_Widgets->addWidget(this->ui_Widget_RomBrowser);
@@ -362,7 +375,18 @@ void MainWindow::updateUI(bool inEmulation, bool isPaused)
if (!settings.GoodName.empty())
{
this->setWindowTitle(QString::fromStdString(settings.GoodName) + QString(" - ") + this->ui_WindowTitle);
QString goodName = QString::fromStdString(settings.GoodName);
if (goodName.endsWith("(unknown rom)") ||
goodName.endsWith("(unknown disk)"))
{
std::filesystem::path romPath;
if (CoreGetRomPath(romPath))
{
goodName = QString::fromStdString(romPath.filename().string());
}
}
this->setWindowTitle(goodName + QString(" - ") + this->ui_WindowTitle);
}
this->ui_Widgets->setCurrentWidget(this->ui_Widget_OpenGL->GetWidget());
@@ -747,6 +771,41 @@ QString MainWindow::getSaveStateSlotText(QAction* action, int slot)
return saveStateSlotText;
}
int MainWindow::getToolbarSettingAreaFromArea(Qt::ToolBarArea area)
{
switch (area)
{
case Qt::ToolBarArea::TopToolBarArea:
return 0;
case Qt::ToolBarArea::BottomToolBarArea:
return 1;
case Qt::ToolBarArea::LeftToolBarArea:
return 2;
case Qt::ToolBarArea::RightToolBarArea:
return 3;
default:
return 0;
}
}
Qt::ToolBarArea MainWindow::getToolbarAreaFromSettingArea(int value)
{
switch (value)
{
default:
case 0:
return Qt::ToolBarArea::TopToolBarArea;
case 1:
return Qt::ToolBarArea::BottomToolBarArea;
case 2:
return Qt::ToolBarArea::LeftToolBarArea;
case 3:
return Qt::ToolBarArea::RightToolBarArea;
}
}
void MainWindow::configureActions(void)
{
// configure actions list
@@ -1243,19 +1302,11 @@ void MainWindow::on_Action_System_Pause(void)
if (!isPaused)
{
if (isRunning)
{
OnScreenDisplayPause();
}
ret = CorePauseEmulation();
error = "CorePauseEmulation() Failed!";
}
else
{
if (isPaused)
{
OnScreenDisplayResume();
}
ret = CoreResumeEmulation();
error = "CoreResumeEmulation() Failed!";
}
@@ -1275,10 +1326,6 @@ void MainWindow::on_Action_System_Screenshot(void)
{
this->showErrorMessage("CoreTakeScreenshot() Failed!", QString::fromStdString(CoreGetError()));
}
else
{
OnScreenDisplaySetMessage("Captured screenshot.");
}
}
void MainWindow::on_Action_System_LimitFPS(void)
@@ -1301,30 +1348,20 @@ void MainWindow::on_Action_System_SpeedFactor(int factor)
{
this->showErrorMessage("CoreSetSpeedFactor() Failed!", QString::fromStdString(CoreGetError()));
}
else
{
OnScreenDisplaySetMessage("Playback speed: " + std::to_string(CoreGetSpeedFactor()) + "%");
}
}
void MainWindow::on_Action_System_SaveState(void)
{
this->ui_ManuallySavedState = true;
if (!CoreSaveState())
{
this->ui_ManuallySavedState = false;
this->showErrorMessage("CoreSaveState() Failed", QString::fromStdString(CoreGetError()));
}
else
{
OnScreenDisplaySetMessage("Saved state to slot: " + std::to_string(CoreGetSaveStateSlot()));
// refresh savestate slot times in 1 second,
// kill any existing timers
if (this->ui_UpdateSaveStateSlotTimerId != 0)
{
this->killTimer(this->ui_UpdateSaveStateSlotTimerId);
this->ui_UpdateSaveStateSlotTimerId = 0;
}
this->ui_UpdateSaveStateSlotTimerId = this->startTimer(1000);
}
}
@@ -1342,8 +1379,11 @@ void MainWindow::on_Action_System_SaveAs(void)
if (!fileName.isEmpty())
{
this->ui_ManuallySavedState = true;
if (!CoreSaveState(fileName.toStdU32String()))
{
this->ui_ManuallySavedState = false;
this->showErrorMessage("CoreSaveState() Failed", QString::fromStdString(CoreGetError()));
}
else
@@ -1360,8 +1400,11 @@ void MainWindow::on_Action_System_SaveAs(void)
void MainWindow::on_Action_System_LoadState(void)
{
this->ui_ManuallyLoadedState = true;
if (!CoreLoadSaveState())
{
this->ui_ManuallyLoadedState = false;
this->showErrorMessage("CoreLoadSaveState() Failed", QString::fromStdString(CoreGetError()));
}
else
@@ -1381,12 +1424,15 @@ void MainWindow::on_Action_System_Load(void)
}
QString fileName =
QFileDialog::getOpenFileName(this, tr("Open Save State"), "", tr("Save State (*.dat *.state);;All Files (*)"));
QFileDialog::getOpenFileName(this, tr("Open Save State"), "", tr("Save State (*.dat *.state *.st* *.pj*);;All Files (*)"));
if (!fileName.isEmpty())
{
this->ui_ManuallyLoadedState = true;
if (!CoreLoadSaveState(fileName.toStdU32String()))
{
this->ui_ManuallyLoadedState = false;
this->showErrorMessage("CoreLoadSaveState() Failed", QString::fromStdString(CoreGetError()));
}
else
@@ -1411,29 +1457,6 @@ void MainWindow::on_Action_System_CurrentSaveState(int slot)
{
this->showErrorMessage("CoreSetSaveStateSlot() Failed", QString::fromStdString(CoreGetError()));
}
else
{
slotAction = this->ui_SlotActions[slot];
dateTimeText = this->getSaveStateSlotDateTimeText(slotAction);
// construct OSD message
message = "Selected save slot: " + std::to_string(slot);
// add date and time when available
if (!dateTimeText.isEmpty())
{
message += " [";
message += dateTimeText.toStdString();
message += "]";
}
else
{
message += " [N/A]";
}
// display message
OnScreenDisplaySetMessage(message);
}
}
void MainWindow::on_Action_System_Cheats(void)
@@ -1940,7 +1963,24 @@ void MainWindow::on_VidExt_ResizeWindow(int width, int height)
if (!this->toolBar->isHidden())
{
height += this->toolBar->height();
Qt::ToolBarArea area = this->toolBarArea(this->toolBar);
// dont resize when toolbar is floating
if (this->toolBar->isFloating())
{
return;
}
if (area == Qt::ToolBarArea::TopToolBarArea ||
area == Qt::ToolBarArea::BottomToolBarArea)
{
height += this->toolBar->height();
}
else if (area == Qt::ToolBarArea::LeftToolBarArea ||
area == Qt::ToolBarArea::RightToolBarArea)
{
width += this->toolBar->width();
}
}
if (!this->statusBar()->isHidden())
@@ -2084,18 +2124,97 @@ void MainWindow::on_Core_DebugCallback(CoreDebugMessageType type, QString contex
void MainWindow::on_Core_StateCallback(CoreStateCallbackType type, int value)
{
if (type == CoreStateCallbackType::SaveStateLoaded)
switch (type)
{
if (value == 0)
default:
break;
case CoreStateCallbackType::EmulationState:
{
OnScreenDisplaySetMessage("Failed to load save state.");
}
}
else if (type == CoreStateCallbackType::SaveStateSaved)
{
if (value == 0)
// update Pause button
this->action_System_Pause->setChecked(value == (int)CoreEmulationState::Paused);
// update OSD state
if (value == (int)CoreEmulationState::Paused)
{
OnScreenDisplayPause();
}
else if (value == (int)CoreEmulationState::Running)
{
OnScreenDisplayResume();
}
} break;
case CoreStateCallbackType::SaveStateSlot:
{
OnScreenDisplaySetMessage("Failed to save state.");
}
QAction* slotAction = this->ui_SlotActions[value];
QString dateTimeText = this->getSaveStateSlotDateTimeText(slotAction);
std::string message = "Selected save slot: " + std::to_string(value);
// add date and time when available
if (!dateTimeText.isEmpty())
{
message += " [";
message += dateTimeText.toStdString();
message += "]";
}
else
{
message += " [N/A]";
}
// display message
OnScreenDisplaySetMessage(message);
// update UI
this->ui_SlotActions[value]->setChecked(true);
} break;
case CoreStateCallbackType::SpeedFactor:
{
OnScreenDisplaySetMessage("Playback speed: " + std::to_string(value) + "%");
} break;
case CoreStateCallbackType::SaveStateLoaded:
{
if (value == 0)
{
OnScreenDisplaySetMessage("Failed to load save state.");
}
else if (!this->ui_ManuallyLoadedState)
{
OnScreenDisplaySetMessage("Loaded save state.");
}
this->ui_ManuallyLoadedState = false;
} break;
case CoreStateCallbackType::SaveStateSaved:
{
if (value == 0)
{
OnScreenDisplaySetMessage("Failed to save state.");
}
else if (!this->ui_ManuallySavedState)
{
OnScreenDisplaySetMessage("Saved state.");
}
// refresh savestate slot times in 1 second,
// kill any existing timers
if (this->ui_UpdateSaveStateSlotTimerId != 0)
{
this->killTimer(this->ui_UpdateSaveStateSlotTimerId);
this->ui_UpdateSaveStateSlotTimerId = 0;
}
this->ui_UpdateSaveStateSlotTimerId = this->startTimer(1000);
this->ui_ManuallySavedState = false;
} break;
case CoreStateCallbackType::ScreenshotCaptured:
{
if (value == 0)
{
OnScreenDisplaySetMessage("Failed to capture screenshot.");
}
else
{
OnScreenDisplaySetMessage("Captured screenshot.");
}
} break;
}
}
+6
View File
@@ -80,6 +80,9 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
bool ui_ManuallyPaused = true;
bool ui_ManuallySavedState = false;
bool ui_ManuallyLoadedState = false;
QList<QAction*> ui_Actions;
bool ui_AddedActions = false;
@@ -119,6 +122,9 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
QString getSaveStateSlotDateTimeText(QAction* action);
QString getSaveStateSlotText(QAction* action, int slot);
int getToolbarSettingAreaFromArea(Qt::ToolBarArea area);
Qt::ToolBarArea getToolbarAreaFromSettingArea(int value);
void configureActions(void);
void connectActionSignals(void);
void updateActions(bool inEmulation, bool isPaused);
+4 -1
View File
@@ -162,11 +162,14 @@
<string>toolBar</string>
</property>
<property name="movable">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextUnderIcon</enum>
</property>
<property name="floatable">
<bool>false</bool>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
+1 -1
View File
@@ -128,7 +128,7 @@ static m64p_error VidExt_SetMode(int Width, int Height, int BitsPerPixel, int Sc
static m64p_error VidExt_SetModeWithRate(int Width, int Height, int RefreshRate, int BitsPerPixel, int ScreenMode, int Flags)
{
return VidExt_SetMode(Width, Height, BitsPerPixel, ScreenMode, Flags);
return M64ERR_UNSUPPORTED;
}
static m64p_function VidExt_GLGetProc(const char *Proc)
+17
View File
@@ -94,6 +94,15 @@ int main(int argc, char **argv)
setenv("QT_QPA_PLATFORM", "xcb", 1);
#endif // FORCE_XCB
#ifndef _WIN32
// ensure the default OpenGL format
// doesn't have vsync enabled by default,
// only needed for linux (for now)
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
format.setSwapInterval(0);
QSurfaceFormat::setDefaultFormat(format);
#endif
QApplication app(argc, argv);
UserInterface::MainWindow window;
@@ -112,9 +121,11 @@ int main(int argc, char **argv)
parser.addVersionOption();
// custom options
#ifndef PORTABLE_INSTALL
QCommandLineOption libPathOption("lib-path", "Changes the path where the libraries are stored", "path");
QCommandLineOption corePathOption("core-path", "Changes the path where the core library is stored", "path");
QCommandLineOption pluginPathOption("plugin-path", "Changes the path where the plugins are stored", "path");
QCommandLineOption sharedDataPathOption("shared-data-path", "Changes the path where the shared data is stored", "path");
libPathOption.setFlags(QCommandLineOption::HiddenFromHelp);
corePathOption.setFlags(QCommandLineOption::HiddenFromHelp);
pluginPathOption.setFlags(QCommandLineOption::HiddenFromHelp);
sharedDataPathOption.setFlags(QCommandLineOption::HiddenFromHelp);
@@ -126,6 +137,7 @@ int main(int argc, char **argv)
QCommandLineOption diskOption("disk", "64DD Disk to open ROM in combination with", "64DD Disk");
#ifndef PORTABLE_INSTALL
parser.addOption(libPathOption);
parser.addOption(corePathOption);
parser.addOption(pluginPathOption);
parser.addOption(sharedDataPathOption);
@@ -142,9 +154,14 @@ int main(int argc, char **argv)
#ifndef PORTABLE_INSTALL
// set path overrides before initializing
QString libPathOverride = parser.value(libPathOption);
QString corePathOveride = parser.value(corePathOption);
QString pluginPathOverride = parser.value(pluginPathOption);
QString sharedDataPathOverride = parser.value(sharedDataPathOption);
if (!libPathOverride.isEmpty())
{
CoreSetLibraryPathOverride(libPathOverride.toStdString());
}
if (!corePathOveride.isEmpty())
{
CoreSetCorePathOverride(corePathOveride.toStdString());