Compare commits

...

42 Commits

Author SHA1 Message Date
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
63 changed files with 4836 additions and 143 deletions
+20 -1
View File
@@ -8,6 +8,7 @@ option(NO_GIT_CLONE "Disables git clone usage for 3rdParty dependencies" OFF
option(UPDATER "Enables updater" ${PORTABLE_INSTALL})
option(APPIMAGE_UPDATER "Enables AppImage updater" OFF)
option(DISCORD_RPC "Enables Discord Rich Presence" ON)
option(VRU "Enables VRU support in RMG-Input" ON)
option(USE_CCACHE "Enables usage of ccache when ccache has been found" ON)
option(FORCE_XCB "Forces Qt to use the xcb platform on linux" ${LINUX})
option(NO_RUST "Disables the building of rust subprojects" OFF)
@@ -61,12 +62,16 @@ if (PORTABLE_INSTALL)
set(CMAKE_INSTALL_PREFIX "")
set(INSTALL_PATH "Bin/${CMAKE_BUILD_TYPE}")
set(RMG_INSTALL_PATH "${INSTALL_PATH}")
set(SYSTEM_LIB_INSTALL_PATH "${INSTALL_PATH}")
set(LIB_INSTALL_PATH "${INSTALL_PATH}")
set(CORE_INSTALL_PATH "${INSTALL_PATH}/Core")
set(PLUGIN_INSTALL_PATH "${INSTALL_PATH}/Plugin")
set(DATA_INSTALL_PATH "${INSTALL_PATH}/Data")
set(INSTALL_DESKTOP_FILE OFF)
else()
set(RMG_INSTALL_PATH "bin")
set(SYSTEM_LIB_INSTALL_PATH "lib")
set(LIB_INSTALL_PATH "lib/RMG")
set(CORE_INSTALL_PATH "lib/RMG/Core")
set(PLUGIN_INSTALL_PATH "lib/RMG/Plugin")
set(DATA_INSTALL_PATH "share/RMG")
@@ -78,11 +83,17 @@ endif()
add_subdirectory(Source/3rdParty)
add_subdirectory(Source/3rdParty/7-Zip)
if (VRU)
add_subdirectory(Source/3rdParty/vosk-api)
endif(VRU)
add_subdirectory(Source/RMG-Core)
add_subdirectory(Source/RMG)
add_subdirectory(Source/RMG-Audio)
add_subdirectory(Source/RMG-Input)
install(TARGETS RMG-Core
DESTINATION ${SYSTEM_LIB_INSTALL_PATH}
)
install(TARGETS RMG
DESTINATION ${RMG_INSTALL_PATH}
)
@@ -95,7 +106,7 @@ install(TARGETS RMG-Input
if (WIN32)
add_subdirectory(Source/Installer)
add_custom_target(bundle_dependencies
COMMAND bash "${CMAKE_SOURCE_DIR}/Source/Script/BundleDependencies.sh" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}/RMG.exe" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}" "/mingw64/bin"
)
@@ -107,6 +118,14 @@ install(FILES ${MUPEN64PLUSCORE_LIB}
install(FILES ${MUPEN64PLUSCORE_INI} Data/font.ttf
DESTINATION ${DATA_INSTALL_PATH}
)
if (VRU)
install(FILES ${VOSK_API_LIBRARY}
DESTINATION ${LIB_INSTALL_PATH}
)
install(FILES ${VOSK_API_MODEL}
DESTINATION ${DATA_INSTALL_PATH}
)
endif(VRU)
install(FILES ${SDL_GAMECONTROLLERDB}
DESTINATION ${DATA_INSTALL_PATH}
)
+1
View File
@@ -4,6 +4,7 @@ set -e
cur_dir="$(readlink -f "$(dirname "$0")")"
exec "$cur_dir/usr/bin/RMG" \
--lib-path="$cur_dir/usr/lib/RMG" \
--core-path="$cur_dir/usr/lib/RMG/Core" \
--plugin-path="$cur_dir/usr/lib/RMG/Plugin" \
--shared-data-path="$cur_dir/usr/share/RMG" \
+1
View File
@@ -9,6 +9,7 @@ export QMAKE="$(which qmake6)"
export EXTRA_QT_PLUGINS="imageformats;iconengines;"
export VERSION="$(git describe --tags --always)"
export OUTPUT="$bin_dir/../RMG-Portable-Linux64-$VERSION.AppImage"
export LD_LIBRARY_PATH="$toplvl_dir/build/Source/RMG-Core" # hack
if [ ! -f "$script_dir/linuxdeploy-x86_64.AppImage" ]
then
+1 -1
View File
@@ -1,6 +1,6 @@
# Maintainer: Rosalie Wanders <rosalie@mailbox.org>
pkgname=rmg
pkgver=0.3.9
pkgver=0.4.3
pkgrel=1
pkgdesc="Rosalie's Mupen GUI"
arch=('x86_64')
Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 KiB

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 80 KiB

@@ -33,6 +33,44 @@
</screenshot>
</screenshots>
<releases>
<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>
+3 -1
View File
@@ -17,7 +17,9 @@ You can download Rosalie's Mupen GUI on
## Support
Join the [Rosalie's Mupen GUI Discord Server](https://discord.gg/k9GuyJ2PpF) for support
You can ask for help or report issues on
* [Github](https://github.com/Rosalie241/RMG/issues/new)
* [Discord](https://discord.gg/k9GuyJ2PpF)
## License
+1 -1
View File
@@ -31,7 +31,7 @@ set(7ZIP_SOURCES
add_custom_command(
OUTPUT ${7ZIP_SOURCES}
COMMAND ${CMAKE_COMMAND} -E tar "xvz" "${CMAKE_CURRENT_SOURCE_DIR}/lzma2201.tar.gz"
COMMAND ${CMAKE_COMMAND} -E tar "xvz" "${CMAKE_CURRENT_SOURCE_DIR}/lzma2301.tar.gz"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
+1 -1
View File
@@ -1,2 +1,2 @@
# 7-Zip SDK v22.01
# 7-Zip SDK v23.01
Downloaded from https://www.7-zip.org/sdk.html
Binary file not shown.
Binary file not shown.
+10 -10
View File
@@ -38,8 +38,8 @@ else(USE_CCACHE)
endif(USE_CCACHE)
if(NOT NO_GIT_CLONE)
set(MUPEN64PLUSCORE_URL "https://github.com/mupen64plus/mupen64plus-core")
set(MUPEN64PLUSCORE_TAG "d4f3e12db0609158c7b4e0beef2bb950aad0ccb9")
set(MUPEN64PLUSCORE_URL "https://github.com/Rosalie241/mupen64plus-core")
set(MUPEN64PLUSCORE_TAG "bb6949ad2ab268024ee4049279abc2f3c7fbdbb4")
set(MUPEN64PLUS_RSP_CXD4_URL "https://github.com/mupen64plus/mupen64plus-rsp-cxd4")
set(MUPEN64PLUS_RSP_CXD4_TAG "39f79201baa15890c4cbae92f2215a634cc3ee6d")
@@ -54,13 +54,13 @@ if(NOT NO_GIT_CLONE)
set(MUPEN64PLUS_INPUT_RAPHNET_TAG "86112413e98a8648edb11d199673cc24d5799af8")
set(MUPEN64PLUS_INPUT_GCA_URL "https://github.com/amatho/mupen64plus-input-gca")
set(MUPEN64PLUS_INPUT_GCA_TAG "a6886b1ae022936a2e542af9bfbab40ea0af5af5")
set(MUPEN64PLUS_INPUT_GCA_TAG "21639fb13dfa797a7c0949ffd9bbda9a3456fc69")
set(MUPEN64PLUS_GFX_ANGRYLION_URL "https://github.com/Rosalie241/angrylion-rdp-plus")
set(MUPEN64PLUS_GFX_ANGRYLION_TAG "670abbc972bd430fa77291b0967dd73128314317")
set(MUPEN64PLUS_GFX_GLIDEN64_URL "https://github.com/gonetz/GLideN64")
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "0fee30d010d1feda7d343654871b3dfd05ccab70")
set(MUPEN64PLUS_GFX_GLIDEN64_URL "https://github.com/Rosalie241/GLideN64")
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "2f1b358028e700fcae2502a53f4f5e6822ce0367")
set(MUPEN64PLUS_GFX_PARALLEL_URL "https://github.com/Rosalie241/parallel-rdp-standalone")
set(MUPEN64PLUS_GFX_PARALLEL_TAG "2c2226517c4c8929e08ec944654867e26efe0cf5")
@@ -72,7 +72,7 @@ if(NOT NO_GIT_CLONE)
set(IMGUI_TAG "d7c8516a4b848c0291e3d75b627c0843f515f591")
set(SDL_GAMECONTROLLERDB_URL "https://github.com/gabomdq/SDL_GameControllerDB")
set(SDL_GAMECONTROLLERDB_TAG "b7e5701da82fc97beeede64d3818ef0f4d015aba")
set(SDL_GAMECONTROLLERDB_TAG "5e25aeccb84fb166451443c4cd9fff349e8b0360")
endif(NOT NO_GIT_CLONE)
ExternalProject_Add(mupen64plus-core
@@ -84,11 +84,11 @@ ExternalProject_Add(mupen64plus-core
GIT_REPOSITORY ${MUPEN64PLUSCORE_URL}
GIT_TAG ${MUPEN64PLUSCORE_TAG}
BUILD_COMMAND make all OSD=0 NEW_DYNAREC=1 TARGET=${CORE_FILE} DEBUG=$<CONFIG:Debug> KEYBINDINGS=0 CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
BUILD_COMMAND make all OSD=0 NEW_DYNAREC=1 KEYBINDINGS=0 ACCURATE_FPU=1 TARGET=${CORE_FILE} DEBUG=$<CONFIG:Debug> CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
BUILD_IN_SOURCE False
BINARY_DIR ${M64P_CORE_DIR}/projects/unix
BUILD_BYPRODUCTS ${M64P_CORE_DIR}/projects/unix/${CORE_FILE}
)
@@ -107,7 +107,7 @@ ExternalProject_Add(mupen64plus-rsp-cxd4
BUILD_IN_SOURCE False
BINARY_DIR ${THIRDPARTY_DIR}/mupen64plus-rsp-cxd4/projects/unix
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-rsp-cxd4/projects/unix/mupen64plus-rsp-cxd4.${SO_EXT}
DEPENDS mupen64plus-core
)
@@ -158,7 +158,7 @@ ExternalProject_Add(mupen64plus-input-raphnetraw
BUILD_IN_SOURCE False
BINARY_DIR ${THIRDPARTY_DIR}/mupen64plus-input-raphnetraw/projects/unix
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-input-raphnetraw/projects/unix/mupen64plus-input-raphnetraw.${SO_EXT}
DEPENDS mupen64plus-core
)
+27
View File
@@ -0,0 +1,27 @@
#
# 7-Zip CMakeLists.txt
#
project(vosk-api)
set(VOSK_API_VERSION "0.3.45")
if (WIN32)
set(VOSK_API_PLATFORM "win64")
set(SO_EXT "dll")
else(WIN32)
set(SO_EXT "so")
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
set(VOSK_API_PLATFORM "linux-aarch64")
else()
set(VOSK_API_PLATFORM "linux-x86_64")
endif()
endif(WIN32)
set(VOSK_API_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/vosk-${VOSK_API_PLATFORM}-${VOSK_API_VERSION}/libvosk.${SO_EXT}
)
add_library(vosk-api IMPORTED SHARED ${VOSK_API_SOURCES})
set(VOSK_API_LIBRARY ${VOSK_API_SOURCES} PARENT_SCOPE)
set(VOSK_API_MODEL "${CMAKE_CURRENT_SOURCE_DIR}/vosk-model-small-en-us-0.15.zip" PARENT_SCOPE)
+4
View File
@@ -0,0 +1,4 @@
# vosk-api
Downloaded from https://github.com/alphacep/vosk-api/releases/tag/v0.3.45
# vosk-model-small-en-us-0.15.zip
Downloaded from https://alphacephei.com/vosk/models
+361
View File
@@ -0,0 +1,361 @@
// Copyright 2020-2021 Alpha Cephei Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/* This header contains the C API for Vosk speech recognition system */
#ifndef VOSK_API_H
#define VOSK_API_H
#ifdef __cplusplus
extern "C" {
#endif
/** Model stores all the data required for recognition
* it contains static data and can be shared across processing
* threads. */
typedef struct VoskModel VoskModel;
/** Speaker model is the same as model but contains the data
* for speaker identification. */
typedef struct VoskSpkModel VoskSpkModel;
/** Recognizer object is the main object which processes data.
* Each recognizer usually runs in own thread and takes audio as input.
* Once audio is processed recognizer returns JSON object as a string
* which represent decoded information - words, confidences, times, n-best lists,
* speaker information and so on */
typedef struct VoskRecognizer VoskRecognizer;
/**
* Batch model object
*/
typedef struct VoskBatchModel VoskBatchModel;
/**
* Batch recognizer object
*/
typedef struct VoskBatchRecognizer VoskBatchRecognizer;
/** Loads model data from the file and returns the model object
*
* @param model_path: the path of the model on the filesystem
* @returns model object or NULL if problem occured */
VoskModel *vosk_model_new(const char *model_path);
/** Releases the model memory
*
* The model object is reference-counted so if some recognizer
* depends on this model, model might still stay alive. When
* last recognizer is released, model will be released too. */
void vosk_model_free(VoskModel *model);
/** Check if a word can be recognized by the model
* @param word: the word
* @returns the word symbol if @param word exists inside the model
* or -1 otherwise.
* Reminding that word symbol 0 is for <epsilon> */
int vosk_model_find_word(VoskModel *model, const char *word);
/** Loads speaker model data from the file and returns the model object
*
* @param model_path: the path of the model on the filesystem
* @returns model object or NULL if problem occured */
VoskSpkModel *vosk_spk_model_new(const char *model_path);
/** Releases the model memory
*
* The model object is reference-counted so if some recognizer
* depends on this model, model might still stay alive. When
* last recognizer is released, model will be released too. */
void vosk_spk_model_free(VoskSpkModel *model);
/** Creates the recognizer object
*
* The recognizers process the speech and return text using shared model data
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sample_rate The sample rate of the audio you going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @returns recognizer object or NULL if problem occured */
VoskRecognizer *vosk_recognizer_new(VoskModel *model, float sample_rate);
/** Creates the recognizer object with speaker recognition
*
* With the speaker recognition mode the recognizer not just recognize
* text but also return speaker vectors one can use for speaker identification
*
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sample_rate The sample rate of the audio you going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @param spk_model speaker model for speaker identification
* @returns recognizer object or NULL if problem occured */
VoskRecognizer *vosk_recognizer_new_spk(VoskModel *model, float sample_rate, VoskSpkModel *spk_model);
/** Creates the recognizer object with the phrase list
*
* Sometimes when you want to improve recognition accuracy and when you don't need
* to recognize large vocabulary you can specify a list of phrases to recognize. This
* will improve recognizer speed and accuracy but might return [unk] if user said
* something different.
*
* Only recognizers with lookahead models support this type of quick configuration.
* Precompiled HCLG graph models are not supported.
*
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sample_rate The sample rate of the audio you going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @param grammar The string with the list of phrases to recognize as JSON array of strings,
* for example "["one two three four five", "[unk]"]".
*
* @returns recognizer object or NULL if problem occured */
VoskRecognizer *vosk_recognizer_new_grm(VoskModel *model, float sample_rate, const char *grammar);
/** Adds speaker model to already initialized recognizer
*
* Can add speaker recognition model to already created recognizer. Helps to initialize
* speaker recognition for grammar-based recognizer.
*
* @param spk_model Speaker recognition model */
void vosk_recognizer_set_spk_model(VoskRecognizer *recognizer, VoskSpkModel *spk_model);
/** Reconfigures recognizer to use grammar
*
* @param recognizer Already running VoskRecognizer
* @param grammar Set of phrases in JSON array of strings or "[]" to use default model graph.
* See also vosk_recognizer_new_grm
*/
void vosk_recognizer_set_grm(VoskRecognizer *recognizer, char const *grammar);
/** Configures recognizer to output n-best results
*
* <pre>
* {
* "alternatives": [
* { "text": "one two three four five", "confidence": 0.97 },
* { "text": "one two three for five", "confidence": 0.03 },
* ]
* }
* </pre>
*
* @param max_alternatives - maximum alternatives to return from recognition results
*/
void vosk_recognizer_set_max_alternatives(VoskRecognizer *recognizer, int max_alternatives);
/** Enables words with times in the output
*
* <pre>
* "result" : [{
* "conf" : 1.000000,
* "end" : 1.110000,
* "start" : 0.870000,
* "word" : "what"
* }, {
* "conf" : 1.000000,
* "end" : 1.530000,
* "start" : 1.110000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 1.950000,
* "start" : 1.530000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.340000,
* "start" : 1.950000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.610000,
* "start" : 2.340000,
* "word" : "one"
* }],
* </pre>
*
* @param words - boolean value
*/
void vosk_recognizer_set_words(VoskRecognizer *recognizer, int words);
/** Like above return words and confidences in partial results
*
* @param partial_words - boolean value
*/
void vosk_recognizer_set_partial_words(VoskRecognizer *recognizer, int partial_words);
/** Set NLSML output
* @param nlsml - boolean value
*/
void vosk_recognizer_set_nlsml(VoskRecognizer *recognizer, int nlsml);
/** Accept voice data
*
* accept and process new chunk of voice data
*
* @param data - audio data in PCM 16-bit mono format
* @param length - length of the audio data
* @returns 1 if silence is occured and you can retrieve a new utterance with result method
* 0 if decoding continues
* -1 if exception occured */
int vosk_recognizer_accept_waveform(VoskRecognizer *recognizer, const char *data, int length);
/** Same as above but the version with the short data for language bindings where you have
* audio as array of shorts */
int vosk_recognizer_accept_waveform_s(VoskRecognizer *recognizer, const short *data, int length);
/** Same as above but the version with the float data for language bindings where you have
* audio as array of floats */
int vosk_recognizer_accept_waveform_f(VoskRecognizer *recognizer, const float *data, int length);
/** Returns speech recognition result
*
* @returns the result in JSON format which contains decoded line, decoded
* words, times in seconds and confidences. You can parse this result
* with any json parser
*
* <pre>
* {
* "text" : "what zero zero zero one"
* }
* </pre>
*
* If alternatives enabled it returns result with alternatives, see also vosk_recognizer_set_max_alternatives().
*
* If word times enabled returns word time, see also vosk_recognizer_set_word_times().
*/
const char *vosk_recognizer_result(VoskRecognizer *recognizer);
/** Returns partial speech recognition
*
* @returns partial speech recognition text which is not yet finalized.
* result may change as recognizer process more data.
*
* <pre>
* {
* "partial" : "cyril one eight zero"
* }
* </pre>
*/
const char *vosk_recognizer_partial_result(VoskRecognizer *recognizer);
/** Returns speech recognition result. Same as result, but doesn't wait for silence
* You usually call it in the end of the stream to get final bits of audio. It
* flushes the feature pipeline, so all remaining audio chunks got processed.
*
* @returns speech result in JSON format.
*/
const char *vosk_recognizer_final_result(VoskRecognizer *recognizer);
/** Resets the recognizer
*
* Resets current results so the recognition can continue from scratch */
void vosk_recognizer_reset(VoskRecognizer *recognizer);
/** Releases recognizer object
*
* Underlying model is also unreferenced and if needed released */
void vosk_recognizer_free(VoskRecognizer *recognizer);
/** Set log level for Kaldi messages
*
* @param log_level the level
* 0 - default value to print info and error messages but no debug
* less than 0 - don't print info messages
* greather than 0 - more verbose mode
*/
void vosk_set_log_level(int log_level);
/**
* Init, automatically select a CUDA device and allow multithreading.
* Must be called once from the main thread.
* Has no effect if HAVE_CUDA flag is not set.
*/
void vosk_gpu_init();
/**
* Init CUDA device in a multi-threaded environment.
* Must be called for each thread.
* Has no effect if HAVE_CUDA flag is not set.
*/
void vosk_gpu_thread_init();
/** Creates the batch recognizer object
*
* @returns model object or NULL if problem occured */
VoskBatchModel *vosk_batch_model_new(const char *model_path);
/** Releases batch model object */
void vosk_batch_model_free(VoskBatchModel *model);
/** Wait for the processing */
void vosk_batch_model_wait(VoskBatchModel *model);
/** Creates batch recognizer object
* @returns recognizer object or NULL if problem occured */
VoskBatchRecognizer *vosk_batch_recognizer_new(VoskBatchModel *model, float sample_rate);
/** Releases batch recognizer object */
void vosk_batch_recognizer_free(VoskBatchRecognizer *recognizer);
/** Accept batch voice data */
void vosk_batch_recognizer_accept_waveform(VoskBatchRecognizer *recognizer, const char *data, int length);
/** Set NLSML output
* @param nlsml - boolean value
*/
void vosk_batch_recognizer_set_nlsml(VoskBatchRecognizer *recognizer, int nlsml);
/** Closes the stream */
void vosk_batch_recognizer_finish_stream(VoskBatchRecognizer *recognizer);
/** Return results */
const char *vosk_batch_recognizer_front_result(VoskBatchRecognizer *recognizer);
/** Release and free first retrieved result */
void vosk_batch_recognizer_pop(VoskBatchRecognizer *recognizer);
/** Get amount of pending chunks for more intelligent waiting */
int vosk_batch_recognizer_get_pending_chunks(VoskBatchRecognizer *recognizer);
#ifdef __cplusplus
}
#endif
#endif /* VOSK_API_H */
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -2
View File
@@ -4,7 +4,6 @@
project(RMG-Core)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
@@ -68,7 +67,7 @@ if (PORTABLE_INSTALL)
add_definitions(-DPORTABLE_INSTALL)
endif(PORTABLE_INSTALL)
add_library(RMG-Core STATIC ${RMG_CORE_SOURCES})
add_library(RMG-Core SHARED ${RMG_CORE_SOURCES})
if(UNIX)
target_link_libraries(RMG-Core dl)
@@ -9,6 +9,8 @@
*/
#include "CachedRomHeaderAndSettings.hpp"
#include "Directories.hpp"
#include "RomSettings.hpp"
#include "RomHeader.hpp"
#include "Error.hpp"
#include "osal/osal_files.hpp"
@@ -307,6 +309,53 @@ bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType t
return true;
}
bool CoreUpdateCachedRomHeaderAndSettings(std::filesystem::path file)
{
l_CacheEntry cachedEntry;
CoreRomType type;
CoreRomHeader header;
CoreRomSettings settings;
// try to find existing entry with same filename,
// when not found, do nothing
auto iter = get_cache_entry_iter(file, false);
if (iter == l_CacheEntries.end())
{
return true;
}
cachedEntry = (*iter);
// attempt to retrieve required information
if (!CoreGetRomType(type) ||
!CoreGetCurrentRomHeader(header) ||
!CoreGetCurrentDefaultRomSettings(settings))
{
return false;
}
// check if the cached entry needs to be updated,
// if it does, then update the entry
if (/* rom type */
cachedEntry.type != type ||
/* header */
cachedEntry.header.Name != header.Name ||
cachedEntry.header.Region != header.Region ||
cachedEntry.header.CRC1 != header.CRC1 ||
cachedEntry.header.CRC2 != header.CRC2 ||
/* settings */
cachedEntry.settings.MD5 != settings.MD5 ||
cachedEntry.settings.GoodName != settings.GoodName)
{
(*iter).type = type;
(*iter).header = header;
(*iter).settings.MD5 = settings.MD5;
(*iter).settings.GoodName = settings.GoodName;
l_CacheEntriesChanged = true;
}
return true;
}
bool CoreClearRomHeaderAndSettingsCache(void)
{
l_CacheEntries.clear();
@@ -37,6 +37,12 @@ bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType&
// for given filename succeeds
bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType type, CoreRomHeader header, CoreRomSettings settings);
#ifdef CORE_INTERNAL
// returns whether updating the cached rom header & settings
// for given filename succeeds
bool CoreUpdateCachedRomHeaderAndSettings(std::filesystem::path file);
#endif // CORE_INTERNAL
// returns whether clearing rom header & settings cache
// succeeds
bool CoreClearRomHeaderAndSettingsCache(void);
+29 -8
View File
@@ -22,20 +22,29 @@ static std::function<void(enum CoreDebugMessageType, std::string, std::string)>
static std::function<void(enum CoreStateCallbackType, int)> l_StateCallbackFunc;
static bool l_PrintCallbacks = false;
static bool l_SetupDebugMessageCallback = false;
static std::function<void(void*, int, const char*)> l_DebugMessageCallbackFunc;
static void* l_DebugMessageCallbackFuncContext;
//
// Internal Functions
//
void CoreDebugCallback(void* context, int level, const char* message)
{
std::string contextString((const char*)context);
std::string messageString(message);
if (l_PrintCallbacks)
{
std::cout << contextString << messageString << std::endl;
}
if (!l_SetupCallbacks)
{
return;
}
std::string contextString((const char*)context);
std::string messageString(message);
// convert string encoding accordingly
if (messageString.starts_with("IS64:"))
{
@@ -46,11 +55,6 @@ void CoreDebugCallback(void* context, int level, const char* message)
messageString = CoreConvertStringEncoding(message, CoreStringEncoding::Shift_JIS);
}
if (l_PrintCallbacks)
{
std::cout << contextString << messageString << std::endl;
}
l_DebugCallbackFunc((CoreDebugMessageType)level, contextString, messageString);
}
@@ -81,3 +85,20 @@ void CoreSetPrintDebugCallback(bool enabled)
{
l_PrintCallbacks = enabled;
}
void CoreSetupDebugCallbackMessage(std::function<void(void*, int, const char*)> debugCallbackFunc, void* debugCallbackFuncContext)
{
l_DebugMessageCallbackFunc = debugCallbackFunc;
l_DebugMessageCallbackFuncContext = debugCallbackFuncContext;
l_SetupDebugMessageCallback = true;
}
void CoreDebugCallbackMessage(CoreDebugMessageType type, std::string message)
{
if (!l_SetupDebugMessageCallback)
{
return;
}
l_DebugMessageCallbackFunc(l_DebugMessageCallbackFuncContext, (int)type, message.c_str());
}
+8
View File
@@ -54,4 +54,12 @@ bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::strin
// sets whether the debug callbacks will be printed to stdout
void CoreSetPrintDebugCallback(bool enabled);
#ifdef CORE_PLUGIN
// attempts to setup up the debug message debug callback
void CoreSetupDebugCallbackMessage(std::function<void(void*, int, const char*)> debugCallbackFunc, void* debugCallbackFuncContext);
// sends a debug message to the debug callback (if it exists)
void CoreDebugCallbackMessage(CoreDebugMessageType type, std::string message);
#endif // CORE_PLUGIN
#endif // CORE_CALLBACK_HPP
+14 -1
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;
}
+2 -2
View File
@@ -174,7 +174,7 @@ bool CoreInit(m64p_dynlib_handle handle)
std::string error;
bool ret = false;
ret = m64p::Core.Hook(handle);
ret = m64p::Core.IsHooked() || m64p::Core.Hook(handle);
if (!ret)
{
error = m64p::Core.GetLastError();
@@ -182,7 +182,7 @@ bool CoreInit(m64p_dynlib_handle handle)
return false;
}
ret = m64p::Config.Hook(handle);
ret = m64p::Config.IsHooked() || m64p::Config.Hook(handle);
if (!ret)
{
error = m64p::Config.GetLastError();
+25
View File
@@ -22,6 +22,7 @@
// Local Variables
//
static std::filesystem::path l_LibraryPathOverride;
static std::filesystem::path l_CorePathOverride;
static std::filesystem::path l_PluginPathOverride;
static std::filesystem::path l_SharedDataPathOverride;
@@ -125,6 +126,25 @@ bool CoreCreateDirectories(void)
return true;
}
std::filesystem::path CoreGetLibraryDirectory(void)
{
std::filesystem::path directory;
#ifdef PORTABLE_INSTALL
directory = ".";
#else // Not Portable
if (!l_LibraryPathOverride.empty())
{
directory = l_LibraryPathOverride;
}
else
{
directory = CORE_INSTALL_PREFIX;
directory += "/lib/RMG/";
}
#endif // PORTABLE_INSTALL
return directory;
}
std::filesystem::path CoreGetCoreDirectory(void)
{
std::filesystem::path directory;
@@ -284,6 +304,11 @@ std::filesystem::path CoreGetScreenshotDirectory(void)
}
#ifndef PORTABLE_INSTALL
void CoreSetLibraryPathOverride(std::filesystem::path path)
{
l_LibraryPathOverride = path;
}
void CoreSetCorePathOverride(std::filesystem::path path)
{
l_CorePathOverride = path;
+7
View File
@@ -21,6 +21,10 @@ bool CoreCreateDirectories(void);
// located
std::filesystem::path CoreGetCoreDirectory(void);
// returns the library directory where
// misc libraries should be located
std::filesystem::path CoreGetLibraryDirectory(void);
// returns the plugin directory where
// plugins should be located
std::filesystem::path CoreGetPluginDirectory(void);
@@ -73,6 +77,9 @@ std::filesystem::path CoreGetSaveStateDirectory(void);
// screenshots should be located
std::filesystem::path CoreGetScreenshotDirectory(void);
// changes the library path to the given path
void CoreSetLibraryPathOverride(std::filesystem::path path);
// changes the core path to the given path
void CoreSetCorePathOverride(std::filesystem::path path);
+5 -1
View File
@@ -158,7 +158,6 @@ bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64d
{
error = "CoreStartEmulation m64p::Core.DoCommand(M64CMD_EXECUTE) Failed: ";
error += m64p::Core.ErrorMessage(ret);
CoreSetError(error);
}
CoreClearCheats();
@@ -175,6 +174,11 @@ bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64d
CoreDiscordRpcUpdate(false);
#endif // DISCORD_RPC
// we need to set the emulation error last,
// to prevent the other functions from
// overriding the emulation error
CoreSetError(error);
return ret == M64ERR_SUCCESS;
}
+7
View File
@@ -12,6 +12,13 @@
#include <filesystem>
enum class CoreEmulationState
{
Stopped = 1,
Running,
Paused
};
// starts emulation with given ROM
bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64ddrom);
+1 -2
View File
@@ -16,11 +16,10 @@
#include "RomSettings.hpp"
#include "Settings/Settings.hpp"
#include "m64p/PluginApi.hpp"
#include "osal/osal_dynlib.hpp"
#include "osal/osal_files.hpp"
#include "m64p/PluginApi.cpp"
#include "m64p/PluginApi.hpp"
#include "m64p/Api.hpp"
#include <filesystem>
+24 -1
View File
@@ -7,6 +7,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#define CORE_INTERNAL
#include "Rom.hpp"
#include "Directories.hpp"
#include "Error.hpp"
@@ -15,6 +16,7 @@
#include "RomSettings.hpp"
#include "Cheats.hpp"
#include "osal/osal_files.hpp"
#include "CachedRomHeaderAndSettings.hpp"
// 7-Zip includes
#include "../3rdParty/7-Zip/C/7zTypes.h"
@@ -46,6 +48,7 @@ static bool l_HasRomOpen = false;
static bool l_HasDisk = false;
static bool l_HasExtractedDisk = false;
static std::filesystem::path l_ExtractedDiskPath;
static std::filesystem::path l_RomPath;
//
// Local Functions
@@ -354,7 +357,7 @@ static bool read_7zip_file(std::filesystem::path file, std::filesystem::path* ex
// initialize look reader
lookStream.bufSize = bufSize;
lookStream.realStream = &archiveStream.vt;
LookToRead2_Init(&lookStream);
LookToRead2_INIT(&lookStream);
// initialize CRC table
CrcGenerateTable();
@@ -656,10 +659,14 @@ bool CoreOpenRom(std::filesystem::path file)
if (l_HasRomOpen)
{
// store ROM path
l_RomPath = file;
// store default ROM settings
CoreStoreCurrentDefaultRomSettings();
// apply rom settings overlay
CoreApplyRomSettingsOverlay();
// update cached rom header and settings entry
CoreUpdateCachedRomHeaderAndSettings(file);
}
return l_HasRomOpen;
@@ -686,6 +693,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);
+414 -3
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)
@@ -616,6 +618,18 @@ static l_Setting get_setting(SettingsID settingId)
setting = {SETTING_SECTION_AUDIO, "Synchronize", false};
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::Input_Profiles:
setting = {SETTING_SECTION_INPUT, "Profiles", ""};
break;
@@ -877,6 +891,402 @@ 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_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;
@@ -1269,11 +1679,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());
}
+135
View File
@@ -180,6 +180,9 @@ enum class SettingsID
Audio_Muted,
Audio_Synchronize,
// HLE RSP Plugin Settings
RSP_Fallback,
// Input Plugin Settings
Input_Profiles,
Input_UseProfile,
@@ -268,6 +271,138 @@ 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_Fullscreen_InputType,
Input_Hotkey_Fullscreen_Name,
Input_Hotkey_Fullscreen_Data,
Input_Hotkey_Fullscreen_ExtraData,
Invalid
};
+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,276 @@
/*
* 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->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));
// 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;
}
}
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
@@ -0,0 +1,920 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>HotkeysDialog</class>
<widget class="QDialog" name="HotkeysDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>377</width>
<height>563</height>
</rect>
</property>
<property name="windowTitle">
<string>Hotkeys</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="keybindingsMenuTabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="systemMenuTab">
<attribute name="title">
<string>System</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_72">
<item>
<widget class="QLabel" name="label_69">
<property name="text">
<string>Shutdown</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="shutdownKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_75">
<item>
<widget class="QLabel" name="label_72">
<property name="text">
<string>Soft Reset</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="softResetKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_76">
<item>
<widget class="QLabel" name="label_73">
<property name="text">
<string>Hard Reset</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="hardResetKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_89">
<item>
<widget class="QLabel" name="label_88">
<property name="text">
<string>Pause</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="pauseKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_77">
<item>
<widget class="QLabel" name="label_74">
<property name="text">
<string>Capture Screenshot</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="generateBitmapKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_78">
<item>
<widget class="QLabel" name="label_75">
<property name="text">
<string>Limit FPS</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="limitFPSKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_80">
<item>
<widget class="QLabel" name="label_77">
<property name="text">
<string>Save State</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="saveStateKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_82">
<item>
<widget class="QLabel" name="label_79">
<property name="text">
<string>Load State</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="loadStateKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_85">
<item>
<widget class="QLabel" name="label_82">
<property name="text">
<string>GS Button</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="gsButtonKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_74">
<item>
<widget class="QLabel" name="label_71">
<property name="text">
<string>Exit</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="exitKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_14">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="verticalLayout_0">
<item>
<widget class="QLabel" name="infoIconLabel">
<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_86">
<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>These hotkeys are only for controllers</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="speedFactorTab">
<attribute name="title">
<string>Speed Factor</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<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="UserInterface::Widget::HotkeyButton" 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="UserInterface::Widget::HotkeyButton" 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="UserInterface::Widget::HotkeyButton" 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="UserInterface::Widget::HotkeyButton" 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="UserInterface::Widget::HotkeyButton" 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="UserInterface::Widget::HotkeyButton" 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="UserInterface::Widget::HotkeyButton" 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="UserInterface::Widget::HotkeyButton" 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="UserInterface::Widget::HotkeyButton" 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="UserInterface::Widget::HotkeyButton" 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="UserInterface::Widget::HotkeyButton" 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="UserInterface::Widget::HotkeyButton" 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>
<item>
<layout class="QHBoxLayout" name="verticalLayout_1">
<item>
<widget class="QLabel" name="infoIconLabel_2">
<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_87">
<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>These hotkeys are only for controllers</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="currentSaveStateTab">
<attribute name="title">
<string>Current Save State</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_95">
<item>
<widget class="QLabel" name="label_92">
<property name="text">
<string>Slot 0</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="saveState0KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_96">
<item>
<widget class="QLabel" name="label_93">
<property name="text">
<string>Slot 1</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="saveState1KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_97">
<item>
<widget class="QLabel" name="label_94">
<property name="text">
<string>Slot 2</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="saveState2KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_98">
<item>
<widget class="QLabel" name="label_95">
<property name="text">
<string>Slot 3</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="saveState3KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_99">
<item>
<widget class="QLabel" name="label_96">
<property name="text">
<string>Slot 4</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="saveState4KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_100">
<item>
<widget class="QLabel" name="label_97">
<property name="text">
<string>Slot 5</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="saveState5KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_101">
<item>
<widget class="QLabel" name="label_98">
<property name="text">
<string>Slot 6</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="saveState6KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_102">
<item>
<widget class="QLabel" name="label_99">
<property name="text">
<string>Slot 7</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="saveState7KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_104">
<item>
<widget class="QLabel" name="label_101">
<property name="text">
<string>Slot 8</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="saveState8KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_103">
<item>
<widget class="QLabel" name="label_100">
<property name="text">
<string>Slot 9</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="saveState9KeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_13">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="infoIconLabel_3">
<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_89">
<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>These hotkeys are only for controllers</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="viewMenuTab">
<attribute name="title">
<string>View</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_86">
<item>
<widget class="QLabel" name="label_83">
<property name="text">
<string>Full Screen</string>
</property>
</widget>
</item>
<item>
<widget class="UserInterface::Widget::HotkeyButton" name="fullscreenKeyButton">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_16">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>419</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="verticalLayout_6">
<item>
<widget class="QLabel" name="infoIconLabel_4">
<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_90">
<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>These hotkeys are only for controllers</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>UserInterface::Widget::HotkeyButton</class>
<extends>QPushButton</extends>
<header>UserInterface/Widget/HotkeyButton.hpp</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>HotkeysDialog</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>HotkeysDialog</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>
+12 -3
View File
@@ -59,9 +59,18 @@ MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread, bool romCo
// always add keyboard device
for (auto& controllerWidget : this->controllerWidgets)
{
controllerWidget->AddInputDevice("None", (int)InputDeviceType::None);
controllerWidget->AddInputDevice("Automatic", (int)InputDeviceType::Automatic);
controllerWidget->AddInputDevice("Keyboard", (int)InputDeviceType::Keyboard);
#ifdef VRU
// both games which support the VRU,
// require the VRU to be in port #4,
// so we only have to expose it there
if (controllerWidget == this->controllerWidgets.last())
{
controllerWidget->AddInputDevice("Voice Recognition Unit", (int)InputDeviceType::EmulateVRU);
}
#endif // VRU
controllerWidget->AddInputDevice("None", (int)InputDeviceType::None);
controllerWidget->AddInputDevice("Automatic", (int)InputDeviceType::Automatic);
controllerWidget->AddInputDevice("Keyboard", (int)InputDeviceType::Keyboard);
controllerWidget->SetInitialized(true);
}
@@ -33,11 +33,6 @@ OptionsDialog::OptionsDialog(QWidget* parent, OptionsDialogSettings settings) :
}
}
bool OptionsDialog::HasSaved()
{
return this->hasSaved;
}
OptionsDialogSettings OptionsDialog::GetSettings()
{
return this->settings;
@@ -72,24 +67,16 @@ void OptionsDialog::hideEmulationInfoText(void)
}
}
void OptionsDialog::on_buttonBox_clicked(QAbstractButton *button)
void OptionsDialog::accept()
{
this->settings.ControllerPak = this->controllerPakComboBox->currentIndex();
this->settings.GameboyRom = this->gameboyRomLineEdit->text().toStdString();
this->settings.GameboySave = this->gameboySaveLineEdit->text().toStdString();
this->settings.RemoveDuplicateMappings = this->removeDuplicateMappingsCheckbox->isChecked();
this->settings.FilterEventsForButtons = this->filterEventsForButtonsCheckBox->isChecked();
this->settings.FilterEventsForAxis = this->filterEventsForAxisCheckBox->isChecked();
QPushButton *pushButton = (QPushButton *)button;
QPushButton *okButton = this->buttonBox->button(QDialogButtonBox::Ok);
if (pushButton == okButton)
{
this->hasSaved = true;
this->settings.ControllerPak = this->controllerPakComboBox->currentIndex();
this->settings.GameboyRom = this->gameboyRomLineEdit->text().toStdString();
this->settings.GameboySave = this->gameboySaveLineEdit->text().toStdString();
this->settings.RemoveDuplicateMappings = this->removeDuplicateMappingsCheckbox->isChecked();
this->settings.FilterEventsForButtons = this->filterEventsForButtonsCheckBox->isChecked();
this->settings.FilterEventsForAxis = this->filterEventsForAxisCheckBox->isChecked();
}
this->accept();
QDialog::accept();
}
void OptionsDialog::on_changeGameboyRomButton_clicked()
@@ -37,19 +37,17 @@ Q_OBJECT
public:
OptionsDialog(QWidget *parent, OptionsDialogSettings settings);
bool HasSaved();
OptionsDialogSettings GetSettings();
protected:
void accept() Q_DECL_OVERRIDE;
private:
bool hasSaved = false;
OptionsDialogSettings settings;
void setIconsForEmulationInfoText(void);
void hideEmulationInfoText(void);
private slots:
void on_buttonBox_clicked(QAbstractButton *);
void on_changeGameboyRomButton_clicked();
void on_changeGameboySaveButton_clicked();
};
@@ -248,5 +248,38 @@
<resources>
<include location="UIResources.qrc"/>
</resources>
<connections/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>OptionsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>OptionsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -92,6 +92,43 @@ 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(
{
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_Shutdown_InputType, SettingsID::Input_Hotkey_Shutdown_Name, SettingsID::Input_Hotkey_Shutdown_Data, SettingsID::Input_Hotkey_Shutdown_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_Exit_InputType, SettingsID::Input_Hotkey_Exit_Name, SettingsID::Input_Hotkey_Exit_Data, SettingsID::Input_Hotkey_Exit_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SoftReset_InputType, SettingsID::Input_Hotkey_SoftReset_Name, SettingsID::Input_Hotkey_SoftReset_Data, SettingsID::Input_Hotkey_SoftReset_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_HardReset_InputType, SettingsID::Input_Hotkey_HardReset_Name, SettingsID::Input_Hotkey_HardReset_Data, SettingsID::Input_Hotkey_HardReset_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_Resume_InputType, SettingsID::Input_Hotkey_Resume_Name, SettingsID::Input_Hotkey_Resume_Data, SettingsID::Input_Hotkey_Resume_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_Screenshot_InputType, SettingsID::Input_Hotkey_Screenshot_Name, SettingsID::Input_Hotkey_Screenshot_Data, SettingsID::Input_Hotkey_Screenshot_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_LimitFPS_InputType, SettingsID::Input_Hotkey_LimitFPS_Name, SettingsID::Input_Hotkey_LimitFPS_Data, SettingsID::Input_Hotkey_LimitFPS_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SpeedFactor25_InputType, SettingsID::Input_Hotkey_SpeedFactor25_Name, SettingsID::Input_Hotkey_SpeedFactor25_Data, SettingsID::Input_Hotkey_SpeedFactor25_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SpeedFactor50_InputType, SettingsID::Input_Hotkey_SpeedFactor50_Name, SettingsID::Input_Hotkey_SpeedFactor50_Data, SettingsID::Input_Hotkey_SpeedFactor50_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SpeedFactor75_InputType, SettingsID::Input_Hotkey_SpeedFactor75_Name, SettingsID::Input_Hotkey_SpeedFactor75_Data, SettingsID::Input_Hotkey_SpeedFactor75_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SpeedFactor100_InputType, SettingsID::Input_Hotkey_SpeedFactor100_Name, SettingsID::Input_Hotkey_SpeedFactor100_Data, SettingsID::Input_Hotkey_SpeedFactor100_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SpeedFactor125_InputType, SettingsID::Input_Hotkey_SpeedFactor125_Name, SettingsID::Input_Hotkey_SpeedFactor125_Data, SettingsID::Input_Hotkey_SpeedFactor125_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SpeedFactor150_InputType, SettingsID::Input_Hotkey_SpeedFactor150_Name, SettingsID::Input_Hotkey_SpeedFactor150_Data, SettingsID::Input_Hotkey_SpeedFactor150_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SpeedFactor175_InputType, SettingsID::Input_Hotkey_SpeedFactor175_Name, SettingsID::Input_Hotkey_SpeedFactor175_Data, SettingsID::Input_Hotkey_SpeedFactor175_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SpeedFactor200_InputType, SettingsID::Input_Hotkey_SpeedFactor200_Name, SettingsID::Input_Hotkey_SpeedFactor200_Data, SettingsID::Input_Hotkey_SpeedFactor200_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SpeedFactor225_InputType, SettingsID::Input_Hotkey_SpeedFactor225_Name, SettingsID::Input_Hotkey_SpeedFactor225_Data, SettingsID::Input_Hotkey_SpeedFactor225_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SpeedFactor250_InputType, SettingsID::Input_Hotkey_SpeedFactor250_Name, SettingsID::Input_Hotkey_SpeedFactor250_Data, SettingsID::Input_Hotkey_SpeedFactor250_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SpeedFactor275_InputType, SettingsID::Input_Hotkey_SpeedFactor275_Name, SettingsID::Input_Hotkey_SpeedFactor275_Data, SettingsID::Input_Hotkey_SpeedFactor275_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SpeedFactor300_InputType, SettingsID::Input_Hotkey_SpeedFactor300_Name, SettingsID::Input_Hotkey_SpeedFactor300_Data, SettingsID::Input_Hotkey_SpeedFactor300_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SaveState_InputType, SettingsID::Input_Hotkey_SaveState_Name, SettingsID::Input_Hotkey_SaveState_Data, SettingsID::Input_Hotkey_SaveState_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_LoadState_InputType, SettingsID::Input_Hotkey_LoadState_Name, SettingsID::Input_Hotkey_LoadState_Data, SettingsID::Input_Hotkey_LoadState_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_GSButton_InputType, SettingsID::Input_Hotkey_GSButton_Name, SettingsID::Input_Hotkey_GSButton_Data, SettingsID::Input_Hotkey_GSButton_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SaveStateSlot0_InputType, SettingsID::Input_Hotkey_SaveStateSlot0_Name, SettingsID::Input_Hotkey_SaveStateSlot0_Data, SettingsID::Input_Hotkey_SaveStateSlot0_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SaveStateSlot1_InputType, SettingsID::Input_Hotkey_SaveStateSlot1_Name, SettingsID::Input_Hotkey_SaveStateSlot1_Data, SettingsID::Input_Hotkey_SaveStateSlot1_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SaveStateSlot2_InputType, SettingsID::Input_Hotkey_SaveStateSlot2_Name, SettingsID::Input_Hotkey_SaveStateSlot2_Data, SettingsID::Input_Hotkey_SaveStateSlot2_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SaveStateSlot3_InputType, SettingsID::Input_Hotkey_SaveStateSlot3_Name, SettingsID::Input_Hotkey_SaveStateSlot3_Data, SettingsID::Input_Hotkey_SaveStateSlot3_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SaveStateSlot4_InputType, SettingsID::Input_Hotkey_SaveStateSlot4_Name, SettingsID::Input_Hotkey_SaveStateSlot4_Data, SettingsID::Input_Hotkey_SaveStateSlot4_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SaveStateSlot5_InputType, SettingsID::Input_Hotkey_SaveStateSlot5_Name, SettingsID::Input_Hotkey_SaveStateSlot5_Data, SettingsID::Input_Hotkey_SaveStateSlot5_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SaveStateSlot6_InputType, SettingsID::Input_Hotkey_SaveStateSlot6_Name, SettingsID::Input_Hotkey_SaveStateSlot6_Data, SettingsID::Input_Hotkey_SaveStateSlot6_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SaveStateSlot7_InputType, SettingsID::Input_Hotkey_SaveStateSlot7_Name, SettingsID::Input_Hotkey_SaveStateSlot7_Data, SettingsID::Input_Hotkey_SaveStateSlot7_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SaveStateSlot8_InputType, SettingsID::Input_Hotkey_SaveStateSlot8_Name, SettingsID::Input_Hotkey_SaveStateSlot8_Data, SettingsID::Input_Hotkey_SaveStateSlot8_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), SettingsID::Input_Hotkey_SaveStateSlot9_InputType, SettingsID::Input_Hotkey_SaveStateSlot9_Name, SettingsID::Input_Hotkey_SaveStateSlot9_Data, SettingsID::Input_Hotkey_SaveStateSlot9_ExtraData },
{ std::vector<int>(), std::vector<int>(), std::vector<int>(), std::vector<std::string>(), 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 +233,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 +293,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 +305,6 @@ void ControllerWidget::removeDuplicates(MappingButton* button)
continue;
}
std::vector<int> inputType;
std::vector<int> inputData;
std::vector<int> extraInputData;
inputType = button->GetInputType();
inputData = button->GetInputData();
extraInputData = button->GetExtraInputData();
for (int i = 0; i < inputType.size(); i++)
{
if (buttonWidget->HasInputData((InputType)inputType.at(i), inputData.at(i), extraInputData.at(i)))
@@ -344,7 +378,8 @@ void ControllerWidget::setPluggedIn(bool value)
this->deadZoneGroupBox,
this->deadZoneSlider,
this->optionsButton,
this->resetButton
this->resetButton,
this->hotkeysButton,
};
for (auto& widget : widgetList)
@@ -623,7 +658,8 @@ void ControllerWidget::on_inputDeviceComboBox_currentIndexChanged(int value)
}
// set plugged in state
this->setPluggedIn(deviceNum != (int)InputDeviceType::None);
this->setPluggedIn(deviceNum != (int)InputDeviceType::None &&
deviceNum != (int)InputDeviceType::EmulateVRU);
emit this->CurrentInputDeviceChanged(this, deviceName, deviceNum);
}
@@ -775,15 +811,39 @@ void ControllerWidget::on_resetButton_clicked()
void ControllerWidget::on_optionsButton_clicked()
{
OptionsDialog dialog(this, this->optionsDialogSettings);
dialog.exec();
int ret = dialog.exec();
// when saved, store settings for later
if (dialog.HasSaved())
if (ret == QDialog::Accepted)
{
this->optionsDialogSettings = dialog.GetSettings();
}
}
void ControllerWidget::on_hotkeysButton_clicked()
{
HotkeysDialog dialog(this, this->hotkeySettingMappings,
this->isCurrentJoystickGameController,
this->currentJoystickId,
this->optionsDialogSettings.FilterEventsForButtons,
this->optionsDialogSettings.RemoveDuplicateMappings);
// clear our UI state
this->controllerImageWidget->ClearControllerState();
this->currentHotkeysDialog = &dialog;
int ret = dialog.exec();
this->currentHotkeysDialog = nullptr;
// when saved, store settings for later
if (ret == QDialog::Accepted)
{
this->hotkeySettingMappings = dialog.GetSettingMappings();
}
}
void ControllerWidget::on_MappingButton_Released(MappingButton* button)
{
if (this->currentButton != nullptr)
@@ -795,7 +855,7 @@ void ControllerWidget::on_MappingButton_Released(MappingButton* button)
this->currentButton = button;
button->SaveState();
button->StartTimer();
this->disableAllChildren();
}
@@ -833,6 +893,13 @@ void ControllerWidget::on_MappingButton_DataSet(MappingButton* button)
void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
{
// pass to hotkeys dialog when it's active
if (this->currentHotkeysDialog != nullptr)
{
this->currentHotkeysDialog->on_MainDialog_SdlEvent(event);
return;
}
switch (event->type)
{
case SDL_CONTROLLERBUTTONDOWN:
@@ -1390,6 +1457,14 @@ void ControllerWidget::LoadSettings(QString sectionQString, bool loadUserProfile
}
}
for (auto& hotkeySetting : this->hotkeySettingMappings)
{
hotkeySetting.inputTypes = CoreSettingsGetIntListValue(hotkeySetting.inputTypeSettingsId, section);
hotkeySetting.inputText = CoreSettingsGetStringListValue(hotkeySetting.nameSettingsId, section);
hotkeySetting.inputData = CoreSettingsGetIntListValue(hotkeySetting.dataSettingsId, section);
hotkeySetting.extraInputData = CoreSettingsGetIntListValue(hotkeySetting.extraDataSettingsId, section);
}
// force refresh some UI elements
this->CheckInputDeviceSettings();
this->on_deadZoneSlider_valueChanged(this->deadZoneSlider->value());
@@ -1529,6 +1604,14 @@ void ControllerWidget::SaveSettings(QString section)
CoreSettingsSetValue(buttonSetting.dataSettingsId, sectionStr, buttonSetting.button->GetInputData());
CoreSettingsSetValue(buttonSetting.extraDataSettingsId, sectionStr, buttonSetting.button->GetExtraInputData());
}
for (auto& hotkeySetting : this->hotkeySettingMappings)
{
CoreSettingsSetValue(hotkeySetting.inputTypeSettingsId, sectionStr, hotkeySetting.inputTypes);
CoreSettingsSetValue(hotkeySetting.nameSettingsId, sectionStr, hotkeySetting.inputText);
CoreSettingsSetValue(hotkeySetting.dataSettingsId, sectionStr, hotkeySetting.inputData);
CoreSettingsSetValue(hotkeySetting.extraDataSettingsId, sectionStr, hotkeySetting.extraInputData);
}
}
void ControllerWidget::RevertSettings()
@@ -15,6 +15,7 @@
#include "UserInterface/EventFilter.hpp"
#include "UserInterface/OptionsDialog.hpp"
#include "UserInterface/HotkeysDialog.hpp"
using namespace UserInterface::Widget;
@@ -72,6 +73,7 @@ private:
QList<buttonWidgetMapping> buttonWidgetMappings;
QList<axisWidgetMapping> joystickWidgetMappings;
QList<buttonSettingMapping> buttonSettingMappings;
QList<HotkeySettingMapping> hotkeySettingMappings;
QList<MappingButton*> setupButtonWidgets;
void initializeMappingButtons();
@@ -106,6 +108,8 @@ private:
bool onlyLoadGameProfile = false;
HotkeysDialog* currentHotkeysDialog = nullptr;
public:
ControllerWidget(QWidget* parent, EventFilter* eventFilter);
~ControllerWidget();
@@ -156,6 +160,7 @@ private slots:
void on_resetButton_clicked();
void on_optionsButton_clicked();
void on_hotkeysButton_clicked();
public slots:
void on_MappingButton_Released(MappingButton* button);
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>1239</width>
<height>562</height>
<height>601</height>
</rect>
</property>
<property name="sizePolicy">
@@ -1254,6 +1254,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="hotkeysButton">
<property name="text">
<string>Hotkeys</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
@@ -0,0 +1,221 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "HotkeyButton.hpp"
#include "UserInterface/HotkeysDialog.hpp"
#include <QMouseEvent>
using namespace UserInterface::Widget;
HotkeyButton::HotkeyButton(QWidget* parent) : QPushButton(parent)
{
this->countDownTimer = new QTimer(this);
connect(this->countDownTimer, &QTimer::timeout, this, &HotkeyButton::on_countDownTimer_triggered);
this->initialSize = this->size();
}
HotkeyButton::~HotkeyButton()
{
}
void HotkeyButton::Initialize(HotkeysDialog* dialog)
{
this->hotkeysDialog = dialog;
connect(this, &QPushButton::released, [=]
{
emit this->hotkeysDialog->on_HotkeyButton_Released(this);
});
this->setText(" ");
}
void HotkeyButton::Clear()
{
this->inputData.clear();
this->savedInputData.clear();
this->setText("");
}
void HotkeyButton::StartTimer()
{
// clear current state
this->inputData.clear();
this->currentCountDownNum = 5;
this->on_countDownTimer_triggered();
this->countDownTimer->start(1000);
}
void HotkeyButton::StopTimer()
{
this->countDownTimer->stop();
}
void HotkeyButton::AddInputData(enum InputType type, int value, int extraValue, QString name)
{
// don't add stub
if (name.simplified().isEmpty())
{
return;
}
if (!this->HasInputData(type, value, extraValue))
{
this->inputData.push_back(
{
type,
value,
extraValue,
name
}
);
}
}
bool HotkeyButton::HasInputData(enum InputType type, int value, int extraValue)
{
return this->getInputDataIter(type, value, extraValue) != this->inputData.end();
}
std::vector<int> HotkeyButton::GetInputType()
{
std::vector<int> inputTypeList;
for (const auto& data : this->inputData)
{
inputTypeList.push_back((int)data.Type);
}
return inputTypeList;
}
std::vector<int> HotkeyButton::GetInputData()
{
std::vector<int> inputDataList;
for (const auto& data : this->inputData)
{
inputDataList.push_back(data.Data);
}
return inputDataList;
}
std::vector<int> HotkeyButton::GetExtraInputData()
{
std::vector<int> extraInputDataList;
for (const auto& data : this->inputData)
{
extraInputDataList.push_back(data.ExtraData);
}
return extraInputDataList;
}
std::vector<std::string> HotkeyButton::GetInputText()
{
std::vector<std::string> inputTextList;
for (const auto& data : this->inputData)
{
inputTextList.push_back(data.Text.toStdString());
}
return inputTextList;
}
void HotkeyButton::SaveState()
{
this->savedInputData = this->inputData;
}
void HotkeyButton::RestoreState()
{
this->inputData = this->savedInputData;
this->reloadText();
}
void HotkeyButton::FinishState()
{
this->reloadText();
emit this->hotkeysDialog->on_HotkeyButton_StateFinished(this);
}
void HotkeyButton::mousePressEvent(QMouseEvent* event)
{
if (event->button() == Qt::RightButton)
{
this->Clear();
return;
}
QPushButton::mousePressEvent(event);
}
void HotkeyButton::on_countDownTimer_triggered()
{
this->setText(QString::number(this->currentCountDownNum));
if (this->currentCountDownNum == 0)
{
this->setText("");
this->currentCountDownNum = 5;
this->countDownTimer->stop();
emit this->hotkeysDialog->on_HotkeyButton_TimerFinished(this);
}
this->currentCountDownNum--;
}
void HotkeyButton::reloadText()
{
QString text;
QFontMetrics fontMetrics(this->font());
int size = this->inputData.size();
for (int i = 0; i < size; i++)
{
text += this->inputData.at(i).Text;
// only add comma when
// not at the last item
if (i < (size - 1))
{
text += "+";
}
}
QString elidedText = fontMetrics.elidedText(text, Qt::ElideRight, this->initialSize.width());
// needed for spacing
if (elidedText.isEmpty())
{
elidedText = " ";
}
this->setToolTip(text);
this->setText(elidedText);
}
std::vector<HotkeyButtonInputDataType>::iterator HotkeyButton::getInputDataIter(InputType type, int value, int extraValue)
{
auto predicate = [type, value, extraValue](const auto& entry)
{
return entry.Type == type &&
(value == -1 || entry.Data == value) &&
(extraValue == -1 || entry.ExtraData == extraValue);
};
return std::find_if(this->inputData.begin(), this->inputData.end(), predicate);
}
@@ -0,0 +1,86 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef HOTKEYBUTTON_HPP
#define HOTKEYBUTTON_HPP
#include <QPushButton>
#include <QTimer>
#include "common.hpp"
namespace UserInterface
{
// we can't include HotkeysDialog.hpp
// because that header includes this header,
// so forward-declare it to prevent issues
class HotkeysDialog;
namespace Widget
{
struct HotkeyButtonInputDataType
{
InputType Type;
int Data;
int ExtraData;
QString Text;
};
class HotkeyButton : public QPushButton
{
private:
QSize initialSize;
QTimer* countDownTimer = nullptr;
HotkeysDialog* hotkeysDialog = nullptr;
int currentCountDownNum = 0;
std::vector<HotkeyButtonInputDataType> inputData;
std::vector<HotkeyButtonInputDataType> savedInputData;
void reloadText();
std::vector<HotkeyButtonInputDataType>::iterator getInputDataIter(InputType type, int value, int extraValue);
public:
HotkeyButton(QWidget* parent);
~HotkeyButton();
void Initialize(HotkeysDialog* dialog);
void Clear();
void StartTimer();
void StopTimer();
void AddInputData(InputType type, int value, int extraValue, QString name);
bool HasInputData(InputType type, int value = -1, int extraValue = -1);
std::vector<int> GetInputType();
std::vector<int> GetInputData();
std::vector<int> GetExtraInputData();
std::vector<std::string> GetInputText();
void SaveState();
void RestoreState();
void FinishState();
protected:
void mousePressEvent(QMouseEvent* event);
private slots:
void on_countDownTimer_triggered();
};
}
}
#endif // HOTKEYBUTTON_HPP
+603
View File
@@ -0,0 +1,603 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#define CORE_PLUGIN
#define M64P_PLUGIN_PROTOTYPES 1
#include <RMG-Core/Core.hpp>
#include <RMG-Core/osal/osal_dynlib.hpp>
#include <../3rdParty/vosk-api/include/vosk_api.h>
#include <iostream>
#include <QByteArray>
#include <QStringDecoder>
#include <QStringList>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <SDL.h>
#include "VRU.hpp"
#include "VRUwords.hpp"
//
// Local Enums
//
enum Language
{
English = 0,
JapaneseOrDemo = 1
};
//
// Local Variables
//
// vosk-api library variables
//
typedef VoskModel* (*ptr_vosk_model_new)(const char *);
typedef void (*ptr_vosk_model_free)(VoskModel *);
typedef VoskRecognizer* (*ptr_vosk_recognizer_new_grm)(VoskModel *, float, const char *);
typedef void (*ptr_vosk_recognizer_free)(VoskRecognizer *);
typedef int (*ptr_vosk_recognizer_accept_waveform)(VoskRecognizer *, const char *, int );
typedef const char * (*ptr_vosk_recognizer_final_result)(VoskRecognizer *);
typedef void (*ptr_vosk_set_log_level)(int);
typedef void (*ptr_vosk_recognizer_set_max_alternatives)(VoskRecognizer *, int);
static ptr_vosk_model_new l_vosk_model_new = nullptr;
static ptr_vosk_model_free l_vosk_model_free = nullptr;
static ptr_vosk_recognizer_new_grm l_vosk_recognizer_new_grm = nullptr;
static ptr_vosk_recognizer_free l_vosk_recognizer_free = nullptr;
static ptr_vosk_recognizer_accept_waveform l_vosk_recognizer_accept_waveform = nullptr;
static ptr_vosk_recognizer_final_result l_vosk_recognizer_final_result = nullptr;
static ptr_vosk_set_log_level l_vosk_set_log_level = nullptr;
static ptr_vosk_recognizer_set_max_alternatives l_vosk_recognizer_set_max_alternatives = nullptr;
static osal_dynlib_lib_handle l_VoskLibHandle = nullptr;
static VoskModel* l_VoskModel = nullptr;
static VoskRecognizer* l_VoskRecognizer = nullptr;
// VRU implementation variables
//
static bool l_Initialized = false;
static std::vector<VRUWordEntry> l_WordEntries;
static int l_MicState = 0;
static int l_WordListSize = 0;
static int l_WordListCount = 0;
static QStringList l_RegisteredWords;
static QList<int> l_RegisteredWordsIndex;
static SDL_AudioDeviceID l_AudioDevice = 0;
static SDL_AudioSpec l_AudioDeviceSpec;
//
// Local Functions
//
static bool hook_vosk(void)
{
std::string debugMessage;
std::filesystem::path voskApiPath;
voskApiPath = CoreGetLibraryDirectory();
voskApiPath += "/libvosk" OSAL_DYNLIB_LIB_EXT_STR;
l_VoskLibHandle = osal_dynlib_open(voskApiPath);
if (l_VoskLibHandle == nullptr)
{
debugMessage = "VRU: Failed to open library \"";
debugMessage += voskApiPath.string().c_str();
debugMessage += "\": ";
debugMessage += osal_dynlib_strerror();
CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage);
return false;
}
l_vosk_model_new = (ptr_vosk_model_new) osal_dynlib_sym(l_VoskLibHandle, "vosk_model_new");
l_vosk_model_free = (ptr_vosk_model_free) osal_dynlib_sym(l_VoskLibHandle, "vosk_model_free");
l_vosk_recognizer_new_grm = (ptr_vosk_recognizer_new_grm) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_new_grm");
l_vosk_recognizer_free = (ptr_vosk_recognizer_free) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_free");
l_vosk_recognizer_accept_waveform = (ptr_vosk_recognizer_accept_waveform) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_accept_waveform");
l_vosk_recognizer_final_result = (ptr_vosk_recognizer_final_result) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_final_result");
l_vosk_set_log_level = (ptr_vosk_set_log_level) osal_dynlib_sym(l_VoskLibHandle, "vosk_set_log_level");
l_vosk_recognizer_set_max_alternatives = (ptr_vosk_recognizer_set_max_alternatives) osal_dynlib_sym(l_VoskLibHandle, "vosk_recognizer_set_max_alternatives");
if (l_vosk_model_new == nullptr ||
l_vosk_model_free == nullptr ||
l_vosk_recognizer_new_grm == nullptr ||
l_vosk_recognizer_free == nullptr ||
l_vosk_recognizer_accept_waveform == nullptr ||
l_vosk_recognizer_final_result == nullptr ||
l_vosk_set_log_level == nullptr ||
l_vosk_recognizer_set_max_alternatives == nullptr)
{
debugMessage = "VRU: Failed to open library: missing functions";
CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage);
return false;
}
return true;
}
static void unhook_vosk(void)
{
l_vosk_model_new = nullptr;
l_vosk_model_free = nullptr;
l_vosk_recognizer_new_grm = nullptr;
l_vosk_recognizer_free = nullptr;
l_vosk_recognizer_accept_waveform = nullptr;
l_vosk_recognizer_final_result = nullptr;
l_vosk_set_log_level = nullptr;
l_vosk_recognizer_set_max_alternatives = nullptr;
osal_dynlib_close(l_VoskLibHandle);
}
static bool setup_vosk_model(void)
{
std::string debugMessage;
std::filesystem::path voskModelPath;
voskModelPath = CoreGetSharedDataDirectory();
voskModelPath += "/vosk-model-small-en-us-0.15.zip";
bool missingModelFile = false;
std::filesystem::path voskModelFiles[] =
{
"vosk-model-small-en-us-0.15/am/final.mdl",
"vosk-model-small-en-us-0.15/conf/mfcc.conf",
"vosk-model-small-en-us-0.15/conf/model.conf",
"vosk-model-small-en-us-0.15/graph/disambig_tid.int",
"vosk-model-small-en-us-0.15/graph/Gr.fst",
"vosk-model-small-en-us-0.15/graph/HCLr.fst",
"vosk-model-small-en-us-0.15/graph/phones/word_boundary.int",
"vosk-model-small-en-us-0.15/ivector/final.dubm",
"vosk-model-small-en-us-0.15/ivector/final.ie",
"vosk-model-small-en-us-0.15/ivector/final.mat",
"vosk-model-small-en-us-0.15/ivector/global_cmvn.stats",
"vosk-model-small-en-us-0.15/ivector/online_cmvn.conf",
"vosk-model-small-en-us-0.15/ivector/splice.conf",
};
for (std::filesystem::path& file : voskModelFiles)
{
std::filesystem::path fullFilePath;
fullFilePath = CoreGetUserDataDirectory();
fullFilePath += "/";
fullFilePath += file;
if (!std::filesystem::exists(fullFilePath))
{
missingModelFile = true;
break;
}
}
// all required files exist,
// so we don't need to extract the zip again
if (!missingModelFile)
{
return true;
}
if (!std::filesystem::is_regular_file(voskModelPath))
{
debugMessage = "VRU: vosk model file \"";
debugMessage += voskModelPath.string().c_str();
debugMessage += "\" doesn't exist!";
CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage);
return false;
}
if (!CoreUnzip(voskModelPath, CoreGetUserDataDirectory()))
{
debugMessage = "VRU: Failed to extract vosk model file \"";
debugMessage += voskModelPath.string().c_str();
debugMessage += "\": ";
debugMessage += CoreGetError();
CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage);
return false;
}
return true;
}
static bool init_vosk(void)
{
std::filesystem::path voskModelPath;
voskModelPath = CoreGetUserDataDirectory();
voskModelPath += "/vosk-model-small-en-us-0.15";
l_vosk_set_log_level(-1);
l_VoskModel = l_vosk_model_new(voskModelPath.string().c_str());
if (l_VoskModel == nullptr)
{
CoreDebugCallbackMessage(CoreDebugMessageType::Error, "VRU: vosk_model_new failed");
return false;
}
return true;
}
static void quit_vosk(void)
{
if (l_VoskModel != nullptr)
{
l_vosk_model_free(l_VoskModel);
l_VoskModel = nullptr;
}
if (l_VoskRecognizer != nullptr)
{
l_vosk_recognizer_free(l_VoskRecognizer);
l_VoskRecognizer = nullptr;
}
}
static bool init_mic(void)
{
std::string debugMessage;
SDL_AudioSpec desiredAudioSpec;
desiredAudioSpec.freq = 44100;
desiredAudioSpec.format = AUDIO_S16SYS;
desiredAudioSpec.channels = 1;
desiredAudioSpec.samples = 1024;
desiredAudioSpec.callback = nullptr;
desiredAudioSpec.userdata = nullptr;
l_AudioDevice = SDL_OpenAudioDevice(nullptr, 1, &desiredAudioSpec, &l_AudioDeviceSpec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
if (l_AudioDevice == 0)
{
debugMessage = "VRU: SDL_OpenAudioDevice Failed: ";
debugMessage += SDL_GetError();
CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage);
return false;
}
return true;
}
static void quit_mic(void)
{
if (l_AudioDevice != 0)
{
SDL_CloseAudioDevice(l_AudioDevice);
}
}
static QByteArray words_to_byte_array(uint16_t* words, uint16_t size)
{
QByteArray byte_array;
uint8_t* bytes = (uint8_t*)words;
for (int i = 0; i < (size * 2); i += 2)
{
byte_array.push_back(bytes[i + 1]);
byte_array.push_back(bytes[i]);
}
return byte_array;
}
static bool find_word_from_hex(std::string hex, std::string& word)
{
auto predicate = [hex](const VRUWordEntry& entry)
{
return entry.hex == hex;
};
auto iter = std::find_if(l_WordEntries.begin(), l_WordEntries.end(), predicate);
if (iter != l_WordEntries.end())
{
word = (*iter).words;
}
return iter != l_WordEntries.end();
}
//
// Exported Functions
//
bool InitVRU(void)
{
if (l_Initialized)
{
return true;
}
if (!hook_vosk())
{
return false;
}
if (!setup_vosk_model())
{
return false;
}
if (!init_vosk())
{
return false;
}
if (!init_mic())
{
return false;
}
l_MicState = 0;
if (l_WordEntries.empty())
{
l_WordEntries = GetVRUWordEntries();
}
l_Initialized = true;
return true;
}
bool IsVRUInit(void)
{
return l_Initialized;
}
bool QuitVRU(void)
{
if (!l_Initialized)
{
return false;
}
quit_mic();
quit_vosk();
unhook_vosk();
l_Initialized = false;
return true;
}
int GetVRUMicState(void)
{
return l_MicState;
}
//
// VRU Plugin Functions
//
EXPORT void CALL SendVRUWord(uint16_t length, uint16_t* word, uint8_t lang)
{
if (!l_Initialized)
{
return;
}
QByteArray byte_array = words_to_byte_array(word, length);
std::string debugMessage;
std::string word_str;
if (find_word_from_hex(byte_array.toHex().toUpper().toStdString(), word_str))
{ // found word
l_RegisteredWords.append(QString::fromStdString(word_str));
l_RegisteredWordsIndex.append(l_WordListCount);
}
else
{ // not found
QStringDecoder utf8_decoder = QStringDecoder(QStringDecoder::Utf8);
QString encoded_string = utf8_decoder.decode(byte_array);
if (utf8_decoder.hasError())
{
debugMessage = "VRU: unknown word: ";
debugMessage += encoded_string.toStdString();
CoreDebugCallbackMessage(CoreDebugMessageType::Error, debugMessage);
}
else
{
l_RegisteredWords.append(encoded_string);
l_RegisteredWordsIndex.append(l_WordListCount);
}
}
l_WordListCount++;
// we've reached the end of the list
if (l_WordListCount == l_WordListSize)
{
// needed for vosk-api, see vosk_api.h
l_RegisteredWords.append("[unk]");
l_RegisteredWordsIndex.append(l_WordListCount);
QJsonDocument json_document;
json_document.setArray(QJsonArray::fromStringList(l_RegisteredWords));
// free existing recognizer if needed
if (l_VoskRecognizer)
{
l_vosk_recognizer_free(l_VoskRecognizer);
l_VoskRecognizer = nullptr;
}
// try to create a new recognizer
l_VoskRecognizer = l_vosk_recognizer_new_grm(l_VoskModel, (float)l_AudioDeviceSpec.freq, json_document.toJson().constData());
if (l_VoskRecognizer != nullptr)
{
l_vosk_recognizer_set_max_alternatives(l_VoskRecognizer, 3);
}
}
}
EXPORT void CALL SetMicState(int state)
{
if (!l_Initialized)
{
return;
}
if (state)
{
SDL_ClearQueuedAudio(l_AudioDevice);
SDL_PauseAudioDevice(l_AudioDevice, 0);
}
else
{
SDL_PauseAudioDevice(l_AudioDevice, 1);
}
l_MicState = state;
}
EXPORT void CALL ReadVRUResults(uint16_t* error_flags, uint16_t* num_results, uint16_t* mic_level, uint16_t* voice_level, uint16_t* voice_length, uint16_t* matches)
{
if (!l_Initialized || l_VoskRecognizer == nullptr)
{
return;
}
// initialize result data
*num_results = 0;
*mic_level = 0xBB8;
*voice_level = 0xBB8;
*voice_length = 0x8004;
for (int i = 0; i < 10; i += 2)
{
matches[i] = 0x7FFF;
matches[i + 1] = 0;
}
// retrieve audio data from device
SDL_PauseAudioDevice(l_AudioDevice, 1);
void* audio_buf = nullptr;
uint32_t audio_size = SDL_GetQueuedAudioSize(l_AudioDevice);
audio_buf = malloc(audio_size);
if (audio_buf == nullptr)
{
*error_flags = 0x8000;
return;
}
audio_size = SDL_DequeueAudio(l_AudioDevice, audio_buf, audio_size);
// hand audio data to vosk and retrieve results
int ret = l_vosk_recognizer_accept_waveform(l_VoskRecognizer, (const char*)audio_buf, audio_size);
if (ret == -1)
{
*error_flags = 0x8000;
free(audio_buf);
return;
}
QJsonDocument json_document = QJsonDocument::fromJson(l_vosk_recognizer_final_result(l_VoskRecognizer));
// parse results from vosk
QJsonArray alternatives_array = json_document.object().value("alternatives").toArray();
QStringList alternative_words;
QStringList found_words;
std::string debugMessage;
// parse words
for (int i = 0; i < alternatives_array.size(); i++)
{
QString word = alternatives_array.at(i).toObject().value("text").toString();
if (!word.isEmpty())
{
alternative_words.append(word);
}
}
// check the registered words,
// and see if any matches with the recognized words
for (const QString& word : l_RegisteredWords)
{
if (word != "[unk]" &&
!found_words.contains(word) &&
alternative_words.filter(word).size() > 0)
{
found_words.append(word);
if (found_words.size() == 5)
{
break;
}
}
}
// sort found words by length
std::sort(found_words.begin(), found_words.end(), [](QString& a, QString& b)
{
return a.size() > b.size();
});
int matches_index = 0;
for (int i = 0; i < found_words.size(); i++)
{
matches[matches_index++] = l_RegisteredWordsIndex.at(l_RegisteredWords.indexOf(found_words.at(i)));
matches[matches_index++] = i * 256;
debugMessage = "VRU: found match ";
debugMessage += std::to_string(i);
debugMessage += ": ";
debugMessage += found_words.at(i).toStdString();
CoreDebugCallbackMessage(CoreDebugMessageType::Info, debugMessage);
}
if (found_words.size() == 0 && alternative_words.size() > 0)
{
// heard something but it didn't match anything
*error_flags = 0x4000;
matches[0] = 0;
found_words.append("0");
debugMessage = "VRU: heard something but it didn't match anything";
CoreDebugCallbackMessage(CoreDebugMessageType::Info, debugMessage);
}
*num_results = found_words.size();
free(audio_buf);
}
EXPORT void CALL ClearVRUWords(uint8_t length)
{
if (!l_Initialized)
{
return;
}
l_WordListCount = 0;
l_WordListSize = length;
l_RegisteredWords.clear();
l_RegisteredWordsIndex.clear();
if (l_VoskRecognizer != nullptr)
{
l_vosk_recognizer_free(l_VoskRecognizer);
l_VoskRecognizer = nullptr;
}
}
EXPORT void CALL SetVRUWordMask(uint8_t length, uint8_t* mask)
{
}
+24
View File
@@ -0,0 +1,24 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef VRU_HPP
#define VRU_HPP
// attempts to initialize VRU capabilities
bool InitVRU(void);
// returns whether VRU has been initialized
bool IsVRUInit(void);
// attempts to de-initialize VRY capabilities
bool QuitVRU(void);
int GetVRUMicState(void);
#endif // VRU_HPP
+739
View File
@@ -0,0 +1,739 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "VRUwords.hpp"
//
// Exported Functions
//
std::vector<VRUWordEntry> GetVRUWordEntries(void)
{
std::vector<VRUWordEntry> entries;
entries.push_back({"03A50024000303CF00A80003036000EA", "pikachu"});
entries.push_back({"03A50045000303CF00A80003036000EA", "pikachu" });
entries.push_back({"03A50024000303C900450003036000EA", "pikachu" });
entries.push_back({"03A8018F000303CF00A80003036000EA", "pikachu" });
entries.push_back({"03B101B0000303CF00A80003036000EA", "pikachu" });
entries.push_back({"03CF00A80003036000EA", "pikachu" });
entries.push_back({"03A80066000303CF00A80003036000F900EA", "pikachu" });
entries.push_back({"03A50024000303CF00A80003035D001200F900EA", "pikachu" });
entries.push_back({"040801740024", "hey" });
entries.push_back({"03CF00C603360405000F0234", "come here" });
entries.push_back({"0369004803FC0318018F", "this way" });
entries.push_back({"039C010B000603900006037B01B0", "good bye" });
entries.push_back({"039900A80006037B01B0", "good bye" });
entries.push_back({"03F900090309009F02E2018F000303BD0234", "see you later" });
entries.push_back({"037B01B00006037B01B0", "bye bye" });
entries.push_back({"03FC000303C30255000303C6", "start" });
entries.push_back({"02E2006903FC000303B402E2018F", "lets play" });
entries.push_back({"040B00C002EB0213", "hello" });
entries.push_back({"043B0213000303AB00A5034803FC006903FC00A503270024", "open sesame" });
entries.push_back({"043B0213000303A80063034803FC006903FC00A503270024", "open sesame" });
entries.push_back({"039F01FE00990318018F", "go away" });
entries.push_back({"039C010B00060390033302D603390042035A", "good morning" });
entries.push_back({"039900A5033302D603390042035A", "good morning" });
entries.push_back({"042F01AD033603FC023A0024", "im sorry" });
entries.push_back({"042F01AD033603FC012602F10024", "im sorry" });
entries.push_back({"03FC023A0024", "sorry" });
entries.push_back({"03FC012602F10024", "sorry" });
entries.push_back({"042F01B00003036000ED03DB030C00EA", "i choose you" });
entries.push_back({"04080174030C00EA000303A50024000303CF00A80003036000EA", "hey you pikachu" });
entries.push_back({"03A50024000303CF00A8000303A50024000303CF00A80003036000EA", "pika pikachu" });
entries.push_back({"03A50024000303CF00A8000303A50024000303CF00A8000303A50024", "pika pika pi" });
entries.push_back({"03A50024000303A50024000303CF00A80003036000EA", "pi pikachu" });
entries.push_back({"03A50024000303A50024000303CF00A8000303A50024", "pi pika pi" });
entries.push_back({"03A50024000303D8000303CF00C9", "pika" });
entries.push_back({"03A50024000303CF00A8", "pika" });
entries.push_back({"03A50024000303CF00A8000303A50024000303CF00A8", "pika pika" });
entries.push_back({"03A503030024000303CF00A8", "pi ka" });
entries.push_back({"03A50024000303CF00C9000303CF00C9", "pi ka ka" });
entries.push_back({"03A50024000303CF00A8000303CF00A8000303A50024", "pi ka ka pi" });
entries.push_back({"037E02F10042035A036C0087000303C604050297", "bring that here" });
entries.push_back({"039F0213000603960066000303B70045000303C6", "go get it" });
entries.push_back({"0393004803E70045000303C6000303C000E703270024", "give it to me" });
entries.push_back({"0393004203270027036C0087000303C6", "gimme that" });
entries.push_back({"03F600C603480006038702370402014D000303D8", "thunder shock" });
entries.push_back({"03F600C603480006038702340006037B020A02EE000303C6", "thunderbolt" });
entries.push_back({"03F600C60348000603870234", "thunder" });
entries.push_back({"03F600C6033F0234", "thunder" });
entries.push_back({"0432009F02E20066000303D8000303C602F10045000303D802F40087000303C6", "electric rat" });
entries.push_back({"0426001B02E20066000303D8000303C602F10045000303D802F40087000303C6", "electric rat" });
entries.push_back({"0432009F02E20066000303C602F10045000303D802F40087000303C6", "electric rat" });
entries.push_back({"042F01A40408018F000303B7030C00EA", "i hate you" });
entries.push_back({"03A202F4018F000303C600060366014D0006037E", "great job" });
entries.push_back({"036C0087000303C3031B00AB03DE000603A202F4018F000303C6", "that was great" });
entries.push_back({"0309023703FC0213000303C9030C00EA000303C6", "you're so cute" });
entries.push_back({"03BD00A202F1004803ED0045000303D8", "terrific" });
entries.push_back({"037500C9000303BD023703F002F10024", "butter free" });
entries.push_back({"043200C603360006037E02F4005D02E500A8", "am brel a" });
entries.push_back({"037B01CE035A0006037B01CE035A", "boing boing" });
entries.push_back({"043801290348000303C000ED036C00A5033C0066000303D803FC000303C603FC000303BA018F00060366", "on to the next stage" });
entries.push_back({"042F0087000303AB009F02EE", "apple" });
entries.push_back({"043200A8000303AB009F02EE", "apple" });
entries.push_back({"0426000C0087000303B402EE", "apple" });
entries.push_back({"03A202F10021033C0087000303AB009F02EE", "green apple" });
entries.push_back({"0372018F000303D8000303BA0087000303AB009F02EE", "baked apple" });
entries.push_back({"039F020A02EE0006038700A5033C0087000303AB009F02EE", "golden apple" });
entries.push_back({"03A5002400030360", "peach" });
entries.push_back({"03FC000303C602FD012C00060372029D0024", "strawberry" });
entries.push_back({"03FC000303BD0225012C00060372029D0024", "strawberry" });
entries.push_back({"02F4008A03DE00060372029D0024", "raspberry" });
entries.push_back({"02F4008A03FC0006037E02F10024", "raspberry" });
entries.push_back({"037500A5033C0084033F00A8", "banana" });
entries.push_back({"036F0042033C0084033F00C9", "banana" });
entries.push_back({"037500C6033C0084033F00A8", "banana" });
entries.push_back({"03CC0087000303C6000303BA018602EE", "cat tail" });
entries.push_back({"032101A702EE00060390040B02340006037E", "wild herb" });
entries.push_back({"03D502D60348", "corn" });
entries.push_back({"03B1014D000303B4000303D502D60348", "popcorn" });
entries.push_back({"03AB00C60336000303B4000303C900420348", "pumpkin" });
entries.push_back({"03AB00C60336000303C900420348", "pumpkin" });
entries.push_back({"03AB00C6035A000303CF00A50348", "pumpkin" });
entries.push_back({"03C00273033F00A8000303B4", "turnip" });
entries.push_back({"03C0027303390045000303B4", "turnip" });
entries.push_back({"03CC00870006036F004500060366", "cabbage" });
entries.push_back({"03CC008102F700A8000303C6", "carrot" });
entries.push_back({"03CC02A300A8000303C6", "carrot" });
entries.push_back({"043200C60339030900A50348", "onion" });
entries.push_back({"043200A5033F00A50348", "onion" });
entries.push_back({"043501080339030900A50348", "onion" });
entries.push_back({"03FC031500240006037500C9000303BA018F0006038D0213", "sweet potato" });
entries.push_back({"03FC03150024000303C6000303AB00A8000303C3016E0006038D0213", "sweet potato" });
entries.push_back({"03FC03150024000303B4000303BA018F0006038700A8", "sweet potato" });
entries.push_back({"0411014D000303C603FC03150024000303C6000303AB00C9000303BA018F0006038D0213", "hot sweet potato" });
entries.push_back({"03FC032A005D02DF002703F002FA00EA000303C6", "smelly fruit" });
entries.push_back({"03FC000303B70045000303C9002703F002FA00EA000303C6", "sticky fruit" });
entries.push_back({"02FD021603FC000303BD00A80006039003F002FA00EA000303C6", "roasted fruit" });
entries.push_back({"0321012302EE033F00A8000303C6", "walnut" });
entries.push_back({"03D802F40087000303D50321012302EE033F00A8000303C6", "cracked walnut" });
entries.push_back({"03FC000303B101B0000303C900270402005D02EE", "spiky shell" });
entries.push_back({"03FC000303B101AD033900270402005D02EE", "spiny shell" });
entries.push_back({"0360006903FC033F00A8000303C6", "chestnut" });
entries.push_back({"036F002400030360033F00C9000303C6", "beach nut" });
entries.push_back({"03D50213000303CF00A5033F00C9000303C6", "coconut" });
entries.push_back({"042C018F000303D502D60348", "acorn" });
entries.push_back({"03C3021603FC000303BD00A800060384018F000303D502D60348", "toasted acorn" });
entries.push_back({"03F002EB01950042034E018F000303D502D60348", "flying acorn" });
entries.push_back({"042C018F000303D502D60348000303C3014D000303B4", "acorn top" });
entries.push_back({"036600C603360006037B0216040202FA00E70336", "jumbo mushroom" });
entries.push_back({"02FD021603FC000303BD00A8000603900006036600A503360006037B0213", "roasted jumbo" });
entries.push_back({"039002F1002103270027040202FA00E70336", "dreamy mushroom" });
entries.push_back({"03C602F700CC03F0009F02EE000303C3014D000303B4", "truffle top" });
entries.push_back({"037E02E800ED040202FA00E70336", "blue mushroom" });
entries.push_back({"0411014D000303C6040202FA00E70336", "hot mushroom" });
entries.push_back({"02F4006600060390040202FA00E70336", "red mushroom" });
entries.push_back({"03FC00C603390027040202FA00E70336", "sunny mushroom" });
entries.push_back({"032D00CC040202FA00E70336", "mushroom" });
entries.push_back({"0411014D000303C6032D00CC040202FA00E70336", "hot mushroom" });
entries.push_back({"02EB01B0000303C60006037500C002EE0006037E", "light bulb" });
entries.push_back({"02EB01B0000303C600060378010202EE0006037E", "light bulb" });
entries.push_back({"03CF00C9000303B4000303CC018F000303D8", "cupcake" });
entries.push_back({"03840174002703DB0024", "daisy" });
entries.push_back({"03A50045000303C000E70339030900A8", "petunia" });
entries.push_back({"03C000E102E500A8000303B4", "tulip" });
entries.push_back({"03C000E102DF0045000303B4", "tulip" });
entries.push_back({"03840084034800060387009F02EB019B00A50348", "dandelion" });
entries.push_back({"03840084034800060381001B02EB019B00A50348", "dandelion" });
entries.push_back({"037E02E800EA00060372005D02EE", "bluebell" });
entries.push_back({"03FC000303CF00C60348000303D80006037E02EB015003FC00A50336", "skunk blossom" });
entries.push_back({"03FC00C6034803F002EB01DD0234", "sunflower" });
entries.push_back({"02DF003C02DF0024", "lily" });
entries.push_back({"02FD021603DE0006037500C900060390", "rose bud" });
entries.push_back({"02F400660006039002FD021603DE", "red rose" });
entries.push_back({"0375009F02E800E70348", "balloon" });
entries.push_back({"03B10213000303CC018F00060381004803FC000303D8", "poke disc" });
entries.push_back({"036F0024000303600006037B012302EE", "beach ball" });
entries.push_back({"0321012C000303BD02190042035A000303CC00840348", "watering can" });
entries.push_back({"0321012C000303BD02190042035A0006036600C9000603A2", "watering jug" });
entries.push_back({"0306005D02EB02130006037B012302EE", "yellow ball" });
entries.push_back({"03600255000303D5020A02EE", "charcoal" });
entries.push_back({"02DF002703F004110315004803FC009F02EE", "leaf whistle" });
entries.push_back({"041102520333014A03390045000303CF00A8", "harmonica" });
entries.push_back({"03C602F700C60336000303A80066", "trumpet" });
entries.push_back({"03C602FA01080336000303AB00A8000303C6", "trumpet" });
entries.push_back({"037500A5033C0084033F00A8000303A5000F009F02EE", "banana peel" });
entries.push_back({"032A018F0006039900AB03F002100348", "megaphone" });
entries.push_back({"039F020A02EE00060390000303D501CE0348", "gold coin" });
entries.push_back({"0360014D000303CF009F02E500A8000303C6000303D501CE0348", "chocolate coin" });
entries.push_back({"0402014D000303D802E500A8000303C6000303D501CE0348", "chocolate coin" });
entries.push_back({"03F9003C02EE03EA0234000303D501CE0348", "silver coin" });
entries.push_back({"03D5014D000303AB0234000303D501CE0348", "copper coin" });
entries.push_back({"02FA00EA0006036F0024", "ruby" });
entries.push_back({"03FC008A03F001AA0300", "sapphire" });
entries.push_back({"03FC008A03F0019B0234", "sapphire" });
entries.push_back({"03C30213000303A8008A03DE", "topaz" });
entries.push_back({"02F40066000603900333025500060375009F02EE", "red marble" });
entries.push_back({"037E02E800E70333025500060375009F02EE", "blue marble" });
entries.push_back({"0306005D02EB02100333025500060375009F02EE", "yellow marble" });
entries.push_back({"02FA00EA0006036F001E02F10042035A", "ruby ring" });
entries.push_back({"037B014D00060387009F02EE000303CC0087000303B402F10042035A", "bottle cap ring" });
entries.push_back({"03B101AA02F700A8000303C603FC02D900060390", "pirate sword" });
entries.push_back({"03B101AA02F10045000303C603FC02D900060390", "pirate sword" });
entries.push_back({"03C301D403FC0126030000060390", "toy sword" });
entries.push_back({"037502340006039003F00069036C0234", "bird feather" });
entries.push_back({"037B020A02EE000303C6", "bolt" });
entries.push_back({"032A0087000603A203390045000303C6", "magnet" });
entries.push_back({"032A018F000603A203390045000303C6", "magnet" });
entries.push_back({"0333025500060375009F02EE", "marble" });
entries.push_back({"03D802F4018F000303C6", "crate" });
entries.push_back({"03D50255000603900006037B02D9000603900006037B014D000303D803FC", "cardboard box" });
entries.push_back({"03CF00A503360405000F0234", "come here" });
entries.push_back({"043B021603EA022804050297", "over here" });
entries.push_back({"040B009F02EB0213", "hello" });
entries.push_back({"039C010B00060390034501950024000303C6", "good night" });
entries.push_back({"039900A5034501B0000303C6", "good night" });
entries.push_back({"03F6018C035A000303C9030C00EA", "thank you" });
entries.push_back({"038A00ED03FC00C6033603F30042035A", "do something" });
entries.push_back({"02DF004803FC00A50348000303BD00A503270024", "listen to me" });
entries.push_back({"03A500090024000303CF00A8", "pi ka" });
entries.push_back({"039F0213000603930045000303BD00A8000303C6", "go get it" });
entries.push_back({"036C0087000303C603FC03F001AD0348", "thats fine" });
entries.push_back({"043B0213000303CC01740024", "ok" });
entries.push_back({"04020276", "sure" });
entries.push_back({"02FD01B0000303C6", "right" });
entries.push_back({"02E2006903FC0006038A00ED036C0087000303C6", "lets do that" });
entries.push_back({"0345014D000303C6036C0087000303C3031B00C60348", "not that one" });
entries.push_back({"036C0087000303C603DE02FD0129035A", "thats wrong" });
entries.push_back({"0372008700060390000303B10213000303CC018C0333014A0348", "bad pokemon" });
entries.push_back({"038D02100348000303C60006038A00ED036C0087000303C6", "dont do that" });
entries.push_back({"042900420348000303CF021C0066000303D8000303C6", "incorrect" });
entries.push_back({"03CF00C9000303BD00A8000303C301F2000303C6", "cut it out" });
entries.push_back({"03450213", "no" });
entries.push_back({"0318018F0006038700A80006039F0213", "way to go" });
entries.push_back({"03F002EB01DD0234", "flower" });
entries.push_back({"038400840348000303C603FC", "dance" });
entries.push_back({"03F602FD01F80045000303C6", "throw it" });
entries.push_back({"03C3015003F90045000303C6", "toss it" });
entries.push_back({"030C00EA000303CC008403390024000303C6036C0087000303C6", "you can eat that" });
entries.push_back({"03BA019203FC000303B70045000303C6", "taste it" });
entries.push_back({"041101F503DB0045000303C6000303BA019203FC000303C6", "hows it taste" });
entries.push_back({"041101F503DB0045000303C603FC032A005D02EE", "hows it smell" });
entries.push_back({"041101F503DB0045000303C603FC01EF034800060390", "hows it sound" });
entries.push_back({"0411031B00A8000303C60006038700AB03DB0045000303C60006038A00EA", "what does it do" });
entries.push_back({"03B402E201830411031B00A8000303C6", "play what" });
entries.push_back({"03C602FD01950045000303C6", "try it" });
entries.push_back({"03B402E201740045000303C6", "play it" });
entries.push_back({"039002FD014D000303A50045000303C6", "drop it" });
entries.push_back({"03A80066000303CF00A80003036000EA", "pikachu" });
entries.push_back({"030C00EA000303CC00840348000303BA019203FC000303B70045000303C6", "you can taste it" });
entries.push_back({"041101F503DB0045000303C603FC01EF0348", "hows it sound" });
entries.push_back({"03AE010B000303C6036C0087000303C6000603720087000303D8", "put that back" });
entries.push_back({"03FC000303BA018003150048036C03270024", "stay with me" });
entries.push_back({"03FC000303BA01770087000303C6033301A4041101F503FC", "stay at my house" });
entries.push_back({"03F90009030C00E102E2018F000303BD0234", "see you later" });
entries.push_back({"03F90009030C00EA", "see you" });
entries.push_back({"037B01B0", "bye" });
entries.push_back({"0411031B00A8000303BD0219030900A80006038A00CF0042035A", "what are you doing" });
entries.push_back({"0411031B00A8000303C603FC00C9000303B4", "whats up" });
entries.push_back({"0411031B00A8000303C603FC00C9000303B4036C02B8", "whats up there" });
entries.push_back({"042F0087000303AB009F02EE", "apple" });
entries.push_back({"033C006903EA0231033301AD034800060390", "never mind" });
entries.push_back({"039C010B00060390034501B0000303C6", "good night" });
entries.push_back({"03F60084035A000303C9030C00EA", "thank you" });
entries.push_back({"04290045000303C603DE02F700C603390042035100990318018F", "its running away" });
entries.push_back({"03F002EB01DD02340006037500C900060390", "flower bud" });
entries.push_back({"03BA008700060393030902190045000303C6", "tag you're it" });
entries.push_back({"039F01FE00BA0318018F", "go away" });
entries.push_back({"02E8010B000303D5021603EA0237036C02B8", "look over there" });
entries.push_back({"04290045000303C603FC021603EA0237036C02B8", "its over there" });
entries.push_back({"02DF003C02DF0024", "lily" });
entries.push_back({"03FC00C6034803F002EB01DD0234", "sunflower" });
entries.push_back({"03FC000303CF00C60348000303D80006037E02EB015003FC014A0336", "skunk blossom" });
entries.push_back({"03FC000303C602FD016E00060372029D0024", "strawberry" });
entries.push_back({"02F4008A03FC000303B402F10024", "raspberry" });
entries.push_back({"0438012C0006038100480402", "odd ish" });
entries.push_back({"03A202E800E70336", "gloom" });
entries.push_back({"03EA01A702EE000303B402E800E70336", "vile plume" });
entries.push_back({"042F01AD033603FC02BE0024", "im sorry" });
entries.push_back({"03FC02BE0024", "sorry" });
entries.push_back({"03CC0084033F00A50348", "cannon" });
entries.push_back({"03810045000603930045000303C301F2000303C6", "dig it out" });
entries.push_back({"03810045000603A2036C017A0234", "dig there" });
entries.push_back({"03810045000603A2", "dig" });
entries.push_back({"03AE010202EE", "pull" });
entries.push_back({"033F00C9000303C6", "nut" });
entries.push_back({"03780108033C0084033F00C9", "banana" });
entries.push_back({"03C602F4006903E4023400030360006903FC000303C6", "treasure chest" });
entries.push_back({"03C602F4006903E40234", "treasure" });
entries.push_back({"0372029D002400060390000303C602F4006903E40234", "buried treasure" });
entries.push_back({"0408005D02EB0213", "hello" });
entries.push_back({"042F01A702E500CC03E7030C00EA", "i love you" });
entries.push_back({"04080084035701290348", "hang on" });
entries.push_back({"03C602F40066000603660234", "treasure" });
entries.push_back({"03960066000303C602EB015003FC000303C6", "get lost" });
entries.push_back({"03A50024000303CF00BD040B00A8", "pee ka" });
entries.push_back({"03A500090024000303CF00C9", "pi ka" });
entries.push_back({"0375009C041101AD034800060381030C00EA", "behind you" });
entries.push_back({"036F0018041101AD03480006036600EA", "behind you" });
entries.push_back({"041101EF032A006303390024", "how many" });
entries.push_back({"041101EF032A0063033900150258036C02B8", "how many are there" });
entries.push_back({"03B1020A02DF001503180087000603A2", "poly wag" });
entries.push_back({"03B1014402DF001503180087000603A2", "poly wag" });
entries.push_back({"03B1020A02DF0015031B022B02EE", "poliwhirl" });
entries.push_back({"03FC000303D5031B0234000303BD009F02EE", "squirt el" });
entries.push_back({"0396008A03FC000303C602DF0024", "ghastly" });
entries.push_back({"041101290348000303BD0234", "haunt er" });
entries.push_back({"02FD0129035A", "wrong" });
entries.push_back({"036C0087000303C603DE02FD0129035A", "thats wrong" });
entries.push_back({"03D503150045000303C6", "quit" });
entries.push_back({"03CF00C9000303B700450006038D01F2000303C6", "cut it out" });
entries.push_back({"03CF00A503270297", "come here" });
entries.push_back({"03CF00A5033604050297", "come here" });
entries.push_back({"02E8010B000303D5021603EA022804050297", "look over here" });
entries.push_back({"02E8010B000303D501F2000303C6", "look out" });
entries.push_back({"0321012C0003036001F2000303C6", "watch out" });
entries.push_back({"036C02B8", "there" });
entries.push_back({"03FC03150042035A034501F2", "swing now" });
entries.push_back({"03FC03150042035A", "swing" });
entries.push_back({"039F020D02FD01B0000303C6", "go right" });
entries.push_back({"02FD01B0000303C6", "right" });
entries.push_back({"03F00258036C022E02FD01B0000303C6", "farther right" });
entries.push_back({"039F020A02E2006903F0000303C6", "go left" });
entries.push_back({"02E2006903F0000303C6", "left" });
entries.push_back({"03F00258036C022B02E2006903F0000303C6", "farther left" });
entries.push_back({"03FC000303C3014D000303B4", "stop" });
entries.push_back({"03FC000303C3014D000303B4034501F2", "stop now" });
entries.push_back({"03FC000303C3014D000303B4036C02B8", "stop there" });
entries.push_back({"03FC000303A50042033F00A202FD01EF034800060390", "spin around" });
entries.push_back({"02FD012903570318018F", "wrong way" });
entries.push_back({"03BD0231033F00A202FD01EF034800060390", "turn around" });
entries.push_back({"03720087000303CF00C9000303B4", "back up" });
entries.push_back({"03C90024000303B40006039F01F80042035A", "keep going" });
entries.push_back({"03FC000303C602F4018F00060387009C0408006600060390", "straight ahead" });
entries.push_back({"037500C002EE0006037500AB03FC02D9", "bulb a saur" });
entries.push_back({"03E70021033F00AB03FC02D9", "venus are" });
entries.push_back({"03FC02EB0213000303B10213000303D8", "slowpoke" });
entries.push_back({"03FC000303D5031B0234000303BD009F02EE", "squirt el" });
entries.push_back({"03600252032A00840348000603870234", "charmander" });
entries.push_back({"03C903060087000303BD0234000303A50024", "cater pie" });
entries.push_back({"02EB014D000303B402F700AB03FC", "lapras" });
entries.push_back({"02E20087000303B402F700AB03FC", "lapras" });
entries.push_back({"03C302130006039900A8000303A50024", "togepi" });
entries.push_back({"03C30213000603930045000303A500090024", "togepi" });
entries.push_back({"03A500420339030F012C0006038700A8", "pinata" });
entries.push_back({"03A500210339030F014D000303BD00A8", "pinata" });
entries.push_back({"02DF004803F900420348000303BD00A503270024", "listen to me" });
entries.push_back({"03F002FA00EA000303C6", "fruit" });
entries.push_back({"03450213000303C6000303A8008700060390", "notepad" });
entries.push_back({"042900420348000603A202F1002400060381000F00A50348000303C603FC", "ingredients" });
entries.push_back({"02F4006903FC00A8000303A50024", "recipe" });
entries.push_back({"02F4006903F90045000303A50024", "recipe" });
entries.push_back({"0411014D000303C603FC03150024000303AB00C9000303BA018F0006038D0213", "hot sweet potato" });
entries.push_back({"0411014D000303C603FC03150024000303B4000303BA018F0006038D0213", "hot sweet potato" });
entries.push_back({"03D200E102EE", "cool" });
entries.push_back({"03F001AD0348", "fine" });
entries.push_back({"0309023703FC0213000303C9030C00EA000303C6", "youre so cute" });
entries.push_back({"0393004803E70045000303C6000303C000E703270024", "give it to me" });
entries.push_back({"0393004203270027036C0087000303C6", "gimme that" });
entries.push_back({"03F602FD01F80045000303C6", "throw it" });
entries.push_back({"03FC000303C000EA000303A5004500060390", "stupid" });
entries.push_back({"02E20066000303C603FC000303B402E2018F", "lets play" });
entries.push_back({"039C0108033302D603390042035A", "good morning" });
entries.push_back({"0318018F000303CF00C9000303B4", "wake up" });
entries.push_back({"03960066000303BD00C9000303B4", "get up" });
entries.push_back({"04260024000303CF00A5034803DE", "e cans" });
entries.push_back({"042C0066000303CF00A5034803DE", "e cans" });
entries.push_back({"037E02F10042034B0045000303C604050297", "bring it here" });
entries.push_back({"030C00EA000303CF00A503390024000303C6036C0087000303C6", "you can eat that" });
entries.push_back({"03BA019203FC000303BD00A8000303C6", "taste it" });
entries.push_back({"04260024000303B70045000303C6", "eat it" });
entries.push_back({"032A0087000603A2033F00A8000303C6", "magnet" });
entries.push_back({"03D501CE0348", "coin" });
entries.push_back({"036600D5009F02EE", "jewel" });
entries.push_back({"0333025500060375009F02EE", "marble" });
entries.push_back({"03B101AA02F10045000303C603FC01", "pirate sword" });
entries.push_back({"039C0108034501B0000303C6", "good night" });
entries.push_back({"03D50315004803DE000303C301AD0336", "quiz time" });
entries.push_back({"03B7002703E70024", "tv" });
entries.push_back({"042F01B0000303D503150045000303C6", "i quit" });
entries.push_back({"042F01AD03360006038700C60348", "im done" });
entries.push_back({"030C00EA000303CF00A50348000303B402E2018F", "you can play" });
entries.push_back({"03150024000303CF00A50348000303B402E2018F", "we can play" });
entries.push_back({"0372008700060390", "bad" });
entries.push_back({"0345014D000303C90045000303C3012F03F0", "knock it off" });
entries.push_back({"03450213000303B402E201740042035A", "no playing" });
entries.push_back({"03FC000303C3014D000303B4000303B402E201740042035A", "stop playing" });
entries.push_back({"042F01AD03360345014D000303C6000303B402E201740042035A", "im not playing" });
entries.push_back({"03D503150045000303C6", "quit" });
entries.push_back({"03FC000303C3014D000303B4036C0087000303C6", "stop that" });
entries.push_back({"03D802DF002103390045000303BD00C9000303B4", "clean it up" });
entries.push_back({"03AE010B000303B70045000303BD00990318018F", "put it away" });
entries.push_back({"03D802DF0021033F00C9000303B4", "clean up" });
entries.push_back({"03D802DF00210348036C0087000303BD00C9000303B4", "clean that up" });
entries.push_back({"03B70048040200EA", "tissue" });
entries.push_back({"037500C002EE0006037500AB03FC02D9", "bulb a saur" });
entries.push_back({"042F01B303E7002703FC02D9", "ivy saur" });
entries.push_back({"042F01B303EA00AB03FC02D9", "ivy saur" });
entries.push_back({"03E70021033F00AB03FC02D9", "venus are" });
entries.push_back({"03600252032A00840348000603870234", "char mander" });
entries.push_back({"036002520327001B02DF0009030900A50348", "char me leon" });
entries.push_back({"0360025803DE025500060390", "chari z ard" });
entries.push_back({"0360024000AB03DE025500060390", "chari z ard" });
entries.push_back({"03FC000303D5031B0234000303BD009F02EE", "squirt el" });
entries.push_back({"03210255000303BD0234000303BD009F02EE", "war tor tell" });
entries.push_back({"03210255000303C302D9000303BD009F02EE", "war tor tell" });
entries.push_back({"037E02E2008A03FC000303C301D403FC", "blast oise" });
entries.push_back({"03CC0087000303BD0234000303A50024", "cater pie" });
entries.push_back({"032A0066000303BD00A8000303B1014D00060390", "meta pod" });
entries.push_back({"037500C9000303BD023703F002F10024", "butter free" });
entries.push_back({"0315002400060387009F02EE", "weed el" });
entries.push_back({"03D2010B000303D200E7033F00A8", "ka kuna" });
entries.push_back({"03C90045000303D200E7033F00A8", "ka kuna" });
entries.push_back({"036F00240006039002F1003C02EE", "bee drill" });
entries.push_back({"036F00240006039002F7009F02EE", "bee drill" });
entries.push_back({"03A5004500060366014D000303C6", "pid gee ot" });
entries.push_back({"02F40087000303BD00A8000303BD00A8", "rat tata" });
entries.push_back({"02F700A8000303BA00870006038700A8", "rat tata" });
entries.push_back({"02F40087000303BA00870006038700A8", "rat tata" });
entries.push_back({"02F40087000303B70045000303CC018F000303C6", "rat i cat" });
entries.push_back({"03FC000303A502880213", "spear ow" });
entries.push_back({"03ED02880213", "fear ow" });
entries.push_back({"04260024000303CF00A5034803DE", "e cans" });
entries.push_back({"042C0066000303CF00A5034803DE", "e cans" });
entries.push_back({"043802550006037B014D000303D8", "ar bok" });
entries.push_back({"03A50024000303CF00A80003036000EA", "pikachu" });
entries.push_back({"02FD01B00003036000EA", "rye chu" });
entries.push_back({"03FC00840348040202FA00EA", "sand shrew" });
entries.push_back({"03FC0084034803FC02E2008A0402", "sand slash" });
entries.push_back({"0339004500060387021F00A5034803ED0021032A018602EE", "ni doran female" });
entries.push_back({"033900450006038D020D02F700A5034803ED0021032A017A009F02EE", "ni doran female" });
entries.push_back({"033900450006038702190021033F00A8", "ni door ina" });
entries.push_back({"033900240006038D0213000303D5031500210348", "nido queen" });
entries.push_back({"033900450006038D020D02F700A50348032A018602EE", "ni doran male" });
entries.push_back({"0339004500060387021F00A50348032A017A009F02EE", "ni doran male" });
entries.push_back({"033900450006038D02BE002103450213", "ni dor ino" });
entries.push_back({"033900240006038D020D02F1002103450213", "ni dor ino" });
entries.push_back({"033900240006038D0213000303C90042035A", "ni do king" });
entries.push_back({"03D802E2006903F0008102F10024", "cle fairy" });
entries.push_back({"03D802E500AB03F0008102F10024", "cle fairy" });
entries.push_back({"03D802E2006903F0018F00060375009F02EE", "cle fable" });
entries.push_back({"03D802E500AB03F0018F00060375009F02EE", "cle fable" });
entries.push_back({"03EA009F02EE000303A50045000303D803FC", "vol pix" });
entries.push_back({"034501AD0348000303BA018602EE03DE", "nine tales" });
entries.push_back({"03630045000603A202DF0024000303AB00CC03F0", "jiggly puff" });
entries.push_back({"0363004500060399009F02DF0024000303AB00CC03F0", "jiggly puff" });
entries.push_back({"03150045000603A202DF0024000303BD00CC03F0", "wiggly tuff" });
entries.push_back({"03DE00EA000603720087000303C6", "zoo bat" });
entries.push_back({"039F020A02EE000603720087000303C6", "goal bat" });
entries.push_back({"0438012C0006038100480402", "odd ish" });
entries.push_back({"03A202E800E70336", "gloom" });
entries.push_back({"03EA01A702EE000303B402E800E70336", "vile plume" });
entries.push_back({"03B1024000AB03FC", "paras" });
entries.push_back({"03A802A300AB03FC", "paras" });
entries.push_back({"03B1024000AB03FC0066000303D8000303C6", "para sect" });
entries.push_back({"03A802A300AB03FC0066000303D8000303C6", "para sect" });
entries.push_back({"03EA006303450210033C0087000303C6", "ven on at" });
entries.push_back({"03EA0063034502100333012F03F6", "venom oth" });
entries.push_back({"03810045000603A202E500A8000303C6", "dig let" });
entries.push_back({"0327001501F503F6", "meow eth" });
entries.push_back({"03AB023703E400A50348", "persian" });
entries.push_back({"03FC01B00006038700C9000303D8", "psy duck" });
entries.push_back({"039C010202EE0006038700C9000303D8", "goal duck" });
entries.push_back({"032A0084035A000303C90024", "man key" });
entries.push_back({"03B402FD01AD032A018F000303B4", "prime ape" });
entries.push_back({"03A202FD020A02EB01B3036C", "growl ith" });
entries.push_back({"03A202FD01E902DF0048036C", "growl ith" });
entries.push_back({"04380255000303CC018C034501AD0348", "ar canine" });
entries.push_back({"04380255000303CF00A5034501AD0348", "ar canine" });
entries.push_back({"03B1020A02DF001503180087000603A2", "poly wag" });
entries.push_back({"03B1020A02DF0015031B022B02EE", "poly whirl" });
entries.push_back({"03B1020A02DF001E02F4008A03F6", "poly wrath" });
entries.push_back({"03B1014402DF001E02F4008A03F6", "poly wrath" });
entries.push_back({"042F00870006037E02F700A8", "abra" });
entries.push_back({"03CF00A80006038400870006037E02F700A8", "ka dab ra" });
entries.push_back({"042F007E02E500A8000303CF00AB03DE00840336", "ala ka zam" });
entries.push_back({"032D00A800030360014D000303B4", "ma chop" });
entries.push_back({"032D00A8000303600213000303D8", "ma choke" });
entries.push_back({"032D00A80003036000840336000303B4", "ma champ" });
entries.push_back({"0372005D02EE03FC000303B402FD01F2000303C6", "bell sprout" });
entries.push_back({"03BA0063033F00A8000303CF00C002EE", "ten ta cool" });
entries.push_back({"03BA0063033F00A8000303D802FA00E102EE", "ten ta cruel" });
entries.push_back({"03630009030F02130006038A00EA00060390", "geo dude" });
entries.push_back({"03A202F4008A03EA009F02E50234", "gravel er" });
entries.push_back({"03A202F4008A03EA02E50234", "gravel er" });
entries.push_back({"039F020A02E500A50336", "golem" });
entries.push_back({"039F014402EE0336", "golem" });
entries.push_back({"03B1021003390024000303BD00A8", "pony ta" });
entries.push_back({"03B1021003390024000303C3016E", "pony ta" });
entries.push_back({"02F40087000303A5004500060384008A0402", "rap e dash" });
entries.push_back({"03FC02EB0213000303B10213000303D8", "slowpoke" });
entries.push_back({"03FC02EB02130006037E02FD0213", "slow bro" });
entries.push_back({"032A0087000603A2033F00A5033301B0000303C6", "mag ne mite" });
entries.push_back({"032A0087000603A2033F00A8000303C3014A0348", "mag ne ton" });
entries.push_back({"03F0025803F0006600030360000303C6", "far fetched" });
entries.push_back({"038D02130006039002F100150213", "dod rio" });
entries.push_back({"03F9001B02EE", "seel" });
entries.push_back({"038A00EA0006039F014A035A", "dew gong" });
entries.push_back({"038A00EA0006039F014A0348", "dew gong" });
entries.push_back({"03A202FD01AD032D0234", "grim er" });
entries.push_back({"032D00C9000303D8", "muck" });
entries.push_back({"0402005D02EE000603870234", "shell der" });
entries.push_back({"03D802EB01D403FC000303BD0234", "cloy ster" });
entries.push_back({"0396008A03FC000303C602DF00", "ghastly" });
entries.push_back({"0396008A03FC02DF0024", "ghastly" });
entries.push_back({"041101290348000303BD0234", "haunt er" });
entries.push_back({"03960084035A0006039F0255", "gen gar" });
entries.push_back({"0396006303480006039F0255", "gen gar" });
entries.push_back({"0438014A03390045000303D803FC", "on ix" });
entries.push_back({"039002FD01F503DB0024", "drowsy" });
entries.push_back({"039002FD021603DB0024", "drowsy" });
entries.push_back({"04050045000303B403450213", "hip no" });
entries.push_back({"03D802F400870006036F00", "crabby" });
entries.push_back({"03C90042035A02E50234", "king ler" });
entries.push_back({"03EA020A02EE000303C302D90006037E", "volt orb" });
entries.push_back({"0426001B02E20066000303D8000303C602FD021300060390", "electrode" });
entries.push_back({"0432009F02E20066000303D8000303C602FD021300060390", "electrode" });
entries.push_back({"042C0066000603A203DE000303C9030C00EA000303C6", "execute" });
entries.push_back({"042C0066000603A203DE0066000303C9030C00EA000303C302D9", "executor" });
entries.push_back({"042C0066000603A203FC00A8000303C9030C00EA000603870234", "executor" });
entries.push_back({"03C9030C00EA0006037B02100348", "cue bone" });
entries.push_back({"032A02A9020403180087000303D8", "mar oh wack" });
entries.push_back({"03330246020403180087000303D8", "mar oh wack" });
entries.push_back({"04050045000303C603330210034802DF0024", "hit mon lee" });
entries.push_back({"04050045000303C60333014A034802DF0024", "hit mon lee" });
entries.push_back({"04050045000303C60333021003480003036000840348", "hit mon chan" });
entries.push_back({"02DF0045000303C90024000303BD00A5035A", "lick eh tung" });
entries.push_back({"02DF0045000303C90045000303BD00A5035A", "lick i tung" });
entries.push_back({"02DF0045000303C90045000303C00108035A", "lick a tung" });
entries.push_back({"03D5015003ED0042035A", "coughing" });
entries.push_back({"0315002703DB0042035A", "wheezing" });
entries.push_back({"02FD01A4041102D60348", "rye horn" });
entries.push_back({"02FD01B00006038D01290348", "rye don" });
entries.push_back({"03600084034803F90024", "chance e" });
entries.push_back({"03BA0084034800060366005D02E500A8", "tangela" });
entries.push_back({"03BA018C034800060396005D02E500A8", "tangela" });
entries.push_back({"03CC018C035A0006039900AB03FC000303D5014A0348", "kang as khan" });
entries.push_back({"041102DC03F90024", "horse sea" });
entries.push_back({"03F900240006039002F700A8", "sea dra" });
entries.push_back({"039F020A02EE0006038100210348", "gold een" });
entries.push_back({"03F90024000303C90042035A", "seeking" });
entries.push_back({"03FC000303C3023A030C00EA", "starry you" });
entries.push_back({"03FC000303C3025203270024", "star me" });
entries.push_back({"0327004803FC000303BD0231033301AD0336", "mister mime" });
entries.push_back({"03FC01B3036C0234", "sigh ther" });
entries.push_back({"03630042035A000303D803FC", "jynx" });
entries.push_back({"0426001B02E20066000303D8000303BD00A80006037500CC03DE", "elect tra buzz" });
entries.push_back({"0432009F02E20066000303D8000303BD00A80006037500CC03DE", "elect tra buzz" });
entries.push_back({"032A0087000603A203330255", "mag mar" });
entries.push_back({"03A50042034803FC0234", "pin sir" });
entries.push_back({"03C3020D02FD012F03FC", "tar os" });
entries.push_back({"03C30246021603FC", "tar os" });
entries.push_back({"032A0087000603630045000303D50255000303B4", "magi karp" });
entries.push_back({"039602A300A80006038D015003FC", "guy a rad os" });
entries.push_back({"039602A300A80006038D021603FC", "guy a rad os" });
entries.push_back({"02EB014D000303B402F700AB03FC", "lap ras" });
entries.push_back({"02E20087000303B402F700AB03FC", "lap ras" });
entries.push_back({"03810045000303C30213", "ditto" });
entries.push_back({"0426002703E70024", "e v" });
entries.push_back({"03EA018F000303B102BE0015014A0348", "vapor eon" });
entries.push_back({"03EA00A8000303B102BE000F00A50348", "vapor eon" });
entries.push_back({"0366020A02EE000303B70015014A0348", "jolt eon" });
entries.push_back({"03F002E2029D0015014A0348", "flare eon" });
entries.push_back({"03B1020D02F100240006039F014A0348", "por e gon" });
entries.push_back({"03B1020D02F100240006039900A50348", "por e gon" });
entries.push_back({"043B0210032D00C6034501B0000303C6", "oman ite" });
entries.push_back({"04380129032D00A5034501B0000303C6", "oman ite" });
entries.push_back({"043B0210032D00CC03FC000303C30255", "oma star" });
entries.push_back({"04380129032D00AB03FC000303C30255", "oma star" });
entries.push_back({"03CF00C90006037800EA0006038D0213", "ka boo tow" });
entries.push_back({"03D5012C0006037800EA000303C3014D000303B403FC", "ka bu tops" });
entries.push_back({"03D5012C0006037500A8000303C3014D000303B403FC", "ka bu tops" });
entries.push_back({"03D5012C0006037500A8000303C3015003FC", "ka bu tops" });
entries.push_back({"042C02A90213000603840087000303D8000303BD00C002EE", "aero dac tell" });
entries.push_back({"03FC034502D002E20087000303D803FC", "snore lax" });
entries.push_back({"04380255000303B70045000303D200E703450213", "art eh cuno" });
entries.push_back({"03DE0087000303B40006038D015003FC", "zap dos" });
entries.push_back({"03DE0087000303B40006038D021603FC", "zap dos" });
entries.push_back({"0333020A02EE000303C602F4006903FC", "mol tres" });
entries.push_back({"039002F700A8000303B7002103390024", "duh rat ini" });
entries.push_back({"039002F400870006039900A5033C02B8", "dragonair" });
entries.push_back({"039002F400870006039900A5034501B0000303C6", "dragon ite" });
entries.push_back({"0327030C00EA000303C000EA", "mew two" });
entries.push_back({"0327030C00EA", "mew" });
entries.push_back({"03C3014D000303AB00AB03EA000603630045000603A202DF0024000303AB00AB03F0", "top of jiggly puff" });
entries.push_back({"03C302130006039900A8000303A50024", "toge pi" });
entries.push_back({"03C302130006039C010B000303A50024", "toge pi" });
entries.push_back({"03C30213000603930045000303A500090024", "toge pi" });
entries.push_back({"03B1014402DF001503180087000603A2", "poly wag" });
entries.push_back({"03150024000303A50042034800060372005D02EE", "weeping bell" });
entries.push_back({"03E70045000303D8000303C602F1002400060372005D02EE", "vic tree bell" });
entries.push_back({"03BA0063033F00A8000303D200E102EE", "ten ta cool" });
entries.push_back({"038700C9000603A2000303C602F100150213", "dug trio" });
entries.push_back({"03A50045000603630024", "pid gee" });
entries.push_back({"038D02130006038A00DB0213", "do duo" });
entries.push_back({"03A50045000603660213000303C30213", "pid gee otto" });
entries.push_back({"03CF00C9000303D200E7033F00A8", "ka kuna" });
entries.push_back({"03BA00630348000303BD00A8000303D200E102EE", "ten ta cool" });
entries.push_back({"03CC018C035A00060396008A03FC000303D5014A0348", "kang as khan" });
entries.push_back({"043B0210032D00AB03FC000303C30255", "oma star" });
entries.push_back({"03CF00A80006037800EA000303C3014D000303B403FC", "ka boo tops" });
entries.push_back({"036C0087000303C603FC02FD01B0000303C6", "thats right" });
entries.push_back({"036C0087000303C603FC0006039C010B00060390", "thats good" });
entries.push_back({"036C0087000303C3031B00C60348", "that one" });
entries.push_back({"036C008A03FC03F001AD0348", "thats fine" });
entries.push_back({"036C0087000303C603DE03F001AD0348", "thats fine" });
entries.push_back({"03CF021C0066000303D8000303C6", "correct" });
entries.push_back({"03CF00A202F40066000303D8000303C6", "correct" });
entries.push_back({"036F0042035A0006039F0213", "bingo" });
entries.push_back({"03D5012302DF0045000303C6", "call it" });
entries.push_back({"02E2006903FC000303B402E2018F", "lets play" });
entries.push_back({"02FD0129035A", "wrong" });
entries.push_back({"0372008700060390000303A50024000303CF00A80003036000EA", "bad pikachu" });
entries.push_back({"0327004803FC", "miss" });
entries.push_back({"038D02100348000303C6000303D5012302DF0045000303C6", "dont call it" });
entries.push_back({"041101F503FC", "house" });
entries.push_back({"041102100336", "home" });
entries.push_back({"03EA00A202F1004500060381000F00C60348", "viridian" });
entries.push_back({"03EA00A202F1004500060381000F00C6034803F002C400AB03FC000303C6", "viridian forest" });
entries.push_back({"043B0213000303CF0234", "ochre" });
entries.push_back({"043B0213000303CF0225031E010B0006039003DE", "ochre woods" });
entries.push_back({"043B0213000303CF023703ED004803FF0042035A0411020A02EE", "ochre fishing hole" });
entries.push_back({"03FC000303B402F10042035A02DF002703F0", "spring leaf" });
entries.push_back({"03FC000303B402F10042035A02DF002703F003ED000F00C002EE00060390", "spring leaf field" });
entries.push_back({"0438014402E500AB03EA01AD0348", "olivine" });
entries.push_back({"0438014402E500AB03EA01AD034802E2018F000303D8", "olivine lake" });
entries.push_back({"0438014402E500AB03EA01AD034803ED004803FF0042035A0411020A02EE", "olivine fishing hole" });
entries.push_back({"03D502130006037B012302EE000303C6", "cobalt" });
entries.push_back({"03D502130006037B012302EE000303C301A702E500C6034800060390", "cobalt island" });
entries.push_back({"03D502130006037E03ED004803FF0042035A0411020A02EE", "cobalt fishing hole" });
entries.push_back({"03D5021603FC000303C6", "coast" });
entries.push_back({"03D502130006037B012302EE000303C6000303D5021603FC000303C6", "cobalt coast" });
entries.push_back({"03FC000303A80069040200C002EE000303C602F4018C03390042035A", "special training" });
entries.push_back({"03BD0231033F00A8000303B4", "turnip" });
entries.push_back({"03BD02310348000303B4", "turnip" });
entries.push_back({"03FC03150024000303C6000303AB00A8000303BA018F0006038D0213", "sweet potato" });
entries.push_back({"0411014D000303C603FC03150024000303C6000303AE010B000303BA018F0006038D0213", "hot sweet potato" });
entries.push_back({"03D501470300000603900006037B02D9000603900006037B014D000303D803FC", "cardboard box" });
entries.push_back({"04080084034B00420348036C02B8", "hang in there" });
entries.push_back({"03AE010202EE", "pull" });
entries.push_back({"02F1001B02DF0045000303B700420348", "reel it in" });
entries.push_back({"034501F2", "now" });
entries.push_back({"03CC00870003035D0045000303C6", "catch it" });
entries.push_back({"03960066000303B70045000303C6", "get it" });
entries.push_back({"03AE010202DF0045000303C6", "pull it" });
entries.push_back({"03AE010202EE04110255000603870234", "pull harder" });
entries.push_back({"02E20066000303B70045000303C60006039F0213", "let it go" });
entries.push_back({"02F1003C02DF002703F90045000303C6", "release it" });
entries.push_back({"02E500C6034800030360", "lunch" });
entries.push_back({"03FC033C0087000303D8", "snack" });
entries.push_back({"02E2006903F90024000303C6", "lets eat" });
entries.push_back({"03CF00C9000303B4000303CC018F000303D8", "cupcake" });
entries.push_back({"042F019B00C6034800060387023703FC000303BA0084034800060390", "i understand" });
entries.push_back({"042F01B0000603930045000303B70045000303C6", "i get it" });
entries.push_back({"0411032101B0", "why" });
entries.push_back({"041101F2000303CF00C60336", "how come" });
entries.push_back({"039C010B0006037B01B0", "good bye" });
entries.push_back({"03BA018F000303D8000303CC02B8", "take care" });
entries.push_back({"042F019B009F02EE0327004803F9030C00EA", "ill miss you" });
entries.push_back({"0438016502EE0327004803F9030C00EA", "ill miss you" });
entries.push_back({"03FC000303C3014D000303B4036C0087000303C6", "stop that" });
entries.push_back({"03D503150045000303C6", "quit" });
entries.push_back({"03CF00C9000303B70045000303C301F2000303C6", "cut it out" });
entries.push_back({"03CF00A503330129034802E20066000303C603DE0006039F0213", "come on lets go" });
entries.push_back({"02E20066000303C603DE0006039F0213", "lets go" });
entries.push_back({"031B0225012F03F0", "we re off" });
entries.push_back({"03BA008700060393030902190045000303C6", "tag youre it" });
entries.push_back({"03CF00C9000303B70045000303C301F2000303C6", "cut it out" });
entries.push_back({"0411031B00A8000303C603FC02FD0129035A", "whats wrong" });
entries.push_back({"0411031B00A8000303B7004803F90045000303C6", "what is it" });
entries.push_back({"03CF00C603330129034802E20066000303C603DE0006039F0213", "come on lets go" });
entries.push_back({"031502970006039F01F80042035A034501F2", "were going now" });
entries.push_back({"02E20066000303C603FC000303600066000303C90045000303C301F2000303C6", "lets check it out" });
entries.push_back({"03F600C6033F02370402014D000303D8", "thunder shock" });
entries.push_back({"03F600C6033F02340006037B020A02EE000303C6", "thunderbolt" });
entries.push_back({"043801290339030300420348", "onion" });
entries.push_back({"03FC02DF0024000303B4000303C301B0000303C6", "sleep tight" });
entries.push_back({"03F90009030C00EA000303C000E7033302460213", "see you tomorrow" });
entries.push_back({"03F90009030C00CF00420348036C00C6033302D603390042035A", "see you in the morning" });
entries.push_back({"039F0213000303BD00C6033302460213", "go tomorrow" });
entries.push_back({"02FD014D000303D8", "rock" });
entries.push_back({"03F9004803DE023703FC", "scissors" });
entries.push_back({"03A8018F000303AB0234", "paper" });
entries.push_back({"0381002A000303B10255000303C6", "depart" });
entries.push_back({"02F10006038100EA03DE00030384002A000303B10255000303C6", "reduced depart" });
entries.push_back({"03D5012F035D0063034800030381002A000303B10255000303C6", "caution depart" });
entries.push_back({"02DF03FC03BD023A000603D8000303B700060381002A000303B10255000303C6", "restricted depart" });
entries.push_back({"03B1008A03FC0042035A", "passing" });
entries.push_back({"03FC000303C3014D000303AB0042035A", "stopping" });
entries.push_back({"031E02DC03390042035A", "warning" });
entries.push_back({"03AB02FA021603F9000900060390", "proceed" });
entries.push_back({"02F10006038100EA03DE00060390", "reduced" });
entries.push_back({"03D5012F035D00630348", "caution" });
entries.push_back({"02DF03FC03BD023A000603D8000303B700060390", "restricted" });
entries.push_back({"042C0066000603A203FC000303AB021C005A03DE", "express" });
entries.push_back({"02E50042032A002A000303C6", "limit" });
entries.push_back({"03450213000602E50042032A002A000303C6", "no limit" });
entries.push_back({"03B7005A0348", "ten" });
entries.push_back({"03E7002A03F6000303B700090348", "fifteen" });
entries.push_back({"03C30318004B0339038A0024", "twenty" });
entries.push_back({"03C30318004B0339038A002403EA019E03EA", "twenty five" });
entries.push_back({"036C02AC03BA0027", "thirty" });
entries.push_back({"036C02AC03BA002703EA019E03EA", "thirty five" });
entries.push_back({"03EA02D6000603900048", "forty" });
entries.push_back({"03EA02D600060390004803EA019E03EA", "forty five" });
entries.push_back({"03F3005A03F0000303B70042", "fifty" });
entries.push_back({"03F3005A03F0000303B7004203EA019E03EA", "fifty five" });
entries.push_back({"03F9002A000303D803FC000303C00009", "sixty" });
entries.push_back({"03F9002A000303D803FC000303C0000903EA019E03EA", "sixty five" });
entries.push_back({"03FC004B036C00630348000303B70009", "seventy" });
entries.push_back({"03FC004B036C00630348000303B7000903EA019E03EA", "seventy five" });
entries.push_back({"042C018C03B70009", "eighty" });
entries.push_back({"042C018C03B7000903EA019E03EA", "eighty five" });
entries.push_back({"034501A103480006038A0048", "ninety" });
entries.push_back({"034501A103480006038A004803EA019E03EA", "ninety five" });
entries.push_back({"031B00C60348040B00BD0348038702F100060390", "one hundred" });
entries.push_back({"031B00C60348021303F001AD03E7", "one oh five" });
entries.push_back({"031B00C60348000303B7005A0348", "one ten" });
entries.push_back({"031B00C60348000303E7002A03F6000303B700090348", "one fifteen" });
entries.push_back({"031B00C60348000303C303180348000303B70024", "one twenty" });
entries.push_back({"031B00C60348000303C303180348000303B7002403EA019E03EA", "one twenty five" });
entries.push_back({"82B582E382C182CF82C282B582F182B182A4", "depart" });
entries.push_back({"82B582E382C182CF82C282B082F182BB82AD", "reduced depart" });
entries.push_back({"82B582E382C182CF82C282BF82E382A482A2", "caution depart" });
entries.push_back({"82B582E382C182CF82C282AF82A282A982A2", "restricted depart" });
entries.push_back({"82C282A482A9", "passing" });
entries.push_back({"82C482A282B582E1", "stopping" });
entries.push_back({"82AF82A282D982A482A082A9", "warning" });
entries.push_back({"82B582F182B182A4", "proceed" });
entries.push_back({"82B082F182BB82AD", "reduced" });
entries.push_back({"82BF82E382A482A2", "caution" });
entries.push_back({"82AF82A282A982A2", "restricted" });
entries.push_back({"82C482A282B5", "stop" });
entries.push_back({"82B182A482BB82AD", "no limit" });
entries.push_back({"82B982A282B082F1", "limit" });
entries.push_back({"82A982A282B682E5", "cancel" });
entries.push_back({"82B682E382A4", "ten" });
entries.push_back({"82B682E382A482B2", "fifteen" });
entries.push_back({"82C982B682E382A4", "twenty" });
entries.push_back({"82C982B682E382A482B2", "twenty five" });
entries.push_back({"82B382F182B682E382A4", "thirty" });
entries.push_back({"82B382F182B682E382A482B2", "thirty five" });
entries.push_back({"82E682F182B682E382A4", "forty" });
entries.push_back({"82E682F182B682E382A482B2", "forty five" });
entries.push_back({"82B282B682E382A4", "fifty" });
entries.push_back({"82B282B682E382A482B2", "fifty five" });
entries.push_back({"82EB82AD82B682E382A4", "sixty" });
entries.push_back({"82EB82AD82B682E382A482B2", "sixty five" });
entries.push_back({"82C882C882B682E382A4", "seventy" });
entries.push_back({"82C882C882B682E382A482B2", "seventy five" });
entries.push_back({"82CD82BF82B682E382A4", "eighty" });
entries.push_back({"82CD82BF82B682E382A482B2", "eighty five" });
entries.push_back({"82AB82E382A482B682E382A4", "ninety" });
entries.push_back({"82AB82E382A482B682E382A482B2", "ninety five" });
entries.push_back({"82D082E182AD", "one hundred" });
entries.push_back({"82D082E182AD82B2", "one oh five" });
entries.push_back({"82D082E182AD82B682E382A4", "one ten" });
entries.push_back({"82D082E182AD82B682E382A482B2", "one fifteen" });
entries.push_back({"82D082E182AD82C982B682E382A4", "one twenty" });
entries.push_back({"82D082E182AD82C982B682E382A482B2", "one twenty five" });
return entries;
}
+24
View File
@@ -0,0 +1,24 @@
/*
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef VRU_WORDS_HPP
#define VRU_WORDS_HPP
#include <string>
#include <vector>
struct VRUWordEntry
{
std::string hex;
std::string words;
};
std::vector<VRUWordEntry> GetVRUWordEntries(void);
#endif // VRU_WORDS_HPP
+4 -3
View File
@@ -33,9 +33,10 @@ enum class N64ControllerButton
enum class InputDeviceType
{
None = -3,
Automatic = -2,
Keyboard = -1
EmulateVRU = -4,
None = -3,
Automatic = -2,
Keyboard = -1,
};
enum class InputType
+267 -12
View File
@@ -13,11 +13,16 @@
#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>
@@ -97,6 +102,54 @@ 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_Fullscreen_Pressed = false;
InputMapping Hotkey_Fullscreen;
};
//
@@ -106,6 +159,9 @@ struct InputProfile
// SDL thread
static Thread::SDLThread *l_SDLThread = nullptr;
// Hotkeys thread (for when paused)
static Thread::HotkeysThread *l_HotkeysThread = nullptr;
// input profiles
static InputProfile l_InputProfiles[NUM_CONTROLLERS];
@@ -253,6 +309,41 @@ 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_Fullscreen, section, SettingsID::Input_Hotkey_Fullscreen_Name, SettingsID::Input_Hotkey_Fullscreen_InputType, SettingsID::Input_Hotkey_Fullscreen_Data, SettingsID::Input_Hotkey_Fullscreen_ExtraData);
}
}
@@ -269,6 +360,7 @@ static void apply_controller_profiles(void)
{
InputProfile* profile = &l_InputProfiles[i];
int plugin = PLUGIN_NONE;
bool emulateVRU = (profile->DeviceNum == (int)InputDeviceType::EmulateVRU);
switch (profile->ControllerPak)
{
@@ -278,7 +370,7 @@ static void apply_controller_profiles(void)
case N64ControllerPak::RumblePak:
plugin = PLUGIN_RAW;
break;
case N64ControllerPak::TransferPak:
case N64ControllerPak::TransferPak:
plugin = PLUGIN_TRANSFER_PAK;
break;
default:
@@ -286,10 +378,26 @@ 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;
}
}
@@ -422,7 +530,7 @@ static void close_controllers(void)
}
}
static int get_button_state(InputProfile* profile, const InputMapping* inputMapping)
static int get_button_state(InputProfile* profile, const InputMapping* inputMapping, const bool allPressed = false)
{
int state = 0;
@@ -435,29 +543,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;
@@ -617,11 +766,78 @@ 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_Fullscreen, Hotkey_Fullscreen_Pressed, CoreToggleFullscreen(), );
#undef DEFINE_HOTKEY
return false;
}
static void sdl_init()
{
std::filesystem::path gameControllerDbPath;
for (const int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_VIDEO, SDL_INIT_HAPTIC})
for (const int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_AUDIO, SDL_INIT_VIDEO, SDL_INIT_HAPTIC})
{
if (!SDL_WasInit(subsystem))
{
@@ -636,7 +852,7 @@ void sdl_init()
SDL_GameControllerAddMappingsFromFile(gameControllerDbPath.string().c_str());
}
void sdl_quit()
static void sdl_quit()
{
for (const int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_HAPTIC})
{
@@ -663,6 +879,8 @@ EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Con
return M64ERR_SYSTEM_FAIL;
}
CoreSetupDebugCallbackMessage(DebugCallback, Context);
sdl_init();
l_SDLThread = new Thread::SDLThread(nullptr);
@@ -673,6 +891,9 @@ EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Con
l_InputProfiles[i].InputDevice.SetSDLThread(l_SDLThread);
}
l_HotkeysThread = new Thread::HotkeysThread(check_hotkeys, nullptr);
l_HotkeysThread->start();
load_settings();
return M64ERR_SUCCESS;
@@ -691,6 +912,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;
@@ -845,6 +1070,23 @@ EXPORT void CALL GetKeys(int Control, BUTTONS* Keys)
return;
}
#ifdef VRU
// when we're emulating the VRU,
// we need to check the mic state
if (profile->DeviceNum == (int)InputDeviceType::EmulateVRU)
{
if (GetVRUMicState())
{
Keys->Value = 0x0020;
}
else
{
Keys->Value = 0x0000;
}
return;
}
#endif // VRU
// check if device has been disconnected,
// if it has, try to open it again,
// only do this every 2 seconds to prevent lag
@@ -868,6 +1110,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);
@@ -930,13 +1180,18 @@ EXPORT void CALL ReadController(int Control, unsigned char *Command)
EXPORT int CALL RomOpen(void)
{
l_HotkeysThread->SetState(HotkeysThreadState::RomOpened);
return 1;
}
EXPORT void CALL RomClosed(void)
{
l_HotkeysThread->SetState(HotkeysThreadState::RomClosed);
l_HasControlInfo = false;
close_controllers();
#ifdef VRU
QuitVRU();
#endif // VRU
}
EXPORT void CALL SDL_KeyDown(int keymod, int keysym)
+5
View File
@@ -97,6 +97,11 @@ target_link_libraries(RMG
RMG-Core
)
# needed for dynamically linked RMG-Core
set_target_properties(RMG PROPERTIES
INSTALL_RPATH "$ORIGIN"
)
target_include_directories(RMG PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
+93 -48
View File
@@ -375,7 +375,18 @@ void MainWindow::updateUI(bool inEmulation, bool isPaused)
if (!settings.GoodName.empty())
{
this->setWindowTitle(QString::fromStdString(settings.GoodName) + QString(" - ") + this->ui_WindowTitle);
QString goodName = QString::fromStdString(settings.GoodName);
if (goodName.endsWith("(unknown rom)") ||
goodName.endsWith("(unknown disk)"))
{
std::filesystem::path romPath;
if (CoreGetRomPath(romPath))
{
goodName = QString::fromStdString(romPath.filename().string());
}
}
this->setWindowTitle(goodName + QString(" - ") + this->ui_WindowTitle);
}
this->ui_Widgets->setCurrentWidget(this->ui_Widget_OpenGL->GetWidget());
@@ -1349,30 +1360,20 @@ void MainWindow::on_Action_System_SpeedFactor(int factor)
{
this->showErrorMessage("CoreSetSpeedFactor() Failed!", QString::fromStdString(CoreGetError()));
}
else
{
OnScreenDisplaySetMessage("Playback speed: " + std::to_string(CoreGetSpeedFactor()) + "%");
}
}
void MainWindow::on_Action_System_SaveState(void)
{
this->ui_ManuallySavedState = true;
if (!CoreSaveState())
{
this->ui_ManuallySavedState = false;
this->showErrorMessage("CoreSaveState() Failed", QString::fromStdString(CoreGetError()));
}
else
{
OnScreenDisplaySetMessage("Saved state to slot: " + std::to_string(CoreGetSaveStateSlot()));
// refresh savestate slot times in 1 second,
// kill any existing timers
if (this->ui_UpdateSaveStateSlotTimerId != 0)
{
this->killTimer(this->ui_UpdateSaveStateSlotTimerId);
this->ui_UpdateSaveStateSlotTimerId = 0;
}
this->ui_UpdateSaveStateSlotTimerId = this->startTimer(1000);
}
}
@@ -1390,8 +1391,11 @@ void MainWindow::on_Action_System_SaveAs(void)
if (!fileName.isEmpty())
{
this->ui_ManuallySavedState = true;
if (!CoreSaveState(fileName.toStdU32String()))
{
this->ui_ManuallySavedState = false;
this->showErrorMessage("CoreSaveState() Failed", QString::fromStdString(CoreGetError()));
}
else
@@ -1408,8 +1412,11 @@ void MainWindow::on_Action_System_SaveAs(void)
void MainWindow::on_Action_System_LoadState(void)
{
this->ui_ManuallyLoadedState = true;
if (!CoreLoadSaveState())
{
this->ui_ManuallyLoadedState = false;
this->showErrorMessage("CoreLoadSaveState() Failed", QString::fromStdString(CoreGetError()));
}
else
@@ -1429,12 +1436,15 @@ void MainWindow::on_Action_System_Load(void)
}
QString fileName =
QFileDialog::getOpenFileName(this, tr("Open Save State"), "", tr("Save State (*.dat *.state);;All Files (*)"));
QFileDialog::getOpenFileName(this, tr("Open Save State"), "", tr("Save State (*.dat *.state *.st* *.pj*);;All Files (*)"));
if (!fileName.isEmpty())
{
this->ui_ManuallyLoadedState = true;
if (!CoreLoadSaveState(fileName.toStdU32String()))
{
this->ui_ManuallyLoadedState = false;
this->showErrorMessage("CoreLoadSaveState() Failed", QString::fromStdString(CoreGetError()));
}
else
@@ -1459,29 +1469,6 @@ void MainWindow::on_Action_System_CurrentSaveState(int slot)
{
this->showErrorMessage("CoreSetSaveStateSlot() Failed", QString::fromStdString(CoreGetError()));
}
else
{
slotAction = this->ui_SlotActions[slot];
dateTimeText = this->getSaveStateSlotDateTimeText(slotAction);
// construct OSD message
message = "Selected save slot: " + std::to_string(slot);
// add date and time when available
if (!dateTimeText.isEmpty())
{
message += " [";
message += dateTimeText.toStdString();
message += "]";
}
else
{
message += " [N/A]";
}
// display message
OnScreenDisplaySetMessage(message);
}
}
void MainWindow::on_Action_System_Cheats(void)
@@ -2149,18 +2136,76 @@ void MainWindow::on_Core_DebugCallback(CoreDebugMessageType type, QString contex
void MainWindow::on_Core_StateCallback(CoreStateCallbackType type, int value)
{
if (type == CoreStateCallbackType::SaveStateLoaded)
switch (type)
{
if (value == 0)
default:
break;
case CoreStateCallbackType::EmulationState:
{
OnScreenDisplaySetMessage("Failed to load save state.");
}
}
else if (type == CoreStateCallbackType::SaveStateSaved)
{
if (value == 0)
this->action_System_Pause->setChecked(value == (int)CoreEmulationState::Paused);
} break;
case CoreStateCallbackType::SaveStateSlot:
{
OnScreenDisplaySetMessage("Failed to save state.");
}
QAction* slotAction = this->ui_SlotActions[value];
QString dateTimeText = this->getSaveStateSlotDateTimeText(slotAction);
std::string message = "Selected save slot: " + std::to_string(value);
// add date and time when available
if (!dateTimeText.isEmpty())
{
message += " [";
message += dateTimeText.toStdString();
message += "]";
}
else
{
message += " [N/A]";
}
// display message
OnScreenDisplaySetMessage(message);
// update UI
this->ui_SlotActions[value]->setChecked(true);
} break;
case CoreStateCallbackType::SpeedFactor:
{
OnScreenDisplaySetMessage("Playback speed: " + std::to_string(value) + "%");
} break;
case CoreStateCallbackType::SaveStateLoaded:
{
if (value == 0)
{
OnScreenDisplaySetMessage("Failed to load save state.");
}
else if (!this->ui_ManuallyLoadedState)
{
OnScreenDisplaySetMessage("Loaded save state.");
}
this->ui_ManuallyLoadedState = false;
} break;
case CoreStateCallbackType::SaveStateSaved:
{
if (value == 0)
{
OnScreenDisplaySetMessage("Failed to save state.");
}
else if (!this->ui_ManuallySavedState)
{
OnScreenDisplaySetMessage("Saved state.");
}
// refresh savestate slot times in 1 second,
// kill any existing timers
if (this->ui_UpdateSaveStateSlotTimerId != 0)
{
this->killTimer(this->ui_UpdateSaveStateSlotTimerId);
this->ui_UpdateSaveStateSlotTimerId = 0;
}
this->ui_UpdateSaveStateSlotTimerId = this->startTimer(1000);
this->ui_ManuallySavedState = false;
} break;
}
}
+3
View File
@@ -80,6 +80,9 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
bool ui_ManuallyPaused = true;
bool ui_ManuallySavedState = false;
bool ui_ManuallyLoadedState = false;
QList<QAction*> ui_Actions;
bool ui_AddedActions = false;
+1 -1
View File
@@ -128,7 +128,7 @@ static m64p_error VidExt_SetMode(int Width, int Height, int BitsPerPixel, int Sc
static m64p_error VidExt_SetModeWithRate(int Width, int Height, int RefreshRate, int BitsPerPixel, int ScreenMode, int Flags)
{
return VidExt_SetMode(Width, Height, BitsPerPixel, ScreenMode, Flags);
return M64ERR_UNSUPPORTED;
}
static m64p_function VidExt_GLGetProc(const char *Proc)
+8
View File
@@ -121,9 +121,11 @@ int main(int argc, char **argv)
parser.addVersionOption();
// custom options
#ifndef PORTABLE_INSTALL
QCommandLineOption libPathOption("lib-path", "Changes the path where the libraries are stored", "path");
QCommandLineOption corePathOption("core-path", "Changes the path where the core library is stored", "path");
QCommandLineOption pluginPathOption("plugin-path", "Changes the path where the plugins are stored", "path");
QCommandLineOption sharedDataPathOption("shared-data-path", "Changes the path where the shared data is stored", "path");
libPathOption.setFlags(QCommandLineOption::HiddenFromHelp);
corePathOption.setFlags(QCommandLineOption::HiddenFromHelp);
pluginPathOption.setFlags(QCommandLineOption::HiddenFromHelp);
sharedDataPathOption.setFlags(QCommandLineOption::HiddenFromHelp);
@@ -135,6 +137,7 @@ int main(int argc, char **argv)
QCommandLineOption diskOption("disk", "64DD Disk to open ROM in combination with", "64DD Disk");
#ifndef PORTABLE_INSTALL
parser.addOption(libPathOption);
parser.addOption(corePathOption);
parser.addOption(pluginPathOption);
parser.addOption(sharedDataPathOption);
@@ -151,9 +154,14 @@ int main(int argc, char **argv)
#ifndef PORTABLE_INSTALL
// set path overrides before initializing
QString libPathOverride = parser.value(libPathOption);
QString corePathOveride = parser.value(corePathOption);
QString pluginPathOverride = parser.value(pluginPathOption);
QString sharedDataPathOverride = parser.value(sharedDataPathOption);
if (!libPathOverride.isEmpty())
{
CoreSetLibraryPathOverride(libPathOverride.toStdString());
}
if (!corePathOveride.isEmpty())
{
CoreSetCorePathOverride(corePathOveride.toStdString());