Compare commits

...

162 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
Rosalie Wanders 33146626a9 Package: v0.3.9 2023-04-06 14:34:29 +02:00
Rosalie Wanders 78e12f774d RMG: add "Edit Game Input Settings" to the context menu of the ROM browser 2023-04-06 14:11:58 +02:00
Rosalie Wanders 689d8debb1 RMG-Input: implement PluginConfig2() and PluginConfig2HasRomConfig() 2023-04-06 14:11:20 +02:00
Rosalie Wanders 8be1ed8af5 RMG-Core: introduce CorePluginsHasROMConfig() and CorePluginsOpenROMConfig() 2023-04-06 14:09:34 +02:00
Rosalie Wanders 0fabdb3f3a RMG-Input: account for versions which didn't have the sensitivity setting in main.cpp 2023-04-06 08:56:49 +02:00
Rosalie Wanders 7a64e7e479 RMG: show progress status in the loading screen of the ROM browser 2023-04-06 01:20:48 +02:00
Rosalie Wanders 8c1589d7cd RMG-Core: correct error message in read_7zip_file 2023-04-06 00:37:31 +02:00
Rosalie Wanders 5a74b137f2 RMG: implement 7-Zip support 2023-04-06 00:28:31 +02:00
Rosalie Wanders 52ba182610 RMG-Core: implement 7-Zip support 2023-04-06 00:28:31 +02:00
Rosalie Wanders b07eb79609 3rdParty: add 7-Zip 2023-04-06 00:28:31 +02:00
Rosalie Wanders 4e3915f527 RMG: only show 'Don't check for updates again' checkbox when needed 2023-04-05 16:22:27 +02:00
Rosalie Wanders 9f620f276d RMG-Input: account for versions which didn't have the sensitivity setting 2023-04-05 16:18:56 +02:00
JaxonWasTaken e3787b5ccf RMG-Input: implement "Analog Stick Sensitivity" 2023-03-31 19:47:31 +02:00
Rosalie Wanders 3d81a052c6 cmake: add NO_RUST option 2023-03-25 20:34:37 +01:00
Rosalie Wanders 6353be1599 RMG: expose CoreOverlay_SaveFileNameFormat setting 2023-03-12 21:47:20 +01:00
Rosalie Wanders bc6ee4877b RMG-Core: use {Core,CoreOverlay}_SaveFileNameFormat settings 2023-03-12 21:47:20 +01:00
Rosalie Wanders 6b38cc3740 RMG-Core: introduce {Core,CoreOverlay}_SaveFileNameFormat settings 2023-03-12 21:47:20 +01:00
Rosalie Wanders 9285fb9fdf 3rdParty: update mupen64plus-core 2023-03-12 21:47:19 +01:00
Rosalie Wanders f5c609413a Package: update archlinux PKGBUILD 2023-03-04 23:33:08 +01:00
RetraCarteR a304f11b1d RMG: introduce more columns (#119) 2023-03-04 23:10:01 +01:00
Rosalie Wanders e10ac1086f RMG: show window after opening ROM 2023-02-25 14:45:28 +01:00
Rosalie Wanders 4533ed61ac 3rdParty: update GLideN64 2023-02-25 14:44:15 +01:00
Rosalie Wanders 235e41653d Package: v0.3.8 2023-02-24 22:51:20 +01:00
Rosalie Wanders 433479b1c3 RMG: add date and time to OSD when selecting a save state slot 2023-02-24 22:47:29 +01:00
Rosalie Wanders 2b4736f224 RMG: add actions in MainWindow::Init() when showUI is false 2023-02-24 22:30:01 +01:00
Rosalie Wanders 41f1dcf9d2 RMG: use RomBrowser_ColumnVisibility 2023-02-24 22:19:41 +01:00
Rosalie Wanders 45b97cf39b RMG-Core: rename RomBrowser_Columns to RomBrowser_ColumnVisibility 2023-02-24 22:19:27 +01:00
Rosalie Wanders 95b1225219 3rdParty: update GLideN64 2023-02-24 22:08:43 +01:00
Rosalie Wanders 70f6c40b26 RMG: use Keybinding_ViewLog setting 2023-02-24 21:48:28 +01:00
Rosalie Wanders 43bc54fca9 RMG-Core: add Keybinding_ViewLog setting 2023-02-24 21:48:12 +01:00
Rosalie Wanders a5ec31ffef RMG: hook up state callback 2023-02-24 21:37:24 +01:00
Rosalie Wanders 81cbf82ddc RMG-Core: implement state callback 2023-02-24 21:36:54 +01:00
Rosalie Wanders 6cea506c6f RMG: implement -d/--debug-messages commandline option 2023-02-24 21:14:48 +01:00
Rosalie Wanders d7d49f261d RMG-Core: introduce CoreSetPrintDebugCallback() 2023-02-24 21:14:27 +01:00
Rosalie Wanders 4692a5c0b7 RMG-Core: use string() for std::filesystem::path in CoreGetSaveStatePath() 2023-02-24 20:04:43 +01:00
Rosalie Wanders d32ea32f1e Package: slight corrections to appdata 2023-02-24 19:57:27 +01:00
Rosalie Wanders f5f053cc4e RMG: add date and time to save state slot items in "Current Save State" 2023-02-24 19:54:24 +01:00
Rosalie Wanders bb3c6dc9fc RMG-Core: introduce CoreGetSaveStatePath() 2023-02-24 19:52:13 +01:00
RetraCarteR 496d4de1de RMG: slightly refactor RomBrowserWidget.cpp (#113) 2023-02-24 18:50:18 +01:00
Rosalie Wanders 71f8437ecb RMG: fix crash in RomBrowserWidget::on_RomBrowserThread_Finished() 2023-02-24 18:40:54 +01:00
Rosalie Wanders e7767105d6 RMG: simplify sanitizing filename in RomBrowserWidget 2023-02-24 00:46:07 +01:00
RetraCarteR 9cfda8514e RMG: implement toggling visibility for columns (#111) 2023-02-24 00:13:51 +01:00
Rosalie Wanders e0c6700a4d RMG: add info about LLE plugins to settings dialog 2023-02-23 22:10:57 +01:00
Rosalie Wanders 12bf158398 RMG: slightly refactor MainWindow.{cpp,hpp} 2023-02-23 21:38:21 +01:00
Rosalie Wanders ea01c86821 RMG: check for updates once an hour and add 'Check For Updates' to View 2023-02-23 15:45:32 +01:00
Rosalie Wanders 96459432a6 RMG-Core: add GUI_LastUpdateCheck setting 2023-02-23 15:36:15 +01:00
Rosalie Wanders 089194c663 Package: add version to AppImage filename 2023-02-23 14:54:28 +01:00
Rosalie Wanders 7a70227535 RMG: handle SIGINT and SIGTERM 2023-02-23 14:42:59 +01:00
Rosalie Wanders 7adfb3123b RMG: use new settings hotkeys 2023-02-23 14:31:19 +01:00
Rosalie Wanders 1d28075601 RMG-Input: add more settings hotkeys 2023-02-23 14:30:43 +01:00
Rosalie Wanders af7aa688bb RMG: implement -n/--nogui commandline option 2023-02-23 14:08:24 +01:00
Rosalie Wanders beb524f523 RMG: keep trying to set video size until it succeeds 2023-02-23 13:57:21 +01:00
Rosalie 18c9c151a8 RMG: hide AppImage commandline options 2023-02-23 09:07:00 +01:00
Rosalie Wanders 83820baf79 Package: v0.3.7 2023-02-19 22:42:49 +01:00
Rosalie Wanders abf50350e7 RMG: account for full path in plugin settings 2023-02-19 22:40:17 +01:00
Rosalie Wanders 6588d0d17a RMG: account for invalid GUI_IconTheme setting value 2023-02-19 22:35:31 +01:00
Rosalie Wanders 648736df48 Package: correct PKGBUILD 2023-02-19 19:22:29 +01:00
Rosalie Wanders 6278a443df ci: add appstream to ubuntu packages 2023-02-19 19:21:45 +01:00
Rosalie Wanders 615295f1f9 Package: v0.3.6 2023-02-19 13:20:57 +01:00
Rosalie Wanders 593135d02b gitignore: add AppImage things 2023-02-19 12:57:42 +01:00
Rosalie Wanders 78ea41a2ca RMG: always go back to ROM Browser when the plugins aren't ready 2023-02-19 12:56:54 +01:00
Rosalie Wanders 105600878e cmake: only allow AppImage updater on linux 2023-02-19 12:33:19 +01:00
Rosalie Wanders 415202e15f RMG: set original file permissions to updated AppImage 2023-02-19 12:28:36 +01:00
Rosalie Wanders 618a6f6c9f Package: change ArchLinux PKGBUILD to use the latest version 2023-02-19 01:01:24 +01:00
Rosalie Wanders af70f35bf2 README: add Download section 2023-02-19 01:01:24 +01:00
Rosalie Wanders 43bb0a3a1c ci: add -DUPDATER=ON -DAPPIMAGE_UPDATER=ON to AppImage build 2023-02-19 01:01:24 +01:00
Rosalie Wanders 8d9f83b1cc RMG: implement AppImage updater 2023-02-19 01:01:24 +01:00
Rosalie Wanders 7d713afbdd cmake: add APPIMAGE_UPDATER option 2023-02-19 01:01:24 +01:00
Rosalie Wanders 5044ef8ab1 Package: specify OUTPUT in AppImage Create.sh 2023-02-19 01:01:24 +01:00
Rosalie 5b4fe5667a ci: use ubuntu 20.04 LTS and add qt6 backport PPA 2023-02-19 01:01:24 +01:00
Rosalie Wanders a4d3efa087 RMG-Core: use filenames instead of absolute paths for plugins 2023-02-19 01:01:24 +01:00
Rosalie Wanders 9cb8adce55 Package: add AppImage files 2023-02-19 01:01:24 +01:00
Rosalie Wanders c061981de0 ci: build AppImage 2023-02-19 01:01:24 +01:00
Rosalie Wanders b2f76fc436 RMG: allow overriding RMG-Core paths using commandline 2023-02-19 01:01:22 +01:00
Rosalie Wanders dc58fbe900 RMG-Core: add CoreSet*PathOverride functions 2023-02-18 00:46:22 +01:00
Rosalie Wanders 0e80142da1 Package: remove empty description tag from appdata.xml 2023-02-18 00:35:30 +01:00
Rosalie Wanders ee77bc7c9b RMG: use the additional SpeedFactor settings 2023-02-17 22:03:25 +01:00
Rosalie Wanders b978248c03 RMG-Core: add more SpeedFactor settings 2023-02-17 22:02:50 +01:00
Rosalie Wanders 85d2b5be5a RMG: skip non-fatal mupen64plus errors 2023-02-17 21:48:11 +01:00
Rosalie Wanders cee35297d6 cmake: fix default for FORCE_XCB option 2023-02-17 21:38:10 +01:00
Rosalie Wanders edde08849f cmake: add FORCE_XCB option 2023-02-17 21:21:24 +01:00
RetraCarteR f649053e00 Add Ability to Move and Re-order Columns in "Game List" Mode (#105) 2023-02-17 10:45:14 +01:00
Rosalie Wanders 6c6b4bcd3a RMG: add Speed Factor hotkeys to {add,remove}FullscreenActions() 2023-02-16 19:37:40 +01:00
Rosalie Wanders 1fef816572 RMG: move changing speed factor to it's own function & add OSD message 2023-02-14 23:00:55 +01:00
Rosalie Wanders a6203cf6e9 RMG: add speed factor keybindings 2023-02-14 22:53:17 +01:00
Rosalie Wanders 200bb0f6e3 RMG-Core: add speed factor keybinding settings 2023-02-14 22:53:17 +01:00
Rosalie Wanders 1dd2fca3db RMG: add "Speed Factor" to System menubar 2023-02-14 22:37:20 +01:00
Rosalie Wanders 5444f3b807 RMG-Core: introduce SpeedFactor functions 2023-02-14 22:36:15 +01:00
Rosalie Wanders 897d81a188 RMG: add support for stylesheets & GUI_IconTheme setting 2023-02-14 21:12:34 +01:00
Rosalie Wanders eae18c446a RMG-Core: add GUI_IconTheme setting 2023-02-14 21:11:56 +01:00
104 changed files with 8624 additions and 578 deletions
+19 -6
View File
@@ -4,7 +4,7 @@ on: [push, pull_request]
jobs:
Linux:
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
@@ -14,20 +14,33 @@ jobs:
key: Linux
- name: Install Packages
run: |
sudo apt-get purge grub\* --yes --allow-remove-essential
sudo add-apt-repository ppa:okirby/qt6-backports --yes
sudo apt-get -qq update
sudo apt-get upgrade
sudo apt-get -y install cmake ninja-build libhidapi-dev libsamplerate0-dev libspeex-dev libminizip-dev libsdl2-dev libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev pkg-config zlib1g-dev binutils-dev libspeexdsp-dev qt6-base-dev libqt6svg6-dev build-essential nasm git zip
sudo apt-get -y install cmake ninja-build libhidapi-dev libsamplerate0-dev libspeex-dev libminizip-dev libsdl2-dev libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev pkg-config zlib1g-dev binutils-dev libspeexdsp-dev qt6-base-dev libqt6svg6-dev build-essential nasm git zip appstream
- name: Prepare Environment
run: |
echo "GIT_REVISION=$(git describe --tags --always)" >> $GITHUB_ENV
- name: Build RMG (Portable)
run: ./Source/Script/Build.sh Release
- name: Build RMG (AppImage)
run: |
mkdir Build Build/AppImage Bin/ -p
export src_dir="$(pwd)"
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"
cmake --install "$build_dir" --prefix="$bin_dir/usr"
shell: bash
- name: Upload RMG (Portable)
- name: Create AppImage
run: |
./Package/AppImage/Create.sh
shell: bash
- name: Upload RMG (AppImage)
uses: actions/upload-artifact@v3
with:
name: RMG-Portable-Linux64-${{ env.GIT_REVISION }}
path: Bin/Release/*
path: Bin/*.AppImage
Windows:
runs-on: windows-2019
+4 -1
View File
@@ -9,4 +9,7 @@ Package/ArchLinux/rmg/
Package/ArchLinux/src/
Package/ArchLinux/*.pkg.*
# Clangd compile_commands.json
compile_commands.json
compile_commands.json
# AppImage
squashfs-root
*.AppImage
+40 -2
View File
@@ -6,8 +6,12 @@ cmake_minimum_required(VERSION 3.15)
option(PORTABLE_INSTALL "Portable Installation" ON)
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)
project(RMG)
@@ -34,21 +38,40 @@ if (NOT PORTABLE_INSTALL AND (WIN32 OR MSYS))
set(PORTABLE_INSTALL ON)
endif()
if (NOT PORTABLE_INSTALL AND UPDATER)
if (NOT PORTABLE_INSTALL AND UPDATER AND NOT APPIMAGE_UPDATER)
message(WARNING "Not-Portable builds don't support the updater, disabling UPDATER")
set(UPDATER OFF)
endif()
if (APPIMAGE_UPDATER AND (WIN32 OR MSYS))
message(WARNING "AppImage updater not supported on windows, disabling APPIMAGE_UPDATER!")
set(APPIMAGE_UPDATER OFF)
endif()
if (UPDATER AND NOT (WIN32 OR MSYS) AND NOT APPIMAGE_UPDATER)
message(WARNING "Only AppImage updater is supported on linux, disabling UPDATER!")
set(UPDATER OFF)
endif()
if (FORCE_XCB AND (WIN32 OR MSYS))
message(WARNING "XCB Qt platform not supported on windows, disabling FORCE_XCB!")
set(FORCE_XCB OFF)
endif()
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")
@@ -59,11 +82,18 @@ else()
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}
)
@@ -76,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"
)
@@ -88,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
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
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" \
"$@"
+40
View File
@@ -0,0 +1,40 @@
#!/usr/bin/env bash
set -ex
script_dir="$(dirname "$0")"
toplvl_dir="$(realpath "$script_dir/../../")"
bin_dir="$toplvl_dir/Bin/AppImage" # RMG should be installed here
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
curl -L https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage \
-o "$script_dir/linuxdeploy-x86_64.AppImage"
chmod +x "$script_dir/linuxdeploy-x86_64.AppImage"
fi
if [ ! -f "$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage" ]
then
curl -L https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage \
-o "$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage"
chmod +x "$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage"
fi
"$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage" --appimage-extract
"$script_dir/linuxdeploy-x86_64.AppImage" --appimage-extract
# delete appimages
rm "$script_dir/linuxdeploy-x86_64.AppImage" \
"$script_dir/linuxdeploy-plugin-qt-x86_64.AppImage"
"$(pwd)/squashfs-root/AppRun" \
--plugin=qt \
--appdir="$bin_dir" \
--custom-apprun="$script_dir/AppRun" \
--output=appimage \
--desktop-file="$bin_dir/usr/share/applications/com.github.Rosalie241.RMG.desktop"
+14 -24
View File
@@ -1,46 +1,36 @@
# Maintainer: Rosalie Wanders <rosalie@mailbox.org>
_pkgname=rmg
pkgname=${_pkgname}-git
pkgver=git
pkgname=rmg
pkgver=0.4.4
pkgrel=1
pkgdesc="Rosalie's Mupen GUI"
arch=('x86_64')
url="https://github.com/Rosalie241/${_pkgname}"
license=('GPLv3')
arch=('x86_64' 'aarch64')
url="https://github.com/Rosalie241/$pkgname"
license=('GPL3')
provides=("$_pkgname")
conflicts=("$_pkgname")
depends=("hidapi" "libsamplerate" "speexdsp" "minizip" "sdl2" "zlib" "freetype2" "qt6-base" "qt6-svg" "xdg-user-dirs")
makedepends=("git" "nasm" "cmake" "ninja")
depends=("hidapi" "libsamplerate" "minizip" "sdl2" "zlib" "freetype2" "qt6-base" "qt6-svg" "xdg-user-dirs")
makedepends=("git" "pkg-config" "nasm" "cmake" "cargo" "ninja")
source=("git+https://github.com/Rosalie241/${_pkgname}.git")
source=("git+https://github.com/Rosalie241/$pkgname.git#tag=v$pkgver")
sha256sums=('SKIP')
pkgver()
{
cd "$_pkgname"
git describe --tags --always | sed -e 's|^v||;s|-|.|g'
}
prepare()
{
mkdir -p "$srcdir/${_pkgname}/build"
mkdir -p "$srcdir/$pkgname/build"
}
build()
{
cmake -S "$srcdir/${_pkgname}" -B "$srcdir/${_pkgname}/build" \
cmake -S "$srcdir/$pkgname" -B "$srcdir/$pkgname/build" \
-DCMAKE_BUILD_TYPE="Release" \
-DPORTABLE_INSTALL="OFF" \
-DCMAKE_INSTALL_PREFIX="/usr" \
-G "Ninja" \
-DNO_RUST="ON" \
-G "Ninja"
cmake --build "$srcdir/${_pkgname}/build"
cmake --build "$srcdir/$pkgname/build"
}
package()
{
cmake --install "$srcdir/${_pkgname}/build" --prefix="$pkgdir/usr"
cmake --install "$srcdir/$pkgname/build" --prefix="$pkgdir/usr"
}
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

+132 -6
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,28 +12,153 @@
<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>
<description/>
<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>
<ul>
<li>Fix "Don't check for updates again" checkbox appearing when requesting an update check through Help -> Check For Updates</li>
<li>Add game format, file name, file extension, file size, game I.D. and game region columns to the list view of the ROM browser which can be toggled in the "Show/Hide Columns" menu of the context menu in the list view of the ROM browser (thank you RetraCarteR)</li>
<li>Add "Reset Column Sizes" to context menu of the list view of the ROM browser (thank you RetraCarteR)</li>
<li>Add "Analog Stick Sensitivity" setting to RMG-Input (thank you JaxonWasTaken)</li>
<li>Add "Save Filename Format" setting to the Core tab of the settings dialog</li>
<li>Add "Edit Game Input Settings" to the context menu of the ROM browser</li>
<li>Add support for 7z files</li>
<li>Add progress status to the loading screen in the ROM browser when loading takes more than 5 seconds</li>
</ul>
</description>
</release>
<release version="v0.3.8" date="2023-02-24" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix RMG not having the correct video size in some cases (i.e on a WM where resizing is not allowed to be done by an application)</li>
<li>Fix translations not working in GLideN64</li>
<li>Add -n/--nogui commandline option</li>
<li>Add -d/--debug-messages commandline option</li>
<li>Add hotkeys for graphics, audio, RSP and input settings</li>
<li>Add hotkey for viewing the log</li>
<li>Add SIGINT and SIGTERM handling on linux</li>
<li>Add "Check For Updates" to "View" in the toolbar</li>
<li>Add information about LLE plugins in the settings dialog</li>
<li>Add support for toggling visibility of columns in the ROM browser list view (thank you RetraCarteR)</li>
<li>Add date and time to the save state slot items in "Current Save State" menu in the menubar</li>
<li>Add date and time to the OSD when selecting a save state slot</li>
<li>Add failure messages to the OSD when loading/saving a save state fails</li>
<li>Improve updater behavior by checking for an update on startup with at least an hour in-between checks</li>
</ul>
</description>
</release>
<release version="v0.3.7" date="2023-02-19" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix icons not showing up in some cases when migrating from a version before v0.3.6</li>
<li>Fix plugin settings not being loaded properly in the settings dialog when migrating from a version before v0.3.6</li>
</ul>
</description>
</release>
<release version="v0.3.6" date="2023-02-19" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix RMG not using xwayland when using wayland (wayland has lots of issues, can be disabled by building with the "-DFORCE_XCB=OFF" option)</li>
<li>Fix some non-fatal mupen64plus errors showing a pop-up</li>
<li>Fix window not returning to ROM browser when launching a game through the commandline and the plugins aren't ready</li>
<li>Add support for Qt stylesheets (place them in the 'user data directory/Styles' directory with the '.qss' extension, they'll show up in "Themes")</li>
<li>Add "Icon Theme" setting</li>
<li>Add "Speed Factor" to System menu bar</li>
<li>Add support for re-ordering columns in the list view of the ROM browser (thank you RetraCarteR)</li>
<li>Add AppImage to github releases (this replaces the old portable linux builds on github releases)</li>
</ul>
</description>
</release>
<release version="v0.3.5" date="2023-02-14" type="stable">
<description>
<p>Changes:</p>
+14 -1
View File
@@ -4,9 +4,22 @@ Rosalie's Mupen GUI is a free and open-source mupen64plus GUI written in C++.
It offers a simple-to-use user interface.
## Download
#### Windows
You can download Rosalie's Mupen GUI on ![Github Releases](https://github.com/Rosalie241/RMG/releases)
#### Linux
You can download Rosalie's Mupen GUI on
* [Github Releases (AppImage)](https://github.com/Rosalie241/RMG/releases)
* [Flathub (Flatpak)](https://flathub.org/apps/details/com.github.Rosalie241.RMG)
* [Arch User Repository](https://aur.archlinux.org/packages/rmg)
## 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
+40
View File
@@ -0,0 +1,40 @@
#
# 7-Zip CMakeLists.txt
#
project(7Zip)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(7ZIP_SOURCES
${CMAKE_CURRENT_BINARY_DIR}/C/Bcj2.c
${CMAKE_CURRENT_BINARY_DIR}/C/Bra.c
${CMAKE_CURRENT_BINARY_DIR}/C/Bra86.c
${CMAKE_CURRENT_BINARY_DIR}/C/BraIA64.c
${CMAKE_CURRENT_BINARY_DIR}/C/CpuArch.c
${CMAKE_CURRENT_BINARY_DIR}/C/Delta.c
${CMAKE_CURRENT_BINARY_DIR}/C/Lzma2Dec.c
${CMAKE_CURRENT_BINARY_DIR}/C/LzmaDec.c
${CMAKE_CURRENT_BINARY_DIR}/C/Ppmd7.c
${CMAKE_CURRENT_BINARY_DIR}/C/Ppmd7Dec.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zCrc.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zCrcOpt.c
${CMAKE_CURRENT_BINARY_DIR}/C/Sha256.c
${CMAKE_CURRENT_BINARY_DIR}/C/Sha256Opt.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zAlloc.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zArcIn.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zBuf.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zBuf2.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zDec.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zFile.c
${CMAKE_CURRENT_BINARY_DIR}/C/7zStream.c
)
add_custom_command(
OUTPUT ${7ZIP_SOURCES}
COMMAND ${CMAKE_COMMAND} -E tar "xvz" "${CMAKE_CURRENT_SOURCE_DIR}/lzma2301.tar.gz"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
add_definitions(-D_7ZIP_PPMD_SUPPPORT -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE)
add_library(7Zip STATIC ${7ZIP_SOURCES})
+2
View File
@@ -0,0 +1,2 @@
# 7-Zip SDK v23.01
Downloaded from https://www.7-zip.org/sdk.html
Binary file not shown.
+13 -11
View File
@@ -6,7 +6,9 @@ include(ExternalProject)
set(THIRDPARTY_DIR ${CMAKE_BINARY_DIR}/Source/3rdParty)
find_program(RUST_CARGO cargo)
if(${RUST_CARGO} STREQUAL "RUST_CARGO-NOTFOUND")
if(NO_RUST)
set(BUILD_INPUT_GCA OFF)
elseif(${RUST_CARGO} STREQUAL "RUST_CARGO-NOTFOUND")
message(WARNING "mupen64plus-input-gca will not be built due to not having cargo installed")
set(BUILD_INPUT_GCA OFF)
else()
@@ -36,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 "7ee312cb282a7794c62d5d284bf93151c585dd1f")
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")
@@ -46,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")
@@ -55,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/Rosalie241/GLideN64")
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "71dcb55a398a5c4d2bdbfa9fc15b90f301f77a6b")
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "2f1b358028e700fcae2502a53f4f5e6822ce0367")
set(MUPEN64PLUS_GFX_PARALLEL_URL "https://github.com/Rosalie241/parallel-rdp-standalone")
set(MUPEN64PLUS_GFX_PARALLEL_TAG "2c2226517c4c8929e08ec944654867e26efe0cf5")
@@ -70,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
@@ -82,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}
)
@@ -105,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
)
@@ -156,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
+3 -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)
@@ -24,6 +23,7 @@ set(RMG_CORE_SOURCES
ConvertStringEncoding.cpp
Settings/Settings.cpp
SpeedLimiter.cpp
SpeedFactor.cpp
RomSettings.cpp
Directories.cpp
MediaLoader.cpp
@@ -67,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)
@@ -79,6 +79,7 @@ endif(WIN32)
target_link_libraries(RMG-Core
${MINIZIP_LIBRARIES}
7Zip
)
if (DISCORD_RPC)
+75 -2
View File
@@ -9,6 +9,8 @@
*/
#include "CachedRomHeaderAndSettings.hpp"
#include "Directories.hpp"
#include "RomSettings.hpp"
#include "RomHeader.hpp"
#include "Error.hpp"
#include "osal/osal_files.hpp"
@@ -36,11 +38,13 @@
#define ROMHEADER_NAME_LEN 256
#define GOODNAME_LEN 256
#define MD5_LEN 33
#define GAMEID_LEN 5
#define REGION_LEN 18
#ifdef _WIN32
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCacheWindows_05"
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCacheWindows_06"
#else // Linux
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCacheLinux_05"
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCacheLinux_06"
#endif // _WIN32
#define CACHE_FILE_ITEMS_MAX 10000
@@ -103,6 +107,8 @@ void CoreReadRomHeaderAndSettingsCache(void)
char magicBuf[sizeof(CACHE_FILE_MAGIC)];
wchar_t fileNameBuf[MAX_FILENAME_LEN];
char headerNameBuf[ROMHEADER_NAME_LEN];
char gameIDBuf[GAMEID_LEN];
char regionBuf[REGION_LEN];
char goodNameBuf[GOODNAME_LEN];
char md5Buf[MD5_LEN];
uint32_t size;
@@ -131,6 +137,8 @@ void CoreReadRomHeaderAndSettingsCache(void)
size = 0;
memset(fileNameBuf, 0, sizeof(fileNameBuf));
memset(headerNameBuf, 0, sizeof(headerNameBuf));
memset(gameIDBuf, 0, sizeof(gameIDBuf));
memset(regionBuf, 0, sizeof(regionBuf));
memset(goodNameBuf, 0, sizeof(goodNameBuf));
memset(md5Buf, 0, sizeof(md5Buf));
@@ -144,7 +152,13 @@ void CoreReadRomHeaderAndSettingsCache(void)
// header
FREAD(size);
FREAD_STR(headerNameBuf, size);
FREAD(size);
FREAD_STR(gameIDBuf, size);
FREAD(size);
FREAD_STR(regionBuf, size);
cacheEntry.header.Name = std::string(headerNameBuf);
cacheEntry.header.GameID = std::string(gameIDBuf);
cacheEntry.header.Region = std::string(regionBuf);
FREAD(cacheEntry.header.CRC1);
FREAD(cacheEntry.header.CRC2);
// (partial) settings
@@ -169,6 +183,8 @@ bool CoreSaveRomHeaderAndSettingsCache(void)
std::ofstream outputStream;
wchar_t fileNameBuf[MAX_FILENAME_LEN];
char headerNameBuf[ROMHEADER_NAME_LEN];
char gameIDBuf[GAMEID_LEN];
char regionBuf[REGION_LEN];
char goodNameBuf[GOODNAME_LEN];
char md5Buf[MD5_LEN];
uint32_t size;
@@ -200,12 +216,16 @@ bool CoreSaveRomHeaderAndSettingsCache(void)
size = 0;
memset(fileNameBuf, 0, sizeof(fileNameBuf));
memset(headerNameBuf, 0, sizeof(headerNameBuf));
memset(gameIDBuf, 0, sizeof(gameIDBuf));
memset(regionBuf, 0, sizeof(regionBuf));
memset(goodNameBuf, 0, sizeof(goodNameBuf));
memset(md5Buf, 0, sizeof(md5Buf));
// copy strings into buffers
wcsncpy(fileNameBuf, cacheEntry.fileName.wstring().c_str(), MAX_FILENAME_LEN);
strncpy(headerNameBuf, cacheEntry.header.Name.c_str(), sizeof(headerNameBuf));
strncpy(gameIDBuf, cacheEntry.header.GameID.c_str(), sizeof(gameIDBuf));
strncpy(regionBuf, cacheEntry.header.Region.c_str(), sizeof(regionBuf));
strncpy(goodNameBuf, cacheEntry.settings.GoodName.c_str(), sizeof(goodNameBuf));
strncpy(md5Buf, cacheEntry.settings.MD5.c_str(), sizeof(md5Buf));
@@ -220,6 +240,12 @@ bool CoreSaveRomHeaderAndSettingsCache(void)
size = cacheEntry.header.Name.size();
FWRITE(size);
FWRITE_STR(headerNameBuf, size);
size = cacheEntry.header.GameID.size();
FWRITE(size);
FWRITE_STR(gameIDBuf, size);
size = cacheEntry.header.Region.size();
FWRITE(size);
FWRITE_STR(regionBuf, size);
FWRITE(cacheEntry.header.CRC1);
FWRITE(cacheEntry.header.CRC2);
// (partial) settings
@@ -283,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);
+47 -5
View File
@@ -11,12 +11,20 @@
#include "Core.hpp"
#include "ConvertStringEncoding.hpp"
#include <iostream>
//
// Local Variables
//
static bool l_SetupCallbacks = false;
static std::function<void(enum CoreDebugMessageType, std::string, std::string)> l_DebugCallbackFunc;
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
@@ -24,14 +32,19 @@ static std::function<void(enum CoreDebugMessageType, std::string, std::string)>
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:"))
{
@@ -47,16 +60,45 @@ void CoreDebugCallback(void* context, int level, const char* message)
void CoreStateCallback(void* context, m64p_core_param param, int value)
{
// TODO
if (!l_SetupCallbacks)
{
return;
}
l_StateCallbackFunc((CoreStateCallbackType)param, value);
}
//
// Exported Functions
//
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string, std::string)> debugCallbackFunc)
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string, std::string)> debugCallbackFunc,
std::function<void(enum CoreStateCallbackType, int)> stateCallbackFunc)
{
l_DebugCallbackFunc = debugCallbackFunc;
l_StateCallbackFunc = stateCallbackFunc;
l_SetupCallbacks = true;
return true;
}
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());
}
+30 -1
View File
@@ -32,6 +32,35 @@ enum class CoreDebugMessageType
Verbose = 5
};
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string, std::string)> debugCallbackFunc);
enum class CoreStateCallbackType
{
EmulationState = 1,
VideoMode,
SaveStateSlot,
SpeedFactor,
SpeedLimiter,
VideoSize,
AudioVolume,
AudioMute,
GamesharkInput,
SaveStateLoaded,
SaveStateSaved,
ScreenshotCaptured,
};
// attempts to setup callbacks with the provided functions
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string, std::string)> debugCallbackFunc,
std::function<void(enum CoreStateCallbackType, int)> stateCallbackFunc);
// 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();
+1
View File
@@ -13,6 +13,7 @@
#include "CachedRomHeaderAndSettings.hpp"
#include "Settings/Settings.hpp"
#include "SpeedLimiter.hpp"
#include "SpeedFactor.hpp"
#include "RomSettings.hpp"
#include "Directories.hpp"
#include "MediaLoader.hpp"
+77 -6
View File
@@ -18,6 +18,15 @@
#include <iostream>
#include <filesystem>
//
// 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;
//
// Local Functions
//
@@ -117,14 +126,40 @@ 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;
#ifdef PORTABLE_INSTALL
directory = "Core";
#else // Not Portable
directory = CORE_INSTALL_PREFIX;
directory += "/lib/RMG/Core";
if (!l_CorePathOverride.empty())
{
directory = l_CorePathOverride;
}
else
{
directory = CORE_INSTALL_PREFIX;
directory += "/lib/RMG/Core";
}
#endif // PORTABLE_INSTALL
return directory;
}
@@ -135,8 +170,15 @@ std::filesystem::path CoreGetPluginDirectory(void)
#ifdef PORTABLE_INSTALL
directory = "Plugin";
#else // Not Portable
directory = CORE_INSTALL_PREFIX;
directory += "/lib/RMG/Plugin";
if (!l_PluginPathOverride.empty())
{
directory = l_PluginPathOverride;
}
else
{
directory = CORE_INSTALL_PREFIX;
directory += "/lib/RMG/Plugin";
}
#endif // PORTABLE_INSTALL
return directory;
}
@@ -233,8 +275,15 @@ std::filesystem::path CoreGetSharedDataDirectory(void)
#ifdef PORTABLE_INSTALL
directory = "Data";
#else // Not Portable
directory = CORE_INSTALL_PREFIX;
directory += "/share/RMG";
if (!l_SharedDataPathOverride.empty())
{
directory = l_SharedDataPathOverride;
}
else
{
directory = CORE_INSTALL_PREFIX;
directory += "/share/RMG";
}
#endif // PORTABLE_INSTALL
return directory;
}
@@ -253,3 +302,25 @@ std::filesystem::path CoreGetScreenshotDirectory(void)
{
return CoreSettingsGetStringValue(SettingsID::Core_ScreenshotPath);
}
#ifndef PORTABLE_INSTALL
void CoreSetLibraryPathOverride(std::filesystem::path path)
{
l_LibraryPathOverride = path;
}
void CoreSetCorePathOverride(std::filesystem::path path)
{
l_CorePathOverride = path;
}
void CoreSetPluginPathOverride(std::filesystem::path path)
{
l_PluginPathOverride = path;
}
void CoreSetSharedDataPathOverride(std::filesystem::path path)
{
l_SharedDataPathOverride = path;
}
#endif // PORTABLE_INSTALL
+16
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,4 +77,16 @@ 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);
// changes the plugin path to the given path
void CoreSetPluginPathOverride(std::filesystem::path path);
// changes the shared data path to the given path
void CoreSetSharedDataPathOverride(std::filesystem::path path);
#endif // DIRECTORIES_HPP
+6 -1
View File
@@ -54,6 +54,7 @@ static void apply_coresettings_overlay(void)
CoreSettingsSetValue(SettingsID::Core_CountPerOp, CoreSettingsGetIntValue(SettingsID::CoreOverlay_CountPerOp));
CoreSettingsSetValue(SettingsID::Core_CountPerOpDenomPot, CoreSettingsGetIntValue(SettingsID::CoreOverlay_CountPerOpDenomPot));
CoreSettingsSetValue(SettingsID::Core_SiDmaDuration, CoreSettingsGetIntValue(SettingsID::CoreOverlay_SiDmaDuration));
CoreSettingsSetValue(SettingsID::Core_SaveFileNameFormat, CoreSettingsGetIntValue(SettingsID::CoreOverLay_SaveFileNameFormat));
}
static void apply_game_coresettings_overlay(void)
@@ -157,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();
@@ -174,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);
+145 -44
View File
@@ -16,10 +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>
@@ -131,6 +131,54 @@ std::string get_plugin_context_name(CorePluginType type)
return name;
}
std::string get_plugin_path(CorePluginType type, std::string settingsValue)
{
std::string pluginPath;
std::string path;
std::string typeName;
// return an empty string when the value is empty
if (settingsValue.empty())
{
return std::string();
}
pluginPath = CoreGetPluginDirectory().string();
// if the full plugin path is in the settings value,
// we know it's the old type
if (settingsValue.find(pluginPath) != std::string::npos)
{
return settingsValue;
}
switch (type)
{
case CorePluginType::Rsp:
typeName = "RSP";
break;
case CorePluginType::Gfx:
typeName = "GFX";
break;
case CorePluginType::Audio:
typeName = "Audio";
break;
case CorePluginType::Input:
typeName = "Input";
break;
default:
return path;
}
path = pluginPath;
path += OSAL_FILES_DIR_SEPERATOR_STR;
path += typeName;
path += OSAL_FILES_DIR_SEPERATOR_STR;
path += settingsValue;
return path;
}
bool apply_plugin_settings(std::string pluginSettings[4])
{
std::string error;
@@ -142,15 +190,14 @@ bool apply_plugin_settings(std::string pluginSettings[4])
for (int i = 0; i < 4; i++)
{
settingValue = pluginSettings[i];
pluginType = (CorePluginType)(i + 1);
settingValue = get_plugin_path(pluginType, pluginSettings[i]);
if (settingValue.empty() ||
!std::filesystem::is_regular_file(settingValue))
{ // skip invalid setting value
continue;
}
pluginType = (CorePluginType)(i + 1);
// copy context string to a c string using strcpy
std::strcpy(l_PluginContext[(int)pluginType], get_plugin_context_name(pluginType).c_str());
@@ -237,6 +284,78 @@ bool apply_plugin_settings(std::string pluginSettings[4])
return true;
}
bool open_plugin_config(CorePluginType type, bool romConfig)
{
std::string error;
m64p_error ret;
bool resumeEmulation = false;
m64p::PluginApi* plugin;
std::string functionName;
if (!romConfig && !CorePluginsHasConfig(type))
{
error = "open_plugin_config Failed: ";
error += get_plugin_type_name(type);
error += " doesn't have the config or config2 function!";
CoreSetError(error);
return false;
}
else if (romConfig && !CorePluginsHasROMConfig(type))
{
error = "open_plugin_config Failed: ";
error += get_plugin_type_name(type);
error += " doesn't support ROM specific configuration!";
CoreSetError(error);
return false;
}
// try to pause emulation,
// when emulation is running
// and try to resume afterwards
if (CoreIsEmulationRunning())
{
// only resume emulation
// after running the config function
// when pausing succeeds
resumeEmulation = CorePauseEmulation();
}
plugin = get_plugin(type);
// check if the plugin has the Config2
// or Config function, the Config2 function
// has priority
if (plugin->Config2 != nullptr)
{
ret = plugin->Config2(romConfig ? 1 : 0);
functionName = "Config2";
}
else
{
ret = plugin->Config();
functionName = "Config";
}
if (ret != M64ERR_SUCCESS)
{
error = "CorePluginsOpenConfig (";
error += get_plugin_type_name(type);
error += ")->";
error += functionName;
error += "() Failed: ";
error += m64p::Core.ErrorMessage(ret);
CoreSetError(error);
}
// try to resume emulation when needed
if (resumeEmulation)
{
CoreResumeEmulation();
}
return ret == M64ERR_SUCCESS;
}
//
// Exported Functions
//
@@ -252,6 +371,7 @@ std::vector<CorePlugin> CoreGetAllPlugins(void)
for (const auto& entry : std::filesystem::recursive_directory_iterator(CoreGetPluginDirectory()))
{
std::string path = entry.path().string();
std::string file = entry.path().filename().string();
if (!entry.is_directory() &&
path.ends_with(OSAL_DYNLIB_LIB_EXT_STR))
{
@@ -272,7 +392,7 @@ std::vector<CorePlugin> CoreGetAllPlugins(void)
continue;
}
CorePlugin corePlugin = {path, plugin_name, plugin_type};
CorePlugin corePlugin = {file, plugin_name, plugin_type};
plugins.emplace_back(corePlugin);
}
}
@@ -335,52 +455,33 @@ bool CoreArePluginsReady(void)
bool CorePluginsHasConfig(CorePluginType type)
{
return get_plugin(type)->Config != nullptr;
m64p::PluginApi* plugin;
plugin = get_plugin(type);
return plugin->Config != nullptr ||
plugin->Config2 != nullptr;
}
bool CorePluginsOpenConfig(CorePluginType type)
{
std::string error;
m64p_error ret;
bool resumeEmulation = false;
return open_plugin_config(type, false);
}
if (!CorePluginsHasConfig(type))
{
error = "CorePluginsOpenConfig Failed: ";
error += get_plugin_type_name(type);
error += " doesn't have config function!";
CoreSetError(error);
return false;
}
bool CorePluginsHasROMConfig(CorePluginType type)
{
m64p::PluginApi* plugin;
// try to pause emulation,
// when emulation is running
// and try to resume afterwards
if (CoreIsEmulationRunning())
{
// only resume emulation
// after running the config function
// when pausing succeeds
resumeEmulation = CorePauseEmulation();
}
plugin = get_plugin(type);
ret = get_plugin(type)->Config();
if (ret != M64ERR_SUCCESS)
{
error = "CorePluginsOpenConfig (";
error += get_plugin_type_name(type);
error += ")->Config() Failed: ";
error += m64p::Core.ErrorMessage(ret);
CoreSetError(error);
}
return plugin->Config2 != nullptr &&
plugin->Config2HasRomConfig != nullptr &&
plugin->Config2HasRomConfig() > 0;
}
// try to resume emulation when needed
if (resumeEmulation)
{
CoreResumeEmulation();
}
return ret == M64ERR_SUCCESS;
bool CorePluginsOpenROMConfig(CorePluginType type)
{
return open_plugin_config(type, true);
}
bool CoreAttachPlugins(void)
+8
View File
@@ -52,6 +52,14 @@ bool CorePluginsHasConfig(CorePluginType type);
// used plugin of given type
bool CorePluginsOpenConfig(CorePluginType type);
// returns wether the currently used plugin
// of the given type has a ROM config GUI
bool CorePluginsHasROMConfig(CorePluginType type);
// opens the ROM config GUI for the currently
// used plugin of given type
bool CorePluginsOpenROMConfig(CorePluginType type);
// attaches all used plugins
bool CoreAttachPlugins(void);
+207 -13
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,7 +16,18 @@
#include "RomSettings.hpp"
#include "Cheats.hpp"
#include "osal/osal_files.hpp"
#include "CachedRomHeaderAndSettings.hpp"
// 7-Zip includes
#include "../3rdParty/7-Zip/C/7zTypes.h"
#include "../3rdParty/7-Zip/C/7z.h"
#include "../3rdParty/7-Zip/C/7zAlloc.h"
#include "../3rdParty/7-Zip/C/7zBuf.h"
#include "../3rdParty/7-Zip/C/7zCrc.h"
#include "../3rdParty/7-Zip/C/7zFile.h"
#include "../3rdParty/7-Zip/C/7zVersion.h"
#include <string>
#include <unzip.h>
#include <fstream>
#include <cstdlib>
@@ -36,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
@@ -125,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;
@@ -140,7 +151,7 @@ static bool read_zip_file(std::filesystem::path file, std::filesystem::path* ext
filefuncs.zclose_file = zlib_filefunc_close;
filefuncs.zerror_file = zlib_filefunc_testerror;
filefuncs.opaque = nullptr;
zipFile = unzOpen2_64((const void*)&file, &filefuncs);
if (zipFile == nullptr)
{
@@ -168,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];
@@ -293,6 +304,155 @@ static bool read_zip_file(std::filesystem::path file, std::filesystem::path* ext
return false;
}
static bool read_7zip_file(std::filesystem::path file, std::filesystem::path* extractedFileName, bool* isDisk, char** buf, int* size)
{
std::string error;
const ISzAlloc alloc = { SzAlloc, SzFree };
const size_t bufSize = ((size_t)1 << 18);
ISzAlloc allocImp;
ISzAlloc allocTempImp;
CFileInStream archiveStream;
CLookToRead2 lookStream;
CSzArEx db;
SRes res;
// initialize allocator
allocImp = alloc;
allocTempImp = alloc;
// try to open file
#ifdef _WIN32
WRes wres = InFile_OpenW(&archiveStream.file, file.wstring().c_str());
#else
WRes wres = InFile_Open(&archiveStream.file, file.string().c_str());
#endif // _WIN32
if (wres != 0)
{
error = "read_7zip_file Failed: InFile_Open Failed: ";
error += std::to_string(wres);
CoreSetError(error);
return false;
}
// create vtables for streams
FileInStream_CreateVTable(&archiveStream);
archiveStream.wres = 0;
LookToRead2_CreateVTable(&lookStream, 0);
lookStream.buf = nullptr;
// allocate memory look reader
lookStream.buf = (Byte*)ISzAlloc_Alloc(&allocImp, bufSize);
if (lookStream.buf == nullptr)
{
error = "read_7zip_file Failed: ISzAlloc_Alloc Failed!";
CoreSetError(error);
return false;
}
// initialize look reader
lookStream.bufSize = bufSize;
lookStream.realStream = &archiveStream.vt;
LookToRead2_INIT(&lookStream);
// initialize CRC table
CrcGenerateTable();
// initialize archive
SzArEx_Init(&db);
// try to open file
res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp);
if (res != SZ_OK)
{
error = "read_7zip_file Failed: SzArEx_Open Failed: ";
error += std::to_string(res);
CoreSetError(error);
SzArEx_Free(&db, &allocImp);
ISzAlloc_Free(&allocImp, lookStream.buf);
return false;
}
for (uint32_t i = 0; i < db.NumFiles; i++)
{
size_t filename_size = 0;
uint16_t fileName[PATH_MAX];
// skip directories
if (SzArEx_IsDir(&db, i))
{
continue;
}
// skip when filename size exceeds our buffer size
filename_size = SzArEx_GetFileNameUtf16(&db, i, nullptr);
if (filename_size > PATH_MAX)
{
continue;
}
SzArEx_GetFileNameUtf16(&db, i, fileName);
std::filesystem::path fileNamePath((char16_t*)fileName);
std::string fileExtension = fileNamePath.has_extension() ? fileNamePath.extension().string() : "";
fileExtension = to_lower_str(fileExtension);
if (fileExtension == ".z64" ||
fileExtension == ".v64" ||
fileExtension == ".n64" ||
fileExtension == ".ndd" ||
fileExtension == ".d64")
{
uint32_t blockIndex = 0xFFFFFFFF;
uint8_t* outBuffer = nullptr;
size_t outBufferSize = 0;
size_t offset = 0;
size_t outSizeProcessed = 0;
res = SzArEx_Extract(&db, &lookStream.vt, i,
&blockIndex, &outBuffer, &outBufferSize,
&offset, &outSizeProcessed,
&allocImp, &allocTempImp);
if (res != SZ_OK)
{
error = "read_7zip_file Failed: SzArEx_Extract Failed: ";
error += std::to_string(res);
CoreSetError(error);
SzArEx_Free(&db, &allocImp);
ISzAlloc_Free(&allocImp, lookStream.buf);
File_Close(&archiveStream.file);
ISzAlloc_Free(&allocImp, outBuffer);
return false;
}
*size = outSizeProcessed;
// we have to memcpy it into buf, otherwise
// the free() in CoreOpenRom() crashes
*buf = (char*)malloc(outSizeProcessed);
memcpy(*buf, (outBuffer + offset), outSizeProcessed);
*extractedFileName = fileNamePath;
*isDisk = (fileExtension == ".ndd" || fileExtension == ".d64");
SzArEx_Free(&db, &allocImp);
ISzAlloc_Free(&allocImp, lookStream.buf);
File_Close(&archiveStream.file);
ISzAlloc_Free(&allocImp, outBuffer);
return true;
}
}
// cleanup
SzArEx_Free(&db, &allocImp);
ISzAlloc_Free(&allocImp, lookStream.buf);
File_Close(&archiveStream.file);
error = "read_7zip_file Failed: no valid ROMs found in 7zip!";
CoreSetError(error);
return false;
}
static bool read_raw_file(std::filesystem::path file, char** buf, int* size)
{
std::string error;
@@ -362,7 +522,6 @@ static bool write_file(std::filesystem::path file, char* buf, int size)
// write buffer to file
fileStream.write(buf, size);
fileStream.close();
return true;
}
@@ -395,14 +554,25 @@ bool CoreOpenRom(std::filesystem::path file)
file_extension = file.has_extension() ? file.extension().string() : "";
file_extension = to_lower_str(file_extension);
if (file_extension == ".zip")
if (file_extension == ".zip" ||
file_extension == ".7z")
{
std::filesystem::path extracted_file;
bool is_disk = false;
if (!read_zip_file(file, &extracted_file, &is_disk, &buf, &buf_size))
if (file_extension == ".zip")
{
return false;
if (!read_zip_file(file, &extracted_file, &is_disk, &buf, &buf_size))
{
return false;
}
}
else
{
if (!read_7zip_file(file, &extracted_file, &is_disk, &buf, &buf_size))
{
return false;
}
}
if (is_disk)
@@ -415,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 (...)
@@ -430,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;
}
@@ -474,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);
}
@@ -487,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;
@@ -517,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);
+94 -1
View File
@@ -21,6 +21,97 @@
#include "Error.hpp"
#include "Rom.hpp"
//
// Local Functions
//
static std::string get_gameid_from_header(m64p_rom_header header)
{
std::string gameID;
if (header.Manufacturer_ID == 0)
{
return "????";
}
gameID.push_back(char(ntohl(header.Manufacturer_ID)));
gameID.push_back(char(header.Cartridge_ID % 256));
gameID.push_back(char(header.Cartridge_ID / 256));
gameID.push_back(char(header.Country_code));
return gameID;
}
static std::string get_region_from_countrycode(char countryCode)
{
std::string region;
switch (countryCode)
{
case 'A':
region = "Region-Free";
break;
case 'B':
region = "Brazil";
break;
case 'C':
region = "China";
break;
case 'D':
region = "Germany";
break;
case 'E':
region = "North America";
break;
case 'F':
region = "France";
break;
case 'G':
region = "Gateway 64 (NTSC)";
break;
case 'H':
region = "Netherlands";
break;
case 'I':
region = "Italy";
break;
case 'J':
region = "Japan";
break;
case 'K':
region = "Korea";
break;
case 'L':
region = "Gateway 64 (PAL)";
break;
case 'N':
region = "Canada";
break;
case 'P':
case 'X':
region = "Europe/Australia";
break;
case 'S':
region = "Spain";
break;
case 'U':
region = "Australia";
break;
case 'W':
region = "Scandanavia";
break;
case 'Y':
case 'Z':
region = "Europe";
break;
default:
region = "Unknown";
break;
}
return region;
}
//
// Exported Functions
//
@@ -49,6 +140,8 @@ bool CoreGetCurrentRomHeader(CoreRomHeader& header)
header.CRC2 = ntohl(m64p_header.CRC2);
header.CountryCode = m64p_header.Country_code;
header.Name = CoreConvertStringEncoding((char*)m64p_header.Name, CoreStringEncoding::Shift_JIS);
header.GameID = get_gameid_from_header(m64p_header);
header.Region = get_region_from_countrycode((char)header.CountryCode);
return true;
}
+2
View File
@@ -19,6 +19,8 @@ struct CoreRomHeader
uint32_t CRC2;
uint32_t CountryCode;
std::string Name;
std::string GameID;
std::string Region;
};
// retrieves the currently opened ROM header
+151
View File
@@ -8,10 +8,33 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "SaveState.hpp"
#include "Directories.hpp"
#include "RomSettings.hpp"
#include "RomHeader.hpp"
#include "Error.hpp"
#include "Settings/Settings.hpp"
#include "m64p/Api.hpp"
#include <algorithm>
//
// Local Functions
//
// 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 (uint32_t i = 0; i < str.size(); i++)
{
char str_char = str.at(i);
if (replace.find(str_char) != std::string::npos)
{
str.at(i) = c;
}
}
}
//
// Exported Functions
//
@@ -59,6 +82,134 @@ 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
// in mupen64plus-core instead
std::filesystem::path saveStatePath;
std::filesystem::path oldSaveStatePath;
std::string saveStateFileName;
std::filesystem::path saveStateExtension;
CoreRomHeader romHeader;
CoreRomSettings romSettings;
// attempt to retrieve the current
// rom header and settings
if (!CoreGetCurrentRomHeader(romHeader) ||
!CoreGetCurrentRomSettings(romSettings))
{
return false;
}
// retrieve save state directory
saveStatePath = CoreGetSaveStateDirectory();
saveStatePath += "/";
// construct extension
saveStateExtension = ".st";
saveStateExtension += std::to_string(slot);
// construct old save state path
oldSaveStatePath = saveStatePath;
oldSaveStatePath += romSettings.GoodName;
oldSaveStatePath += saveStateExtension;
// use old filename if it exists
if (std::filesystem::is_regular_file(oldSaveStatePath))
{
path = oldSaveStatePath;
return true;
}
// else use new filename
int format = CoreSettingsGetIntValue(SettingsID::Core_SaveFileNameFormat);
if (format == 0)
{
saveStatePath += romHeader.Name;
saveStatePath += saveStateExtension;
}
else
{
if (romSettings.GoodName.find("(unknown rom)") == std::string::npos)
{
if (romSettings.GoodName.size() < 32)
{
saveStatePath += romSettings.GoodName;
}
else
{
saveStatePath += romSettings.GoodName.substr(0, 32);
}
}
else if (!romHeader.Name.empty())
{
saveStatePath += romHeader.Name;
}
else
{
saveStatePath += "unknown";
}
saveStatePath += "-";
saveStatePath += romSettings.MD5.substr(0, 8);
saveStatePath += saveStateExtension;
}
// retrieve filename from path
saveStateFileName = saveStatePath.filename().string();
// sanitize filename
str_replace_chars(saveStateFileName, ":<>\"/\\|?*", '_');
// replace filename in path
saveStatePath.replace_filename(saveStateFileName);
path = saveStatePath;
return true;
}
bool CoreSaveState(void)
{
std::string error;
+10
View File
@@ -19,6 +19,16 @@ 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);
// saves state
bool CoreSaveState(void);
+568 -16
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,15 +185,24 @@ 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;
case SettingsID::GUI_Theme:
setting = {SETTING_SECTION_GUI, "Theme", "Native"};
break;
case SettingsID::GUI_IconTheme:
setting = {SETTING_SECTION_GUI, "IconTheme", "Automatic"};
break;
case SettingsID::GUI_CheckForUpdates:
setting = {SETTING_SECTION_GUI, "CheckForUpdates", true};
break;
case SettingsID::GUI_LastUpdateCheck:
setting = {SETTING_SECTION_GUI, "LastUpdateCheck", ""};
break;
case SettingsID::GUI_DiscordRpc:
setting = {SETTING_SECTION_GUI, "DiscordRpc", true};
break;
@@ -202,36 +213,36 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::Core_GFX_Plugin:
setting = {SETTING_SECTION_CORE, "GFX_Plugin",
#ifdef _WIN32
CoreGetPluginDirectory().string() + "\\GFX\\mupen64plus-video-GLideN64.dll",
"mupen64plus-video-GLideN64.dll",
#else
CoreGetPluginDirectory().string() + "/GFX/mupen64plus-video-GLideN64.so",
"mupen64plus-video-GLideN64.so",
#endif // _WIN32
};
break;
case SettingsID::Core_AUDIO_Plugin:
setting = {SETTING_SECTION_CORE, "AUDIO_Plugin",
#ifdef _WIN32
CoreGetPluginDirectory().string() + "\\Audio\\RMG-Audio.dll",
"RMG-Audio.dll",
#else
CoreGetPluginDirectory().string() + "/Audio/RMG-Audio.so",
"RMG-Audio.so",
#endif // _WIN32
};
break;
case SettingsID::Core_INPUT_Plugin:
setting = {SETTING_SECTION_CORE, "INPUT_Plugin",
#ifdef _WIN32
CoreGetPluginDirectory().string() + "\\Input\\RMG-Input.dll",
"RMG-Input.dll",
#else
CoreGetPluginDirectory().string() + "/Input/RMG-Input.so",
"RMG-Input.so",
#endif // _WIN32
};
break;
case SettingsID::Core_RSP_Plugin:
setting = {SETTING_SECTION_CORE, "RSP_Plugin",
#ifdef _WIN32
CoreGetPluginDirectory().string() + "\\RSP\\mupen64plus-rsp-hle.dll",
"mupen64plus-rsp-hle.dll",
#else
CoreGetPluginDirectory().string() + "/RSP/mupen64plus-rsp-hle.so",
"mupen64plus-rsp-hle.so",
#endif // _WIN32
};
break;
@@ -271,6 +282,9 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::Core_SiDmaDuration:
setting = {SETTING_SECTION_M64P, "SiDmaDuration", -1};
break;
case SettingsID::Core_SaveFileNameFormat:
setting = {SETTING_SECTION_M64P, "SaveFilenameFormat", 1};
break;
case SettingsID::CoreOverlay_RandomizeInterrupt:
setting = {SETTING_SECTION_OVERLAY, "RandomizeInterrupt", true};
@@ -293,6 +307,9 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::CoreOverlay_SiDmaDuration:
setting = {SETTING_SECTION_OVERLAY, "SiDmaDuration", -1};
break;
case SettingsID::CoreOverLay_SaveFileNameFormat:
setting = {SETTING_SECTION_OVERLAY, "SaveFilenameFormat", 1};
break;
case SettingsID::Core_ScreenshotPath:
setting = {SETTING_SECTION_M64P, "ScreenshotPath", CoreGetDefaultScreenshotDirectory(), "", true};
@@ -417,6 +434,42 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::KeyBinding_LimitFPS:
setting = {SETTING_SECTION_KEYBIND, "LimitFPS", "F4"};
break;
case SettingsID::KeyBinding_SpeedFactor25:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor25", "Alt+0"};
break;
case SettingsID::KeyBinding_SpeedFactor50:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor50", "Alt+1"};
break;
case SettingsID::KeyBinding_SpeedFactor75:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor75", "Alt+2"};
break;
case SettingsID::KeyBinding_SpeedFactor100:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor100", "Alt+3"};
break;
case SettingsID::KeyBinding_SpeedFactor125:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor125", "Alt+4"};
break;
case SettingsID::KeyBinding_SpeedFactor150:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor150", "Alt+5"};
break;
case SettingsID::KeyBinding_SpeedFactor175:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor175", "Alt+6"};
break;
case SettingsID::KeyBinding_SpeedFactor200:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor200", "Alt+7"};
break;
case SettingsID::KeyBinding_SpeedFactor225:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor225", "Alt+8"};
break;
case SettingsID::KeyBinding_SpeedFactor250:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor250", "Alt+9"};
break;
case SettingsID::KeyBinding_SpeedFactor275:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor275", "Alt+["};
break;
case SettingsID::KeyBinding_SpeedFactor300:
setting = {SETTING_SECTION_KEYBIND, "SpeedFactor300", "Alt+]"};
break;
case SettingsID::KeyBinding_SaveState:
setting = {SETTING_SECTION_KEYBIND, "SaveState", "F5"};
break;
@@ -468,6 +521,21 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::KeyBinding_Fullscreen:
setting = {SETTING_SECTION_KEYBIND, "Fullscreen", "Alt+Return"};
break;
case SettingsID::Keybinding_ViewLog:
setting = {SETTING_SECTION_KEYBIND, "ViewLog", "Ctrl+L"};
break;
case SettingsID::KeyBinding_GraphicsSettings:
setting = {SETTING_SECTION_KEYBIND, "GraphicsSettings", "Ctrl+G"};
break;
case SettingsID::KeyBinding_AudioSettings:
setting = {SETTING_SECTION_KEYBIND, "AudioSettings", "Ctrl+A"};
break;
case SettingsID::KeyBinding_RspSettings:
setting = {SETTING_SECTION_KEYBIND, "RspSettings", "Ctrl+R"};
break;
case SettingsID::KeyBinding_InputSettings:
setting = {SETTING_SECTION_KEYBIND, "InputSettings", "Ctrl+I"};
break;
case SettingsID::KeyBinding_Settings:
setting = {SETTING_SECTION_KEYBIND, "Settings", "Ctrl+T"};
break;
@@ -487,11 +555,14 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::RomBrowser_MaxItems:
setting = {SETTING_SECTION_ROMBROWSER, "MaxItems", 250};
break;
case SettingsID::RomBrowser_Columns:
setting = {SETTING_SECTION_ROMBROWSER, "Columns", std::vector<int>({0, 1, 2})};
case SettingsID::RomBrowser_ColumnVisibility:
setting = {SETTING_SECTION_ROMBROWSER, "ColumnVisibility", std::vector<int>({1, 1, 1, 0, 0, 0, 0, 0, 0})};
break;
case SettingsID::RomBrowser_ColumnOrder:
setting = {SETTING_SECTION_ROMBROWSER, "ColumnOrder", std::vector<int>({0, 1, 2, 3, 4, 5, 6, 7, 8})};
break;
case SettingsID::RomBrowser_ColumnSizes:
setting = {SETTING_SECTION_ROMBROWSER, "ColumnSizes", std::vector<int>({-1, -1, -1})};
setting = {SETTING_SECTION_ROMBROWSER, "ColumnSizes", std::vector<int>({-1, -1, -1, -1, -1, -1, -1, -1, -1})};
break;
case SettingsID::RomBrowser_SortAfterSearch:
setting = {SETTING_SECTION_ROMBROWSER, "SortAfterSearch", true};
@@ -547,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;
@@ -571,6 +663,9 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::Input_Deadzone:
setting = {"", "Deadzone"};
break;
case SettingsID::Input_Sensitivity:
setting = {"", "Sensitivity"};
break;
case SettingsID::Input_Pak:
setting = {"", "Pak"};
break;
@@ -805,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;
@@ -1013,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);
@@ -1057,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);
@@ -1197,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());
}
+183 -1
View File
@@ -20,9 +20,12 @@ enum class SettingsID
GUI_OnScreenDisplayOpacity,
GUI_OnScreenDisplayDuration,
GUI_Toolbar,
GUI_ToolbarArea,
GUI_StatusBar,
GUI_Theme,
GUI_IconTheme,
GUI_CheckForUpdates,
GUI_LastUpdateCheck,
GUI_DiscordRpc,
GUI_Version,
@@ -62,6 +65,7 @@ enum class SettingsID
Core_CountPerOp,
Core_CountPerOpDenomPot,
Core_SiDmaDuration,
Core_SaveFileNameFormat,
// (mupen64plus) Overlay Core Settings
CoreOverlay_RandomizeInterrupt,
@@ -71,6 +75,7 @@ enum class SettingsID
CoreOverlay_CountPerOp,
CoreOverlay_CountPerOpDenomPot,
CoreOverlay_SiDmaDuration,
CoreOverLay_SaveFileNameFormat,
// (mupen64plus) Core Directory Settings
Core_ScreenshotPath,
@@ -108,6 +113,18 @@ enum class SettingsID
KeyBinding_Resume,
KeyBinding_Screenshot,
KeyBinding_LimitFPS,
KeyBinding_SpeedFactor25,
KeyBinding_SpeedFactor50,
KeyBinding_SpeedFactor75,
KeyBinding_SpeedFactor100,
KeyBinding_SpeedFactor125,
KeyBinding_SpeedFactor150,
KeyBinding_SpeedFactor175,
KeyBinding_SpeedFactor200,
KeyBinding_SpeedFactor225,
KeyBinding_SpeedFactor250,
KeyBinding_SpeedFactor275,
KeyBinding_SpeedFactor300,
KeyBinding_SaveState,
KeyBinding_SaveAs,
KeyBinding_LoadState,
@@ -125,6 +142,11 @@ enum class SettingsID
KeyBinding_SaveStateSlot8,
KeyBinding_SaveStateSlot9,
KeyBinding_Fullscreen,
Keybinding_ViewLog,
KeyBinding_GraphicsSettings,
KeyBinding_AudioSettings,
KeyBinding_RspSettings,
KeyBinding_InputSettings,
KeyBinding_Settings,
// RomBrowser Settings
@@ -133,7 +155,8 @@ enum class SettingsID
RomBrowser_Maximized,
RomBrowser_Recursive,
RomBrowser_MaxItems,
RomBrowser_Columns,
RomBrowser_ColumnVisibility,
RomBrowser_ColumnOrder,
RomBrowser_ColumnSizes,
RomBrowser_SortAfterSearch,
RomBrowser_ViewMode,
@@ -157,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,
@@ -166,6 +195,7 @@ enum class SettingsID
Input_DeviceName,
Input_DeviceNum,
Input_Deadzone,
Input_Sensitivity,
Input_Pak,
Input_GameboyRom,
Input_GameboySave,
@@ -244,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
};
+63
View File
@@ -0,0 +1,63 @@
/*
* 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 "SpeedFactor.hpp"
#include "Error.hpp"
#include "m64p/Api.hpp"
#include <string>
//
// Exported Functions
//
int CoreGetSpeedFactor(void)
{
std::string error;
m64p_error ret;
int value = 0;
if (!m64p::Core.IsHooked())
{
return 100;
}
ret = m64p::Core.DoCommand(M64CMD_CORE_STATE_QUERY, M64CORE_SPEED_FACTOR, &value);
if (ret != M64ERR_SUCCESS)
{
error = "CoreGetSpeedFactor: m64p::Core.DoCommand(M64CMD_CORE_STATE_QUERY) Failed: ";
error += m64p::Core.ErrorMessage(ret);
CoreSetError(error);
}
return value;
}
bool CoreSetSpeedFactor(int factor)
{
std::string error;
m64p_error ret;
int value = factor;
if (!m64p::Core.IsHooked())
{
return false;
}
ret = m64p::Core.DoCommand(M64CMD_CORE_STATE_SET, M64CORE_SPEED_FACTOR, &value);
if (ret != M64ERR_SUCCESS)
{
error = "CoreSetSpeedFactor: m64p::Core.DoCommand(M64CMD_CORE_STATE_SET) Failed: ";
error += m64p::Core.ErrorMessage(ret);
CoreSetError(error);
}
return ret == M64ERR_SUCCESS;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* 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 CORE_SPEEDFACTOR_HPP
#define CORE_SPEEDFACTOR_HPP
// returns the current speed factor
int CoreGetSpeedFactor(void);
// sets the speed factor
bool CoreSetSpeedFactor(int factor);
#endif // CORE_SPEEDFACTOR_HPP
+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];
+4
View File
@@ -28,6 +28,8 @@ bool PluginApi::Hook(m64p_dynlib_handle handle)
HOOK_FUNC(handle, Plugin, Startup);
HOOK_FUNC(handle, Plugin, Shutdown);
HOOK_FUNC_OPT(handle, Plugin, Config);
HOOK_FUNC_OPT(handle, Plugin, Config2);
HOOK_FUNC_OPT(handle, Plugin, Config2HasRomConfig);
HOOK_FUNC(handle, Plugin, GetVersion);
this->handle = handle;
@@ -40,6 +42,8 @@ bool PluginApi::Unhook(void)
UNHOOK_FUNC(Plugin, Startup);
UNHOOK_FUNC(Plugin, Shutdown);
UNHOOK_FUNC(Plugin, Config);
UNHOOK_FUNC(Plugin, Config2);
UNHOOK_FUNC(Plugin, Config2HasRomConfig);
UNHOOK_FUNC(Plugin, GetVersion);
this->handle = nullptr;
+2
View File
@@ -34,6 +34,8 @@ class PluginApi
ptr_PluginStartup Startup;
ptr_PluginShutdown Shutdown;
ptr_PluginConfig Config;
ptr_PluginConfig2 Config2;
ptr_PluginConfig2HasRomConfig Config2HasRomConfig;
ptr_PluginGetVersion GetVersion;
private:
+23
View File
@@ -21,6 +21,29 @@ typedef m64p_error (*ptr_PluginConfig)(void);
EXPORT m64p_error CALL PluginConfig(void);
#endif
/* PluginConfig2(int romConfig)
*
* This optional function opens a configuration GUI for the plugin
* https://github.com/mupen64plus/mupen64plus-core/pull/774
*
* romConfig argument determines if it should open the ROM specific config
*/
typedef m64p_error (*ptr_PluginConfig2)(int);
#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES)
EXPORT m64p_error CALL PluginConfig2(int);
#endif
/* PluginConfig2HasRomConfig(void)
*
* This optional function returns wether the plugin supports ROM specific config
* using PluginConfig2
*
*/
typedef int (*ptr_PluginConfig2HasRomConfig)(void);
#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES)
EXPORT int CALL PluginConfig2HasRomConfig(void);
#endif
#ifdef __cplusplus
}
#endif
+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
+14 -4
View File
@@ -18,7 +18,7 @@
using namespace UserInterface;
MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread) : QDialog(parent)
MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread, bool romConfig) : QDialog(parent)
{
this->setupUi(this);
this->setWindowIcon(QIcon(":Resource/RMG.png"));
@@ -41,6 +41,7 @@ MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread) : QDialog(
for (int i = 0; i < this->tabWidget->count(); i++)
{
Widget::ControllerWidget* widget = new Widget::ControllerWidget(this, this->eventFilter);
widget->SetOnlyLoadGameProfile(romConfig);
widget->SetSettingsSection("Player " + QString::number(i + 1), "Rosalie's Mupen GUI - Input Plugin Profile " + QString::number(i));
widget->LoadSettings();
this->tabWidget->widget(i)->layout()->addWidget(widget);
@@ -58,9 +59,18 @@ MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread) : QDialog(
// 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);
}
@@ -59,7 +59,7 @@ private:
void closeInputDevice();
public:
MainDialog(QWidget *parent, Thread::SDLThread*);
MainDialog(QWidget *parent, Thread::SDLThread*, bool);
~MainDialog(void);
public slots:
@@ -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>
@@ -10,8 +10,8 @@
#include "ControllerImageWidget.hpp"
#include <QSvgRenderer>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <QPainter>
#include <QResizeEvent>
@@ -62,6 +62,15 @@ void ControllerImageWidget::SetDeadzone(int value)
}
}
void ControllerImageWidget::SetSensitivity(int value)
{
if (this->sensitivityValue != value)
{
this->sensitivityValue = value;
this->needImageUpdate = true;
}
}
void ControllerImageWidget::ClearControllerState()
{
// reset button state
@@ -153,27 +162,35 @@ void ControllerImageWidget::paintEvent(QPaintEvent *event)
renderer.setAspectRatioMode(Qt::AspectRatioMode::KeepAspectRatio);
QRectF rectF = renderer.viewBoxF();
double offsetx = 0, offsety = 0;
const int width = rectF.width();
const int height = rectF.height();
// we'll move the analog stick by a percentage
// of the total width/height from the image
const double maxOffsety = ((double)(height * 0.12265f) / 2);
const double maxOffsetx = maxOffsety;
const double dist = sqrt(pow(this->xAxisState, 2) + pow(this->yAxisState, 2));
const double absoluteMaxOffset = ((double)(height * 0.12265f) / 2);
// slope as in line gradient
const double offsetSlope = absoluteMaxOffset / 100;
// take sensitivity into account
const double sensitivityFactor = this->sensitivityValue / 100.0;
const double sensitivityAdjustedMaxOffset = absoluteMaxOffset * std::min(sensitivityFactor, 1.0);
double offsetDeadzone = this->deadzoneValue * sensitivityFactor * offsetSlope;
int offsetx = this->xAxisState * sensitivityFactor * offsetSlope;
int offsety = this->yAxisState * sensitivityFactor * offsetSlope;
const double offsetDist = std::hypot(offsetx, offsety);
// take deadzone into account
if (dist > this->deadzoneValue)
// deadzone grows with sensitivity such that the deadzone
// is always a percentage of the real stick range
if (offsetDist <= offsetDeadzone)
{
offsetx = (maxOffsetx / 100 * this->xAxisState);
offsety = (maxOffsety / 100 * this->yAxisState);
offsetx = 0;
offsety = 0;
}
// take circle range into account
if (dist > 100)
if (offsetDist > sensitivityAdjustedMaxOffset)
{
offsetx = (maxOffsetx / 100 * (this->xAxisState / dist * 100));
offsety = (maxOffsety / 100 * (this->yAxisState / dist * 100));
offsetx = (offsetx / offsetDist) * sensitivityAdjustedMaxOffset;
offsety = (offsety / offsetDist) * sensitivityAdjustedMaxOffset;
}
// adjust rect with offset
@@ -31,6 +31,8 @@ private:
int yAxisState = 0;
// deadzone value, 0-100
int deadzoneValue = 0;
// sensitivity value, 25-175
int sensitivityValue = 100;
bool needImageUpdate = false;
public:
@@ -41,6 +43,7 @@ public:
void SetXAxisState(int xAxis);
void SetYAxisState(int yAxis);
void SetDeadzone(int value);
void SetSensitivity(int value);
void ClearControllerState();
void UpdateImage();
@@ -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)))
@@ -323,6 +362,7 @@ void ControllerWidget::setPluggedIn(bool value)
this->analogStickDownButton, this->analogStickDownAddButton, this->analogStickDownRemoveButton,
this->analogStickLeftButton, this->analogStickLeftAddButton, this->analogStickLeftRemoveButton,
this->analogStickRightButton, this->analogStickRightAddButton, this->analogStickRightRemoveButton,
this->analogStickSensitivitySlider,
// cbuttons
this->cButtonsGroupBox,
this->cbuttonUpButton, this->cbuttonUpAddButton, this->cbuttonUpRemoveButton,
@@ -343,7 +383,8 @@ void ControllerWidget::setPluggedIn(bool value)
this->deadZoneGroupBox,
this->deadZoneSlider,
this->optionsButton,
this->resetButton
this->resetButton,
this->hotkeysButton,
};
for (auto& widget : widgetList)
@@ -354,6 +395,67 @@ void ControllerWidget::setPluggedIn(bool value)
this->ClearControllerImage();
}
bool ControllerWidget::hasAnyGameSettingChanged(void)
{
std::string section = this->getCurrentSettingsSection().toStdString();
// fallback to main section
if (!CoreSettingsSectionExists(section))
{
section = this->settingsSection.toStdString();
}
// retrieve data from settings
bool settingsIsPluggedIn = CoreSettingsGetBoolValue(SettingsID::Input_PluggedIn, section);
int settingsDeadZone = CoreSettingsGetIntValue(SettingsID::Input_Deadzone, section);
int settingsAnalogSensitivity = 100;
// account for profiles before v0.3.9
if (CoreSettingsKeyExists(section, "Sensitivity"))
{
settingsAnalogSensitivity = CoreSettingsGetIntValue(SettingsID::Input_Sensitivity, section);
}
// retrieve current data
bool currentIsPluggedIn = this->inputDeviceComboBox->currentText() != "None";
int currentDeadZone = this->deadZoneSlider->value();
int currentAnalogSensitivity = this->analogStickSensitivitySlider->value();
// compare data
if (settingsIsPluggedIn != currentIsPluggedIn ||
settingsDeadZone != currentDeadZone ||
settingsAnalogSensitivity != currentAnalogSensitivity)
{
return true;
}
// compare button mappings with settings
for (auto& buttonSetting : this->buttonSettingMappings)
{
// retrieve data from settings
std::vector<int> settingsTypes = CoreSettingsGetIntListValue(buttonSetting.inputTypeSettingsId, section);
std::vector<std::string> settingsNames = CoreSettingsGetStringListValue(buttonSetting.nameSettingsId, section);
std::vector<int> settingsData = CoreSettingsGetIntListValue(buttonSetting.dataSettingsId, section);
std::vector<int> settingsExtraData = CoreSettingsGetIntListValue(buttonSetting.extraDataSettingsId, section);
// retrieve current data
std::vector<int> currentTypes = buttonSetting.button->GetInputType();
std::vector<std::string> currentNames = buttonSetting.button->GetInputText();
std::vector<int> currentData = buttonSetting.button->GetInputData();
std::vector<int> currentExtraData = buttonSetting.button->GetExtraInputData();
// compare data
if (settingsTypes != currentTypes ||
settingsNames != currentNames ||
settingsData != currentData ||
settingsExtraData != currentExtraData)
{
return true;
}
}
// no differences found
return false;
}
void ControllerWidget::showErrorMessage(QString text, QString details)
{
QMessageBox msgBox(this);
@@ -509,6 +611,16 @@ void ControllerWidget::on_deadZoneSlider_valueChanged(int value)
this->controllerImageWidget->SetDeadzone(value);
}
void ControllerWidget::on_analogStickSensitivitySlider_valueChanged(int value)
{
QString title = tr("Analog Stick Sensitivity: ");
title += QString::number(value);
title += "%";
this->analogStickSensitivityGroupBox->setTitle(title);
this->controllerImageWidget->SetSensitivity(value);
}
void ControllerWidget::on_profileComboBox_currentIndexChanged(int value)
{
// save profile when switching profile
@@ -551,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);
}
@@ -622,7 +735,7 @@ void ControllerWidget::on_removeProfileButton_clicked()
{
bool ret;
if (this->profileComboBox->currentIndex() == 0)
if (this->profileComboBox->currentData().toString() == this->settingsSection)
{
QMessageBox messageBox(this);
messageBox.setIcon(QMessageBox::Icon::Warning);
@@ -678,6 +791,13 @@ void ControllerWidget::on_removeProfileButton_clicked()
this->previousProfileComboBoxIndex = -1;
this->profileComboBox->setCurrentIndex(0);
}
// force a re-load when
// we're only loading the game profile
if (this->onlyLoadGameProfile)
{
this->LoadSettings(this->settingsSection);
}
}
void ControllerWidget::on_resetButton_clicked()
@@ -696,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)
@@ -716,7 +860,7 @@ void ControllerWidget::on_MappingButton_Released(MappingButton* button)
this->currentButton = button;
button->SaveState();
button->StartTimer();
this->disableAllChildren();
}
@@ -754,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:
@@ -1093,10 +1244,21 @@ bool ControllerWidget::IsPluggedIn()
return this->inputDeviceComboBox->currentData().toInt() != (int)InputDeviceType::None;
}
void ControllerWidget::SetOnlyLoadGameProfile(bool value)
{
this->onlyLoadGameProfile = value;
// update UI element
this->addProfileButton->setDisabled(value);
}
void ControllerWidget::SetSettingsSection(QString profile, QString section)
{
this->settingsSection = section;
this->profileComboBox->addItem(profile, section);
if (!this->onlyLoadGameProfile)
{
this->profileComboBox->addItem(profile, section);
}
}
void ControllerWidget::SetInitialized(bool value)
@@ -1145,41 +1307,53 @@ void ControllerWidget::LoadSettings()
// if a game specific section exists,
// select it in the profile combobox
// and use it to load the settings
if (CoreSettingsSectionExists(this->gameSection.toStdString()))
if (CoreSettingsSectionExists(this->gameSection.toStdString()) ||
this->onlyLoadGameProfile)
{
// check if the key 'UseGameProfile' exists,
// if it doesn't then use the profile,
// else check if it's true and use it
if (!CoreSettingsKeyExists(this->gameSection.toStdString(), "UseGameProfile") ||
// else check if it's true and use it,
// or if we're only loading the game profile
if (this->onlyLoadGameProfile ||
!CoreSettingsKeyExists(this->gameSection.toStdString(), "UseGameProfile") ||
CoreSettingsGetBoolValue(SettingsID::Input_UseGameProfile, this->gameSection.toStdString()))
{
this->profileComboBox->setCurrentText(internalName);
section = this->gameSection;
// only use game section if it exists
if (CoreSettingsSectionExists(this->gameSection.toStdString()))
{
section = this->gameSection;
}
}
}
}
// clear profiles list
profiles.clear();
// try to add all the user's profiles
userProfiles = CoreSettingsGetStringListValue(SettingsID::Input_Profiles);
for (const std::string& profile : userProfiles)
// try to add all the user's profiles when we're not only loading the
// game profile
if (!this->onlyLoadGameProfile)
{
QString profileSection = this->getUserProfileSectionName(QString::fromStdString(profile));
// clear profiles list
profiles.clear();
// ensure the profile section exists,
// if it does, add it when it doesn't
// exist yet
if (CoreSettingsSectionExists(profileSection.toStdString()))
userProfiles = CoreSettingsGetStringListValue(SettingsID::Input_Profiles);
for (const std::string& profile : userProfiles)
{
// add to profiles list
this->profiles.push_back(profileSection);
QString profileSection = this->getUserProfileSectionName(QString::fromStdString(profile));
int index = this->profileComboBox->findData(profileSection);
if (index == -1)
// ensure the profile section exists,
// if it does, add it when it doesn't
// exist yet
if (CoreSettingsSectionExists(profileSection.toStdString()))
{
this->profileComboBox->addItem(QString::fromStdString(profile), profileSection);
// add to profiles list
this->profiles.push_back(profileSection);
int index = this->profileComboBox->findData(profileSection);
if (index == -1)
{
this->profileComboBox->addItem(QString::fromStdString(profile), profileSection);
}
}
}
}
@@ -1219,7 +1393,7 @@ void ControllerWidget::LoadSettings(QString sectionQString, bool loadUserProfile
// if it does, see if that profile exists, then load
// that instead
useProfile = CoreSettingsGetStringValue(SettingsID::Input_UseProfile, section);
if (loadUserProfile && !useProfile.empty())
if (!this->onlyLoadGameProfile && loadUserProfile && !useProfile.empty())
{
QString profileSection = this->getUserProfileSectionName(QString::fromStdString(useProfile));
@@ -1232,6 +1406,16 @@ void ControllerWidget::LoadSettings(QString sectionQString, bool loadUserProfile
}
}
// keep backwards compatibility with versions before v0.3.9
if (CoreSettingsKeyExists(section, "Sensitivity"))
{
this->analogStickSensitivitySlider->setValue(CoreSettingsGetIntValue(SettingsID::Input_Sensitivity, section));
}
else
{
this->analogStickSensitivitySlider->setValue(100);
}
this->deadZoneSlider->setValue(CoreSettingsGetIntValue(SettingsID::Input_Deadzone, section));
this->optionsDialogSettings.RemoveDuplicateMappings = CoreSettingsGetBoolValue(SettingsID::Input_RemoveDuplicateMappings, section);
this->optionsDialogSettings.ControllerPak = CoreSettingsGetIntValue(SettingsID::Input_Pak, section);
@@ -1278,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());
@@ -1309,6 +1501,7 @@ void ControllerWidget::SaveDefaultSettings()
CoreSettingsSetValue(SettingsID::Input_DeviceName, section, std::string("None"));
CoreSettingsSetValue(SettingsID::Input_DeviceNum, section, (int)InputDeviceType::None);
CoreSettingsSetValue(SettingsID::Input_Deadzone, section, 9);
CoreSettingsSetValue(SettingsID::Input_Sensitivity, section, 100);
CoreSettingsSetValue(SettingsID::Input_Pak, section, 0);
CoreSettingsSetValue(SettingsID::Input_RemoveDuplicateMappings, section, true);
CoreSettingsSetValue(SettingsID::Input_FilterEventsForButtons, section, true);
@@ -1330,6 +1523,14 @@ void ControllerWidget::SaveSettings()
return;
}
// when we're only loading the game profile,
// we should only save when anything has changed
if (this->onlyLoadGameProfile &&
!this->hasAnyGameSettingChanged())
{
return;
}
this->SaveSettings(this->getCurrentSettingsSection());
// delete all removed profile sections
@@ -1393,6 +1594,7 @@ void ControllerWidget::SaveSettings(QString section)
CoreSettingsSetValue(SettingsID::Input_DeviceName, sectionStr, deviceName.toStdString());
CoreSettingsSetValue(SettingsID::Input_DeviceNum, sectionStr, deviceNum);
CoreSettingsSetValue(SettingsID::Input_Deadzone, sectionStr, this->deadZoneSlider->value());
CoreSettingsSetValue(SettingsID::Input_Sensitivity, sectionStr, this->analogStickSensitivitySlider->value());
CoreSettingsSetValue(SettingsID::Input_Pak, sectionStr, this->optionsDialogSettings.ControllerPak);
CoreSettingsSetValue(SettingsID::Input_GameboyRom, sectionStr, this->optionsDialogSettings.GameboyRom);
CoreSettingsSetValue(SettingsID::Input_GameboySave, sectionStr, this->optionsDialogSettings.GameboySave);
@@ -1407,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()
@@ -1425,6 +1635,14 @@ void ControllerWidget::RevertSettings()
CoreSettingsRevertSection(section.toStdString());
}
// don't compare profiles,
// when we're only loading
// the game profile
if (this->onlyLoadGameProfile)
{
return;
}
// delete all sections for added & removed profiles,
// which aren't in the base profile section list
sections.clear();
@@ -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();
@@ -95,6 +97,8 @@ private:
void setPluggedIn(bool value);
bool hasAnyGameSettingChanged(void);
void showErrorMessage(QString text, QString details = "");
SDL_JoystickID currentJoystickId = -1;
@@ -102,6 +106,10 @@ private:
int previousProfileComboBoxIndex = -1;
bool onlyLoadGameProfile = false;
HotkeysDialog* currentHotkeysDialog = nullptr;
public:
ControllerWidget(QWidget* parent, EventFilter* eventFilter);
~ControllerWidget();
@@ -116,6 +124,8 @@ public:
void GetCurrentInputDevice(QString& deviceName, int& deviceNum, bool ignoreDeviceNotFound = false);
bool IsPluggedIn();
void SetOnlyLoadGameProfile(bool value);
void SetSettingsSection(QString profile, QString section);
void SetInitialized(bool value);
@@ -138,6 +148,7 @@ public:
private slots:
void on_deadZoneSlider_valueChanged(int value);
void on_analogStickSensitivitySlider_valueChanged(int value);
void on_profileComboBox_currentIndexChanged(int value);
@@ -149,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">
@@ -601,6 +601,43 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="analogStickSensitivityGroupBox">
<property name="title">
<string>Analog Stick Sensitivity: 100%</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_15">
<item>
<widget class="QSlider" name="analogStickSensitivitySlider">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>25</number>
</property>
<property name="maximum">
<number>175</number>
</property>
<property name="value">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>15</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
@@ -1217,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
+374 -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 <iostream>
#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
@@ -60,6 +65,7 @@ struct InputProfile
{
bool PluggedIn = false;
int DeadzoneValue = 0;
int SensitivityValue = 100;
N64ControllerPak ControllerPak = N64ControllerPak::None;
@@ -96,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;
};
//
@@ -105,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];
@@ -223,6 +290,16 @@ static void load_settings(void)
profile->GameboyRom = CoreSettingsGetStringValue(SettingsID::Input_GameboyRom, section);
profile->GameboySave = CoreSettingsGetStringValue(SettingsID::Input_GameboySave, section);
// keep compatibility with profiles before version v0.3.9
if (CoreSettingsKeyExists(section, "Sensitivity"))
{
profile->SensitivityValue = CoreSettingsGetIntValue(SettingsID::Input_Sensitivity, section);
}
else
{
profile->SensitivityValue = 100;
}
// load inputmapping settings
load_inputmapping_settings(&profile->Button_A, section, SettingsID::Input_A_Name, SettingsID::Input_A_InputType, SettingsID::Input_A_Data, SettingsID::Input_A_ExtraData);
load_inputmapping_settings(&profile->Button_B, section, SettingsID::Input_B_Name, SettingsID::Input_B_InputType, SettingsID::Input_B_Data, SettingsID::Input_B_ExtraData);
@@ -242,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);
}
}
@@ -258,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)
{
@@ -267,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:
@@ -275,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();
}
}
@@ -406,12 +561,12 @@ static void close_controllers(void)
for (int i = 0; i < NUM_CONTROLLERS; i++)
{
InputProfile* profile = &l_InputProfiles[i];
profile->InputDevice.CloseDevice();
}
}
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;
@@ -424,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;
@@ -520,51 +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
static void simulate_octagon(const double inputX, const double inputY, const double deadzoneFactor, 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;
const double maxDiagonal = MAX_DIAGONAL_VALUE;
const int deadzone = (int)(deadzoneFactor * N64_AXIS_PEAK);
const double axisRange = maxAxis - deadzone;
// scale to [-maxAxis, 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;
@@ -572,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;
}
@@ -605,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))
{
@@ -624,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})
{
@@ -651,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);
@@ -661,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;
@@ -679,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;
@@ -719,7 +996,7 @@ EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *pluginType, int *plugi
// Custom Plugin Functions
//
EXPORT m64p_error CALL PluginConfig()
EXPORT m64p_error CALL PluginConfig2(int romConfig)
{
if (l_SDLThread == nullptr)
{
@@ -731,7 +1008,7 @@ EXPORT m64p_error CALL PluginConfig()
l_SDLThread->SetAction(SDLThreadAction::SDLPumpEvents);
UserInterface::MainDialog dialog(nullptr, l_SDLThread);
UserInterface::MainDialog dialog(nullptr, l_SDLThread, romConfig);
dialog.exec();
l_SDLThread->SetAction(SDLThreadAction::None);
@@ -742,7 +1019,6 @@ EXPORT m64p_error CALL PluginConfig()
QThread::msleep(5);
}
// reload settings
load_settings();
@@ -758,6 +1034,11 @@ EXPORT m64p_error CALL PluginConfig()
return M64ERR_SUCCESS;
}
EXPORT int CALL PluginConfig2HasRomConfig(void)
{
return 1;
}
//
// Input Plugin Functions
//
@@ -779,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);
@@ -796,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)
@@ -829,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
@@ -852,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);
@@ -874,11 +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
octagonX, // outputX
octagonY // outputY
);
@@ -913,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)
+13
View File
@@ -16,10 +16,18 @@ if (UPDATER)
add_definitions(-DUPDATER)
endif(UPDATER)
if (APPIMAGE_UPDATER)
add_definitions(-DAPPIMAGE_UPDATER)
endif(APPIMAGE_UPDATER)
if (DISCORD_RPC)
add_definitions(-DDISCORD_RPC)
endif(DISCORD_RPC)
if (FORCE_XCB)
add_definitions(-DFORCE_XCB)
endif(FORCE_XCB)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
@@ -89,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}
+22 -1
View File
@@ -36,11 +36,12 @@ bool CoreCallbacks::Init(void)
{
// needed for Qt
qRegisterMetaType<CoreDebugMessageType>("CoreDebugMessageType");
qRegisterMetaType<CoreDebugMessageType>("CoreStateCallbackType");
this->LoadSettings();
l_CoreCallbacks = this;
return CoreSetupCallbacks(this->coreDebugCallback);
return CoreSetupCallbacks(this->coreDebugCallback, this->coreStateCallback);
}
void CoreCallbacks::Stop(void)
@@ -66,5 +67,25 @@ void CoreCallbacks::coreDebugCallback(CoreDebugMessageType type, std::string con
return;
}
// skip non-fatal interpreter errors
if (type == CoreDebugMessageType::Error)
{
if (message == "DIV_S by 0" ||
message == "DIV_D by 0")
{
return;
}
}
emit l_CoreCallbacks->OnCoreDebugCallback(type, QString::fromStdString(context), QString::fromStdString(message));
}
void CoreCallbacks::coreStateCallback(CoreStateCallbackType type, int value)
{
if (l_CoreCallbacks == nullptr)
{
return;
}
emit l_CoreCallbacks->OnCoreStateCallback(type, value);
}
+2
View File
@@ -31,9 +31,11 @@ public:
private:
static void coreDebugCallback(CoreDebugMessageType type, std::string context, std::string message);
static void coreStateCallback(CoreStateCallbackType type, int value);
signals:
void OnCoreDebugCallback(CoreDebugMessageType type, QString context, QString message);
void OnCoreStateCallback(CoreStateCallbackType type, int value);
};
#endif // RMG_CALLBACKS_HPP
+10 -7
View File
@@ -70,6 +70,7 @@ void RomSearcherThread::searchDirectory(QString directory)
filter << "*.NDD";
filter << "*.D64";
filter << "*.ZIP";
filter << "*.7Z";
QDirIterator::IteratorFlag flag = this->recursive ?
QDirIterator::Subdirectories :
@@ -82,9 +83,16 @@ void RomSearcherThread::searchDirectory(QString directory)
bool ret;
int count = 0;
QList<QString> roms;
while (romDirIt.hasNext())
{
QString file = romDirIt.next();
roms.push_back(romDirIt.next());
}
int romAmount = std::min(this->maxItems, (int)roms.size());
for (int i = 0; i < romAmount; i++)
{
QString file = roms.at(i);
QElapsedTimer timer;
timer.start();
@@ -111,12 +119,7 @@ void RomSearcherThread::searchDirectory(QString directory)
if (ret)
{
if (count++ >= this->maxItems)
{
break;
}
emit this->RomFound(file, type, header, settings);
emit this->RomFound(file, type, header, settings, (i + 1), romAmount);
}
if (this->stop)
+1 -1
View File
@@ -40,7 +40,7 @@ class RomSearcherThread : public QThread
void searchDirectory(QString);
signals:
void RomFound(QString file, CoreRomType type, CoreRomHeader header, CoreRomSettings settings);
void RomFound(QString file, CoreRomType type, CoreRomHeader header, CoreRomSettings settings, int index, int count);
void Finished(bool canceled);
};
} // namespace Thread
@@ -18,6 +18,7 @@
#include <QNetworkReply>
#include <QTemporaryDir>
#include <QFile>
#include <QProcess>
using namespace UserInterface::Dialog;
@@ -79,6 +80,9 @@ void DownloadUpdateDialog::on_reply_finished(void)
return;
}
QString filePath;
#ifndef APPIMAGE_UPDATER
QTemporaryDir temporaryDir;
temporaryDir.setAutoRemove(false);
if (!temporaryDir.isValid())
@@ -90,12 +94,52 @@ void DownloadUpdateDialog::on_reply_finished(void)
}
this->temporaryDirectory = temporaryDir.path();
filePath = temporaryDir.filePath(this->filename);
#else
const char* appImageEnv = std::getenv("APPIMAGE");
if (appImageEnv == nullptr ||
!QFile(appImageEnv).exists())
{
this->showErrorMessage("APPIMAGE variable is empty or invalid!", "");
this->reply->deleteLater();
this->reject();
return;
}
filePath = appImageEnv;
filePath += ".update";
#endif // APPIMAGE_UPDATER
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
this->showErrorMessage("QFile::open() Failed!", "");
this->reply->deleteLater();
this->reject();
return;
}
QFile file(temporaryDir.filePath(this->filename));
file.open(QIODevice::WriteOnly);
file.write(this->reply->readAll());
#ifdef APPIMAGE_UPDATER
file.setPermissions(QFile(appImageEnv).permissions());
#endif // APPIMAGE_UPDATER
file.close();
#ifdef APPIMAGE_UPDATER
int ret = std::rename(filePath.toStdString().c_str(), appImageEnv);
if (ret != 0)
{
this->showErrorMessage("std::rename() Failed!", QString(strerror(errno)));
this->reply->deleteLater();
this->reject();
return;
}
QProcess process;
process.setProgram(appImageEnv);
process.startDetached();
#endif // APPIMAGE_UPDATER
this->reply->deleteLater();
this->accept();
}
@@ -41,7 +41,6 @@ void InstallUpdateDialog::install(void)
QString appPid = QString::number(QCoreApplication::applicationPid());
QString logPath = appPath + "/Cache/updater.log";
#ifdef _WIN32
// convert paths to use the right path seperator
this->temporaryDirectory = QDir::toNativeSeparators(this->temporaryDirectory);
fullFilePath = QDir::toNativeSeparators(fullFilePath);
@@ -67,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\"",
@@ -79,7 +78,6 @@ void InstallUpdateDialog::install(void)
this->accept();
return;
}
#endif // _WIN32
this->label->setText("Extracting " + this->filename + "...");
this->progressBar->setValue(50);
@@ -106,7 +104,6 @@ void InstallUpdateDialog::install(void)
this->label->setText("Executing update script...");
this->progressBar->setValue(100);
#ifdef _WIN32
extractDirectory = QDir::toNativeSeparators(extractDirectory);
QStringList scriptLines =
@@ -129,31 +126,13 @@ void InstallUpdateDialog::install(void)
"rmdir /S /Q \"" + this->temporaryDirectory + "\"",
};
this->writeAndRunScript(scriptLines);
#else // Linux
QStringList scriptLines =
{
"#!/usr/bin/env bash",
"set -e",
"rm -rf \"" + fullFilePath + "\"",
"kill -1 " + appPid,
"cp -R \"" + extractDirectory + "/\"* \"" + appPath + "/\"",
"chmod +x \"" + appPath + "/RMG\"",
"\"" + appPath + "/RMG\"&",
"rm -rf \"" + this->temporaryDirectory + "\"" ,
};
this->writeAndRunScript(scriptLines);
#endif // _WIN32
}
void InstallUpdateDialog::writeAndRunScript(QStringList stringList)
{
QString scriptPath;
scriptPath = this->temporaryDirectory;
#ifdef _WIN32
scriptPath += "/update.bat";
#else
scriptPath += "/update.sh";
#endif // _WIN32
QFile scriptFile(scriptPath);
if (!scriptFile.open(QIODevice::WriteOnly | QIODevice::Text))
@@ -30,7 +30,8 @@ RomInfoDialog::RomInfoDialog(QString file, CoreRomHeader romHeader, CoreRomSetti
this->locationLineEdit->setCursorPosition(0);
this->crc1LineEdit->setText(QString::number(romHeader.CRC1, 16).toUpper());
this->crc2LineEdit->setText(QString::number(romHeader.CRC2, 16).toUpper());
this->countryCodeLineEdit->setText(QString((char)romHeader.CountryCode));
this->gameIDLineEdit->setText(QString::fromStdString(romHeader.GameID));
this->gameRegionLineEdit->setText(QString::fromStdString(romHeader.Region));
}
RomInfoDialog::~RomInfoDialog(void)
@@ -199,12 +199,36 @@
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Country Code</string>
<string>Game I.D.</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="countryCodeLineEdit">
<widget class="QLineEdit" name="gameIDLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Game Region</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="gameRegionLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
@@ -214,6 +214,7 @@ void SettingsDialog::loadCoreSettings(void)
bool disableExtraMem = false;
int counterFactor = 0;
int cpuEmulator = 0;
int saveFilenameFormat = 0;
int siDmaDuration = -1;
bool randomizeInterrupt = true;
bool debugger = false;
@@ -222,12 +223,14 @@ void SettingsDialog::loadCoreSettings(void)
disableExtraMem = CoreSettingsGetBoolValue(SettingsID::CoreOverlay_DisableExtraMem);
counterFactor = CoreSettingsGetIntValue(SettingsID::CoreOverlay_CountPerOp);
cpuEmulator = CoreSettingsGetIntValue(SettingsID::CoreOverlay_CPU_Emulator);
saveFilenameFormat = CoreSettingsGetIntValue(SettingsID::CoreOverLay_SaveFileNameFormat);
siDmaDuration = CoreSettingsGetIntValue(SettingsID::CoreOverlay_SiDmaDuration);
randomizeInterrupt = CoreSettingsGetBoolValue(SettingsID::CoreOverlay_RandomizeInterrupt);
debugger = CoreSettingsGetBoolValue(SettingsID::CoreOverlay_EnableDebugger);
overrideGameSettings = CoreSettingsGetBoolValue(SettingsID::Core_OverrideGameSpecificSettings);
this->coreCpuEmulatorComboBox->setCurrentIndex(cpuEmulator);
this->coreSaveFilenameFormatComboBox->setCurrentIndex(saveFilenameFormat);
this->coreRandomizeTimingCheckBox->setChecked(randomizeInterrupt);
//this->coreDebuggerCheckBox->setChecked(debugger);
@@ -406,7 +409,24 @@ void SettingsDialog::loadInterfaceOSDSettings(void)
void SettingsDialog::loadInterfaceMiscSettings(void)
{
// find stylesheets and add them to the UI
QString directory;
directory = QString::fromStdString(CoreGetSharedDataDirectory().string());
directory += "/Styles/";
QStringList filter;
filter << "*.qss";
QDirIterator stylesDirectoryIter(directory, filter, QDir::Files, QDirIterator::NoIteratorFlags);
while (stylesDirectoryIter.hasNext())
{
QFileInfo fileInfo(stylesDirectoryIter.next());
this->themeComboBox->addItem(fileInfo.fileName());
}
// select currently chosen theme in UI
this->themeComboBox->setCurrentText(QString::fromStdString(CoreSettingsGetStringValue(SettingsID::GUI_Theme)));
this->iconThemeComboBox->setCurrentText(QString::fromStdString(CoreSettingsGetStringValue(SettingsID::GUI_IconTheme)));
#ifdef UPDATER
this->checkForUpdatesCheckBox->setChecked(CoreSettingsGetBoolValue(SettingsID::GUI_CheckForUpdates));
#endif // UPDATER
@@ -420,6 +440,7 @@ void SettingsDialog::loadDefaultCoreSettings(void)
bool disableExtraMem = false;
int counterFactor = 0;
int cpuEmulator = 0;
int saveFilenameFormat = 0;
int siDmaDuration = -1;
bool randomizeInterrupt = true;
bool debugger = false;
@@ -429,11 +450,13 @@ void SettingsDialog::loadDefaultCoreSettings(void)
counterFactor = CoreSettingsGetDefaultIntValue(SettingsID::CoreOverlay_CountPerOp);
cpuEmulator = CoreSettingsGetDefaultIntValue(SettingsID::CoreOverlay_CPU_Emulator);
siDmaDuration = CoreSettingsGetDefaultIntValue(SettingsID::CoreOverlay_SiDmaDuration);
saveFilenameFormat = CoreSettingsGetDefaultIntValue(SettingsID::CoreOverLay_SaveFileNameFormat);
randomizeInterrupt = CoreSettingsGetDefaultBoolValue(SettingsID::CoreOverlay_RandomizeInterrupt);
debugger = CoreSettingsGetDefaultBoolValue(SettingsID::CoreOverlay_EnableDebugger);
overrideGameSettings = CoreSettingsGetDefaultBoolValue(SettingsID::Core_OverrideGameSpecificSettings);
this->coreCpuEmulatorComboBox->setCurrentIndex(cpuEmulator);
this->coreSaveFilenameFormatComboBox->setCurrentIndex(saveFilenameFormat);
this->coreRandomizeTimingCheckBox->setChecked(randomizeInterrupt);
//this->coreDebuggerCheckBox->setChecked(debugger);
@@ -550,6 +573,7 @@ void SettingsDialog::loadDefaultInterfaceOSDSettings(void)
void SettingsDialog::loadDefaultInterfaceMiscSettings(void)
{
this->themeComboBox->setCurrentText(QString::fromStdString(CoreSettingsGetDefaultStringValue(SettingsID::GUI_Theme)));
this->iconThemeComboBox->setCurrentText(QString::fromStdString(CoreSettingsGetDefaultStringValue(SettingsID::GUI_IconTheme)));
#ifdef UPDATER
this->checkForUpdatesCheckBox->setChecked(CoreSettingsGetDefaultBoolValue(SettingsID::GUI_CheckForUpdates));
#endif // UPDATER
@@ -585,12 +609,14 @@ void SettingsDialog::saveCoreSettings(void)
bool disableExtraMem = (this->coreMemorySizeComboBox->currentIndex() == 0);
int counterFactor = this->coreCounterFactorComboBox->currentIndex() + 1;
int cpuEmulator = this->coreCpuEmulatorComboBox->currentIndex();
int saveFilenameFormat = this->coreSaveFilenameFormatComboBox->currentIndex();
int siDmaDuration = this->coreSiDmaDurationSpinBox->value();
bool randomizeInterrupt = this->coreRandomizeTimingCheckBox->isChecked();
//bool debugger = this->coreDebuggerCheckBox->isChecked();
bool overrideGameSettings = this->coreOverrideGameSettingsGroup->isChecked();
CoreSettingsSetValue(SettingsID::CoreOverlay_CPU_Emulator, cpuEmulator);
CoreSettingsSetValue(SettingsID::CoreOverLay_SaveFileNameFormat, saveFilenameFormat);
CoreSettingsSetValue(SettingsID::CoreOverlay_RandomizeInterrupt, randomizeInterrupt);
//CoreSettingsSetValue(SettingsID::CoreOverlay_EnableDebugger, debugger);
CoreSettingsSetValue(SettingsID::Core_OverrideGameSpecificSettings, overrideGameSettings);
@@ -754,6 +780,7 @@ void SettingsDialog::saveInterfaceOSDSettings(void)
void SettingsDialog::saveInterfaceMiscSettings(void)
{
CoreSettingsSetValue(SettingsID::GUI_Theme, this->themeComboBox->currentText().toStdString());
CoreSettingsSetValue(SettingsID::GUI_IconTheme, this->iconThemeComboBox->currentText().toStdString());
#ifdef UPDATER
CoreSettingsSetValue(SettingsID::GUI_CheckForUpdates, this->checkForUpdatesCheckBox->isChecked());
#endif // UPDATER
@@ -792,6 +819,22 @@ void SettingsDialog::commonHotkeySettings(SettingsDialogAction action)
{ this->gsButtonKeyButton, SettingsID::KeyBinding_GSButton },
};
std::vector<keybinding> keybindings_SpeedFactor =
{
{ this->speedFactor25KeyButton, SettingsID::KeyBinding_SpeedFactor25 },
{ this->speedFactor50KeyButton, SettingsID::KeyBinding_SpeedFactor50 },
{ this->speedFactor75KeyButton, SettingsID::KeyBinding_SpeedFactor75 },
{ this->speedFactor100KeyButton, SettingsID::KeyBinding_SpeedFactor100 },
{ this->speedFactor125KeyButton, SettingsID::KeyBinding_SpeedFactor125 },
{ this->speedFactor150KeyButton, SettingsID::KeyBinding_SpeedFactor150 },
{ this->speedFactor175KeyButton, SettingsID::KeyBinding_SpeedFactor175 },
{ this->speedFactor200KeyButton, SettingsID::KeyBinding_SpeedFactor200 },
{ this->speedFactor225KeyButton, SettingsID::KeyBinding_SpeedFactor225 },
{ this->speedFactor250KeyButton, SettingsID::KeyBinding_SpeedFactor250 },
{ this->speedFactor275KeyButton, SettingsID::KeyBinding_SpeedFactor275 },
{ this->speedFactor300KeyButton, SettingsID::KeyBinding_SpeedFactor300 },
};
std::vector<keybinding> keybindings_CurrentSaveState =
{
{ this->saveState0KeyButton, SettingsID::KeyBinding_SaveStateSlot0 },
@@ -808,12 +851,17 @@ void SettingsDialog::commonHotkeySettings(SettingsDialogAction action)
std::vector<keybinding> keybindings_Settings =
{
{ this->graphicsSettingsKeyButton, SettingsID::KeyBinding_GraphicsSettings },
{ this->audioSettingsKeyButton, SettingsID::KeyBinding_AudioSettings },
{ this->rspSettingsKeyButton, SettingsID::KeyBinding_RspSettings },
{ this->inputSettingsKeyButton, SettingsID::KeyBinding_InputSettings },
{ this->settingsKeyButton, SettingsID::KeyBinding_Settings },
};
std::vector<keybinding> keybindings_View =
{
{ this->fullscreenKeyButton, SettingsID::KeyBinding_Fullscreen },
{ this->logKeyButton, SettingsID::Keybinding_ViewLog },
{ this->refreshRomListKeyButton, SettingsID::KeyBinding_RefreshROMList }
};
@@ -828,12 +876,15 @@ void SettingsDialog::commonHotkeySettings(SettingsDialogAction action)
keybindings.insert(keybindings.end(), keybindings_System.begin(), keybindings_System.end());
break;
case 1:
keybindings.insert(keybindings.end(), keybindings_CurrentSaveState.begin(), keybindings_CurrentSaveState.end());
keybindings.insert(keybindings.end(), keybindings_SpeedFactor.begin(), keybindings_SpeedFactor.end());
break;
case 2:
keybindings.insert(keybindings.end(), keybindings_Settings.begin(), keybindings_Settings.end());
keybindings.insert(keybindings.end(), keybindings_CurrentSaveState.begin(), keybindings_CurrentSaveState.end());
break;
case 3:
keybindings.insert(keybindings.end(), keybindings_Settings.begin(), keybindings_Settings.end());
break;
case 4:
keybindings.insert(keybindings.end(), keybindings_View.begin(), keybindings_View.end());
break;
}
@@ -841,6 +892,7 @@ void SettingsDialog::commonHotkeySettings(SettingsDialogAction action)
else
{
keybindings.insert(keybindings.end(), keybindings_System.begin(), keybindings_System.end());
keybindings.insert(keybindings.end(), keybindings_SpeedFactor.begin(), keybindings_SpeedFactor.end());
keybindings.insert(keybindings.end(), keybindings_CurrentSaveState.begin(), keybindings_CurrentSaveState.end());
keybindings.insert(keybindings.end(), keybindings_Settings.begin(), keybindings_Settings.end());
keybindings.insert(keybindings.end(), keybindings_View.begin(), keybindings_View.end());
@@ -891,7 +943,7 @@ void SettingsDialog::commonPluginSettings(SettingsDialogAction action)
bool pluginFound[] = {false, false, false, false};
QComboBox *comboBox;
std::string pluginFileName;
QString pluginFileName;
int index = 0;
// clear combobox items
@@ -906,12 +958,15 @@ void SettingsDialog::commonPluginSettings(SettingsDialogAction action)
comboBox = comboBoxArray[index];
pluginFileName = action == SettingsDialogAction::LoadSettings ?
CoreSettingsGetStringValue(settingsIdArray[index]) :
CoreSettingsGetDefaultStringValue(settingsIdArray[index]);
QString::fromStdString(CoreSettingsGetStringValue(settingsIdArray[index])) :
QString::fromStdString(CoreSettingsGetDefaultStringValue(settingsIdArray[index]));
// account for full path (<v0.3.5 we used the full path)
pluginFileName = QFileInfo(pluginFileName).fileName();
comboBox->addItem(QString::fromStdString(p.Name), QString::fromStdString(p.File));
if (pluginFileName == p.File)
if (pluginFileName == QString::fromStdString(p.File))
{
comboBox->setCurrentText(QString::fromStdString(p.Name));
pluginFound[index] = true;
@@ -934,7 +989,7 @@ void SettingsDialog::setIconsForEmulationInfoText(void)
QLabel* labels[] = {
this->infoIconLabel_0, this->infoIconLabel_1, this->infoIconLabel_2,
this->infoIconLabel_3, this->infoIconLabel_4, this->infoIconLabel_5,
this->infoIconLabel_7
this->infoIconLabel_7, this->infoIconLabel_6, this->infoIconLabel_8
};
QIcon infoIcon = QIcon::fromTheme("information-line");
@@ -1148,7 +1203,12 @@ void SettingsDialog::on_KeybindButton_KeybindingChanged(KeybindButton* button)
this->startComboKeyButton,
this->shutdownKeyButton,
this->exitKeyButton,
this->graphicsSettingsKeyButton,
this->audioSettingsKeyButton,
this->rspSettingsKeyButton,
this->inputSettingsKeyButton,
this->settingsKeyButton,
this->logKeyButton,
this->refreshRomListKeyButton,
};
@@ -1160,6 +1220,18 @@ void SettingsDialog::on_KeybindButton_KeybindingChanged(KeybindButton* button)
this->pauseKeyButton,
this->generateBitmapKeyButton,
this->limitFPSKeyButton,
this->speedFactor25KeyButton,
this->speedFactor50KeyButton,
this->speedFactor75KeyButton,
this->speedFactor100KeyButton,
this->speedFactor125KeyButton,
this->speedFactor150KeyButton,
this->speedFactor175KeyButton,
this->speedFactor200KeyButton,
this->speedFactor225KeyButton,
this->speedFactor250KeyButton,
this->speedFactor275KeyButton,
this->speedFactor300KeyButton,
this->saveStateKeyButton,
this->saveAsKeyButton,
this->loadStateKeyButton,
@@ -1177,7 +1249,12 @@ void SettingsDialog::on_KeybindButton_KeybindingChanged(KeybindButton* button)
this->saveState8KeyButton,
this->saveState9KeyButton,
this->exitKeyButton,
this->graphicsSettingsKeyButton,
this->audioSettingsKeyButton,
this->rspSettingsKeyButton,
this->inputSettingsKeyButton,
this->settingsKeyButton,
this->logKeyButton,
this->fullscreenKeyButton,
};
@@ -407,7 +407,7 @@
<attribute name="title">
<string>Miscellaneous</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_8">
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_13">
<item>
@@ -438,6 +438,36 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_14">
<item>
<widget class="QLabel" name="label_13">
<property name="text">
<string>Icon Theme</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="iconThemeComboBox">
<item>
<property name="text">
<string>Automatic</string>
</property>
</item>
<item>
<property name="text">
<string>White</string>
</property>
</item>
<item>
<property name="text">
<string>Black</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkForUpdatesCheckBox">
<property name="text">
@@ -831,6 +861,242 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="speedFactorTab">
<attribute name="title">
<string>Speed Factor</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_105">
<item>
<widget class="QLabel" name="label_102">
<property name="text">
<string>25%</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="speedFactor25KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_106">
<item>
<widget class="QLabel" name="label_103">
<property name="text">
<string>50%</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="speedFactor50KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_107">
<item>
<widget class="QLabel" name="label_104">
<property name="text">
<string>75%</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="speedFactor75KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_108">
<item>
<widget class="QLabel" name="label_105">
<property name="text">
<string>100%</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="speedFactor100KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_109">
<item>
<widget class="QLabel" name="label_106">
<property name="text">
<string>125%</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="speedFactor125KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_110">
<item>
<widget class="QLabel" name="label_107">
<property name="text">
<string>150%</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="speedFactor150KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_111">
<item>
<widget class="QLabel" name="label_108">
<property name="text">
<string>175%</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="speedFactor175KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_112">
<item>
<widget class="QLabel" name="label_109">
<property name="text">
<string>200%</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="speedFactor200KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_113">
<item>
<widget class="QLabel" name="label_110">
<property name="text">
<string>225%</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="speedFactor225KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_114">
<item>
<widget class="QLabel" name="label_111">
<property name="text">
<string>250%</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="speedFactor250KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_115">
<item>
<widget class="QLabel" name="label_112">
<property name="text">
<string>275%</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="speedFactor275KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_116">
<item>
<widget class="QLabel" name="label_113">
<property name="text">
<string>300%</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="speedFactor300KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_9">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="currentSaveStateTab">
<attribute name="title">
<string>Current Save State</string>
@@ -1035,7 +1301,79 @@
<attribute name="title">
<string>Settings</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_37">
<layout class="QVBoxLayout" name="verticalLayout_14">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_92">
<item>
<widget class="QLabel" name="label_85">
<property name="text">
<string>Graphics</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="graphicsSettingsKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_93">
<item>
<widget class="QLabel" name="label_87">
<property name="text">
<string>Audio</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="audioSettingsKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_94">
<item>
<widget class="QLabel" name="label_89">
<property name="text">
<string>RSP</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="rspSettingsKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_117">
<item>
<widget class="QLabel" name="label_90">
<property name="text">
<string>Input</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="inputSettingsKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_87">
<item>
@@ -1092,6 +1430,24 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_118">
<item>
<widget class="QLabel" name="label_114">
<property name="text">
<string>Log</string>
</property>
</widget>
</item>
<item>
<widget class="KeybindButton" name="logKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_73">
<item>
@@ -1144,7 +1500,7 @@
<attribute name="title">
<string>Core</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_19">
<layout class="QVBoxLayout" name="verticalLayout_17">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_43">
<item>
@@ -1175,6 +1531,31 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_46">
<item>
<widget class="QLabel" name="label_25">
<property name="text">
<string>Save Filename Format</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="coreSaveFilenameFormatComboBox">
<item>
<property name="text">
<string>Internal ROM Name</string>
</property>
</item>
<item>
<property name="text">
<string>Automatic</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="coreOverrideGameSettingsGroup">
<property name="enabled">
@@ -1692,7 +2073,7 @@
<attribute name="title">
<string>Plugins</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_24">
<layout class="QVBoxLayout" name="verticalLayout_16">
<item>
<widget class="QGroupBox" name="groupBox_19">
<property name="enabled">
@@ -1824,6 +2205,51 @@
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="emulationInfoLayout_6">
<item>
<widget class="QLabel" name="infoIconLabel_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap>:/newPrefix/Resource/Info.ico</pixmap>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_68">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="midLineWidth">
<number>1</number>
</property>
<property name="text">
<string>Make sure to use a LLE RSP plugin (i.e paraLLEl RSP) when using a LLE Video plugin (i.e paraLLEl)</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
@@ -1876,7 +2302,7 @@
<attribute name="title">
<string>Plugins</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_25">
<layout class="QVBoxLayout" name="verticalLayout_15">
<item>
<widget class="QGroupBox" name="groupBox_25">
<property name="title">
@@ -1975,6 +2401,51 @@
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="emulationInfoLayout_4">
<item>
<widget class="QLabel" name="infoIconLabel_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap>:/newPrefix/Resource/Info.ico</pixmap>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_64">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="midLineWidth">
<number>1</number>
</property>
<property name="text">
<string>Make sure to use a LLE RSP plugin (i.e paraLLEl RSP) when using a LLE Video plugin (i.e paraLLEl)</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="emulationInfoLayout_1">
<item>
@@ -23,7 +23,7 @@
using namespace UserInterface::Dialog;
UpdateDialog::UpdateDialog(QWidget *parent, QJsonObject jsonObject) : QDialog(parent)
UpdateDialog::UpdateDialog(QWidget *parent, QJsonObject jsonObject, bool forced) : QDialog(parent)
{
this->setupUi(this);
@@ -35,6 +35,10 @@ UpdateDialog::UpdateDialog(QWidget *parent, QJsonObject jsonObject) : QDialog(pa
// change ok button text to 'Update'
QPushButton* button = this->buttonBox->button(QDialogButtonBox::Ok);
button->setText("Update");
// don't show the 'Don't check for updates again' checkbox,
// when the user requested we check for updates
this->disableUpdateCheckCheckBox->setHidden(forced);
}
UpdateDialog::~UpdateDialog(void)
@@ -36,7 +36,7 @@ class UpdateDialog : public QDialog, private Ui::UpdateDialog
#endif // _WIN32
public:
UpdateDialog(QWidget *parent, QJsonObject jsonObject);
UpdateDialog(QWidget *parent, QJsonObject jsonObject, bool forced);
~UpdateDialog(void);
QString GetFileName(void);
File diff suppressed because it is too large Load Diff
+67 -44
View File
@@ -47,19 +47,19 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
MainWindow(void);
~MainWindow(void);
bool Init(QApplication*);
void OpenROM(QString, QString, bool, bool);
bool Init(QApplication* app, bool showUI);
void OpenROM(QString file, QString disk, bool fullscreen, bool quitAfterEmulation);
private:
Thread::EmulationThread *emulationThread;
Thread::EmulationThread *emulationThread = nullptr;
CoreCallbacks* coreCallBacks;
CoreCallbacks* coreCallBacks = nullptr;
QStackedWidget *ui_Widgets;
Widget::OGLWidget *ui_Widget_OpenGL;
Widget::RomBrowserWidget *ui_Widget_RomBrowser;
EventFilter *ui_EventFilter;
QLabel *ui_StatusBar_Label;
QStackedWidget *ui_Widgets = nullptr;
Widget::OGLWidget *ui_Widget_OpenGL = nullptr;
Widget::RomBrowserWidget *ui_Widget_RomBrowser = nullptr;
EventFilter *ui_EventFilter = nullptr;
QLabel *ui_StatusBar_Label = nullptr;
QByteArray ui_Geometry;
bool ui_Geometry_Maximized = false;
@@ -73,16 +73,29 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
bool ui_QuitAfterEmulation = false;
bool ui_RefreshRomListAfterEmulation = false;
bool ui_ShowUI = false;
bool ui_ShowMenubar = false;
bool ui_ShowToolbar = false;
bool ui_ShowStatusbar = false;
bool ui_ManuallyPaused = true;
bool ui_ManuallySavedState = false;
bool ui_ManuallyLoadedState = false;
QList<QAction*> ui_Actions;
bool ui_AddedActions = false;
QList<QAction*> ui_SlotActions;
bool ui_SilentUpdateCheck = false;
int ui_TimerId = 0;
int ui_TimerTimeout = 0;
int ui_FullscreenTimerId = 0;
int ui_GamesharkButtonTimerId = 0;
int ui_UpdateSaveStateSlotTimerId = 0;
QString ui_WindowTitle;
@@ -91,43 +104,49 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
void closeEvent(QCloseEvent *) Q_DECL_OVERRIDE;
void initializeUI();
void configureUI(QApplication*);
void configureTheme(QApplication*);
void showErrorMessage(QString, QString);
void updateUI(bool, bool);
void configureUI(QApplication* app, bool showUI);
void configureTheme(QApplication* app);
void showErrorMessage(QString text, QString details = "");
void updateUI(bool inEmulation, bool isPaused);
void storeGeometry(void);
void loadGeometry(void);
void initializeEmulationThread(void);
void connectEmulationThreadSignals(void);
void launchEmulationThread(QString, QString);
void launchEmulationThread(QString);
void launchEmulationThread(QString cartRom, QString diskRom = "");
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, bool);
void updateActions(bool inEmulation, bool isPaused);
void updateSaveStateSlotActions(bool inEmulation, bool isPaused);
void addFullscreenActions(void);
void removeFullscreenActions(void);
void addActions(void);
void removeActions(void);
#ifdef UPDATER
void checkForUpdates(void);
void checkForUpdates(bool silent, bool force);
#endif // UPDATER
protected:
void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE;
void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE;
private slots:
void on_EventFilter_KeyPressed(QKeyEvent *);
void on_EventFilter_KeyReleased(QKeyEvent *);
void on_EventFilter_KeyPressed(QKeyEvent *event);
void on_EventFilter_KeyReleased(QKeyEvent *event);
void on_QGuiApplication_applicationStateChanged(Qt::ApplicationState);
void on_QGuiApplication_applicationStateChanged(Qt::ApplicationState state);
#ifdef UPDATER
void on_networkAccessManager_Finished(QNetworkReply *);
void on_networkAccessManager_Finished(QNetworkReply *reply);
#endif // UPDATER
void on_Action_System_OpenRom(void);
@@ -138,11 +157,12 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
void on_Action_System_Pause(void);
void on_Action_System_Screenshot(void);
void on_Action_System_LimitFPS(void);
void on_Action_System_SpeedFactor(int factor);
void on_Action_System_SaveState(void);
void on_Action_System_SaveAs(void);
void on_Action_System_LoadState(void);
void on_Action_System_Load(void);
void on_Action_System_CurrentSaveState(int);
void on_Action_System_CurrentSaveState(int slot);
void on_Action_System_Cheats(void);
void on_Action_System_GSButton(void);
void on_Action_System_Exit(void);
@@ -153,11 +173,11 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
void on_Action_Settings_Input(void);
void on_Action_Settings_Settings(void);
void on_Action_View_Toolbar(bool);
void on_Action_View_StatusBar(bool);
void on_Action_View_GameList(bool);
void on_Action_View_GameGrid(bool);
void on_Action_View_UniformSize(bool);
void on_Action_View_Toolbar(bool checked);
void on_Action_View_StatusBar(bool checked);
void on_Action_View_GameList(bool checked);
void on_Action_View_GameGrid(bool checked);
void on_Action_View_UniformSize(bool checked);
void on_Action_View_Fullscreen(void);
void on_Action_View_RefreshRoms(void);
void on_Action_View_ClearRomCache(void);
@@ -165,27 +185,30 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
void on_Action_Help_Github(void);
void on_Action_Help_About(void);
void on_Action_Help_Update(void);
void on_Emulation_Started(void);
void on_Emulation_Finished(bool);
void on_Emulation_Finished(bool ret);
void on_RomBrowser_PlayGame(QString);
void on_RomBrowser_PlayGameWith(CoreRomType, QString);
void on_RomBrowser_PlayGame(QString file);
void on_RomBrowser_PlayGameWith(CoreRomType type, QString file);
void on_RomBrowser_ChangeRomDirectory(void);
void on_RomBrowser_RomInformation(QString);
void on_RomBrowser_EditGameSettings(QString);
void on_RomBrowser_Cheats(QString);
void on_RomBrowser_RomInformation(QString file);
void on_RomBrowser_EditGameSettings(QString file);
void on_RomBrowser_EditGameInputSettings(QString file);
void on_RomBrowser_Cheats(QString file);
public slots:
void on_VidExt_Init(void);
void on_VidExt_SetupOGL(QSurfaceFormat, QThread *);
void on_VidExt_SetWindowedMode(int, int, int, int);
void on_VidExt_SetFullscreenMode(int, int, int, int);
void on_VidExt_ResizeWindow(int, int);
void on_VidExt_ToggleFS(bool);
void on_VidExt_SetupOGL(QSurfaceFormat format, QThread *thread);
void on_VidExt_SetWindowedMode(int width, int height, int bps, int flags);
void on_VidExt_SetFullscreenMode(int width, int height, int bps, int flags);
void on_VidExt_ResizeWindow(int width, int height);
void on_VidExt_ToggleFS(bool fullscreen);
void on_Core_DebugCallback(CoreDebugMessageType, QString, QString);
void on_Core_DebugCallback(CoreDebugMessageType type, QString context, QString message);
void on_Core_StateCallback(CoreStateCallbackType type, int value);
};
} // namespace UserInterface
+103 -1
View File
@@ -63,6 +63,30 @@
<addaction name="actionSlot_8"/>
<addaction name="actionSlot_9"/>
</widget>
<widget class="QMenu" name="menuSpeedFactor">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Speed Factor</string>
</property>
<property name="icon">
<iconset theme="speed-line">
<normaloff>.</normaloff>.</iconset>
</property>
<addaction name="actionSpeed25"/>
<addaction name="actionSpeed50"/>
<addaction name="actionSpeed75"/>
<addaction name="actionSpeed100"/>
<addaction name="actionSpeed125"/>
<addaction name="actionSpeed150"/>
<addaction name="actionSpeed175"/>
<addaction name="actionSpeed200"/>
<addaction name="actionSpeed225"/>
<addaction name="actionSpeed250"/>
<addaction name="actionSpeed275"/>
<addaction name="actionSpeed300"/>
</widget>
<addaction name="action_System_StartRom"/>
<addaction name="action_System_OpenCombo"/>
<addaction name="separator"/>
@@ -73,6 +97,7 @@
<addaction name="action_System_Screenshot"/>
<addaction name="separator"/>
<addaction name="action_System_LimitFPS"/>
<addaction name="menuSpeedFactor"/>
<addaction name="separator"/>
<addaction name="action_System_SaveState"/>
<addaction name="action_System_SaveAs"/>
@@ -122,6 +147,8 @@
</property>
<addaction name="action_Help_Github"/>
<addaction name="separator"/>
<addaction name="action_Help_Update"/>
<addaction name="separator"/>
<addaction name="action_Help_About"/>
</widget>
<addaction name="menuSystem"/>
@@ -135,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>
@@ -532,6 +562,78 @@
<string>Uniform Size (Grid View)</string>
</property>
</action>
<action name="actionSpeed25">
<property name="checkable">
<bool>false</bool>
</property>
<property name="text">
<string>25%</string>
</property>
</action>
<action name="actionSpeed50">
<property name="text">
<string>50%</string>
</property>
</action>
<action name="actionSpeed100">
<property name="text">
<string>100%</string>
</property>
</action>
<action name="actionSpeed125">
<property name="text">
<string>125%</string>
</property>
</action>
<action name="actionSpeed150">
<property name="text">
<string>150%</string>
</property>
</action>
<action name="actionSpeed200">
<property name="text">
<string>200%</string>
</property>
</action>
<action name="actionSpeed75">
<property name="text">
<string>75%</string>
</property>
</action>
<action name="actionSpeed175">
<property name="text">
<string>175%</string>
</property>
</action>
<action name="actionSpeed225">
<property name="text">
<string>225%</string>
</property>
</action>
<action name="actionSpeed250">
<property name="text">
<string>250%</string>
</property>
</action>
<action name="actionSpeed275">
<property name="text">
<string>275%</string>
</property>
</action>
<action name="actionSpeed300">
<property name="text">
<string>300%</string>
</property>
</action>
<action name="action_Help_Update">
<property name="icon">
<iconset theme="download-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Check For Updates</string>
</property>
</action>
</widget>
<resources>
<include location="UIResources.qrc"/>
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 19h18v2H3v-2zm10-5.828L19.071 7.1l1.414 1.414L12 17 3.515 8.515 4.929 7.1 11 13.17V2h2v11.172z"/></svg>

After

Width:  |  Height:  |  Size: 235 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 19h18v2H3v-2zm10-5.828L19.071 7.1l1.414 1.414L12 17 3.515 8.515 4.929 7.1 11 13.17V2h2v11.172z" fill="#ffffff"/></svg>

After

Width:  |  Height:  |  Size: 250 B

+2
View File
@@ -11,6 +11,7 @@
<file alias="icons/black/svg/delete-back-line.svg">Resource/icons/black/svg/delete-back-line.svg</file>
<file alias="icons/black/svg/delete-bin-line.svg">Resource/icons/black/svg/delete-bin-line.svg</file>
<file alias="icons/black/svg/door-open-line.svg">Resource/icons/black/svg/door-open-line.svg</file>
<file alias="icons/black/svg/download-line.svg">Resource/icons/black/svg/download-line.svg</file>
<file alias="icons/black/svg/file-line.svg">Resource/icons/black/svg/file-line.svg</file>
<file alias="icons/black/svg/file-list-line.svg">Resource/icons/black/svg/file-list-line.svg</file>
<file alias="icons/black/svg/folder-open-line.svg">Resource/icons/black/svg/folder-open-line.svg</file>
@@ -40,6 +41,7 @@
<file alias="icons/white/svg/delete-back-line.svg">Resource/icons/white/svg/delete-back-line.svg</file>
<file alias="icons/white/svg/delete-bin-line.svg">Resource/icons/white/svg/delete-bin-line.svg</file>
<file alias="icons/white/svg/door-open-line.svg">Resource/icons/white/svg/door-open-line.svg</file>
<file alias="icons/white/svg/download-line.svg">Resource/icons/white/svg/download-line.svg</file>
<file alias="icons/white/svg/file-line.svg">Resource/icons/white/svg/file-line.svg</file>
<file alias="icons/white/svg/file-list-line.svg">Resource/icons/white/svg/file-list-line.svg</file>
<file alias="icons/white/svg/folder-open-line.svg">Resource/icons/white/svg/folder-open-line.svg</file>
@@ -65,9 +65,11 @@ void OGLWidget::resizeEvent(QResizeEvent *event)
void OGLWidget::timerEvent(QTimerEvent *event)
{
CoreSetVideoSize(this->width, this->height);
// remove current timer
this->killTimer(this->timerId);
this->timerId = 0;
// only remove current timer
// when setting the video size succeeds
if (CoreSetVideoSize(this->width, this->height))
{
this->killTimer(this->timerId);
this->timerId = 0;
}
}
@@ -11,6 +11,7 @@
#include <QLabel>
#include <QHBoxLayout>
#include <QTimerEvent>
using namespace UserInterface::Widget;
@@ -36,6 +37,12 @@ void RomBrowserLoadingWidget::SetWidgetIndex(int index)
this->widgetIndex = index;
}
void RomBrowserLoadingWidget::SetCurrentRomIndex(int index, int count)
{
this->romIndex = index;
this->romCount = count;
}
void RomBrowserLoadingWidget::on_RomBrowserWidget_currentChanged(int index)
{
// start timer when it isnt running
@@ -45,6 +52,12 @@ void RomBrowserLoadingWidget::on_RomBrowserWidget_currentChanged(int index)
{
if (this->loadingLabelTimerId == -1)
{
this->dotCount = 0;
this->romIndex = 0;
this->romCount = 0;
this->elapsedTimeSinceLoading.start();
// reset loading text
this->updateLoadingText();
this->loadingLabelTimerId = this->startTimer(1000);
}
}
@@ -52,20 +65,52 @@ void RomBrowserLoadingWidget::on_RomBrowserWidget_currentChanged(int index)
{
if (this->loadingLabelTimerId != -1)
{
this->elapsedTimeSinceLoading.invalidate();
this->killTimer(this->loadingLabelTimerId);
this->loadingLabelTimerId = -1;
}
}
}
void RomBrowserLoadingWidget::timerEvent(QTimerEvent *event)
void RomBrowserLoadingWidget::updateLoadingText()
{
if (this->loadingLabel->text().size() >= 10)
QString loadingText = "Loading";
if (this->elapsedTimeSinceLoading.isValid() &&
this->elapsedTimeSinceLoading.elapsed() >= 5000)
{
this->loadingLabel->setText("Loading");
QString romCountString = QString::number(this->romCount);
loadingText += " [";
loadingText += QString::number(this->romIndex).rightJustified(romCountString.size(), '0', false);
loadingText += "/";
loadingText += romCountString;
loadingText += "]";
}
if (dotCount <= 3)
{
for (int i = 0; i < dotCount; i++)
{
loadingText += ".";
}
dotCount++;
}
else
{
this->loadingLabel->setText(this->loadingLabel->text() + ".");
dotCount = 1;
}
this->loadingLabel->setText(loadingText);
}
void RomBrowserLoadingWidget::timerEvent(QTimerEvent *event)
{
if (event->timerId() != this->loadingLabelTimerId)
{
return;
}
this->updateLoadingText();
}
@@ -12,6 +12,7 @@
#include <QWidget>
#include <QLabel>
#include <QElapsedTimer>
namespace UserInterface
{
@@ -26,6 +27,8 @@ public:
void SetWidgetIndex(int index);
void SetCurrentRomIndex(int index, int count);
public slots:
void on_RomBrowserWidget_currentChanged(int index);
@@ -33,6 +36,13 @@ private:
QLabel* loadingLabel;
int loadingLabelTimerId = -1;
int widgetIndex = -1;
int romIndex = 0;
int romCount = 0;
int dotCount = 0;
QElapsedTimer elapsedTimeSinceLoading;
void updateLoadingText();
protected:
void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE;

Some files were not shown because too many files have changed in this diff Show More