UI: Add configurable hotkeys + a new fast forward hotkey (#1519)

This commit is contained in:
AnimeGIF 2025-07-08 00:55:57 +03:00 committed by GitHub
parent e68c31e5fb
commit cdca5eaf78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 619 additions and 8 deletions

View file

@ -354,6 +354,15 @@ void CemuConfig::Load(XMLConfigParser& parser)
dsu_client.host = dsuc.get_attribute("host", dsu_client.host);
dsu_client.port = dsuc.get_attribute("port", dsu_client.port);
// hotkeys
auto xml_hotkeys = parser.get("Hotkeys");
hotkeys.modifiers = xml_hotkeys.get("modifiers", sHotkeyCfg{});
hotkeys.exitFullscreen = xml_hotkeys.get("ExitFullscreen", sHotkeyCfg{uKeyboardHotkey{WXK_ESCAPE}});
hotkeys.toggleFullscreen = xml_hotkeys.get("ToggleFullscreen", sHotkeyCfg{uKeyboardHotkey{WXK_F11}});
hotkeys.toggleFullscreenAlt = xml_hotkeys.get("ToggleFullscreenAlt", sHotkeyCfg{uKeyboardHotkey{WXK_CONTROL_M, true}}); // ALT+ENTER
hotkeys.takeScreenshot = xml_hotkeys.get("TakeScreenshot", sHotkeyCfg{uKeyboardHotkey{WXK_F12}});
hotkeys.toggleFastForward = xml_hotkeys.get("ToggleFastForward", sHotkeyCfg{});
// emulatedusbdevices
auto usbdevices = parser.get("EmulatedUsbDevices");
emulated_usb_devices.emulate_skylander_portal = usbdevices.get("EmulateSkylanderPortal", emulated_usb_devices.emulate_skylander_portal);
@ -557,6 +566,15 @@ void CemuConfig::Save(XMLConfigParser& parser)
dsuc.set_attribute("host", dsu_client.host);
dsuc.set_attribute("port", dsu_client.port);
// hotkeys
auto xml_hotkeys = config.set("Hotkeys");
xml_hotkeys.set("modifiers", hotkeys.modifiers);
xml_hotkeys.set("ExitFullscreen", hotkeys.exitFullscreen);
xml_hotkeys.set("ToggleFullscreen", hotkeys.toggleFullscreen);
xml_hotkeys.set("ToggleFullscreenAlt", hotkeys.toggleFullscreenAlt);
xml_hotkeys.set("TakeScreenshot", hotkeys.takeScreenshot);
xml_hotkeys.set("ToggleFastForward", hotkeys.toggleFastForward);
// emulated usb devices
auto usbdevices = config.set("EmulatedUsbDevices");
usbdevices.set("EmulateSkylanderPortal", emulated_usb_devices.emulate_skylander_portal.GetValue());

View file

@ -191,6 +191,50 @@ enum class CrashDump
ENABLE_ENUM_ITERATORS(CrashDump, CrashDump::Disabled, CrashDump::Enabled);
#endif
typedef union
{
struct
{
uint16 key : 13; // enough bits for all keycodes
uint16 alt : 1;
uint16 ctrl : 1;
uint16 shift : 1;
};
uint16 raw;
} uKeyboardHotkey;
typedef sint16 ControllerHotkey_t;
struct sHotkeyCfg
{
static constexpr uint8 keyboardNone{WXK_NONE};
static constexpr sint8 controllerNone{-1}; // no enums to work with, but buttons start from 0
uKeyboardHotkey keyboard{keyboardNone};
ControllerHotkey_t controller{controllerNone};
/* for defaults */
sHotkeyCfg(const uKeyboardHotkey& keyboard = {WXK_NONE}, const ControllerHotkey_t& controller = {-1}) :
keyboard(keyboard), controller(controller) {};
/* for reading from xml */
sHotkeyCfg(const char* xml_values)
{
std::istringstream iss(xml_values);
iss >> keyboard.raw >> controller;
}
};
template <>
struct fmt::formatter<sHotkeyCfg> : formatter<string_view>
{
template <typename FormatContext>
auto format(const sHotkeyCfg c, FormatContext &ctx) const {
std::string xml_values = fmt::format("{} {}", c.keyboard.raw, c.controller);
return formatter<string_view>::format(xml_values, ctx);
}
};
template <>
struct fmt::formatter<PrecompiledShaderOption> : formatter<string_view> {
template <typename FormatContext>
@ -499,6 +543,17 @@ struct CemuConfig
ConfigValue<uint16> port{ 26760 };
}dsu_client{};
// hotkeys
struct
{
sHotkeyCfg modifiers;
sHotkeyCfg toggleFullscreen;
sHotkeyCfg toggleFullscreenAlt;
sHotkeyCfg exitFullscreen;
sHotkeyCfg takeScreenshot;
sHotkeyCfg toggleFastForward;
} hotkeys{};
// debug
ConfigValueBounds<CrashDump> crash_dump{ CrashDump::Disabled };
ConfigValue<uint16> gdb_port{ 1337 };

View file

@ -7,6 +7,9 @@
#include <string>
#include <mutex>
template <typename T>
concept HasConstCharConstructor = requires { T(std::declval<const char*>()); };
class XMLConfigParser
{
public:
@ -43,7 +46,7 @@ public:
return element->Int64Text(default_value);
else if constexpr (std::is_same_v<T, uint64>) // doesnt support real uint64...
return (uint64)element->Int64Text((sint64)default_value);
else if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, std::string>)
else if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, std::string> || HasConstCharConstructor<T>)
{
const char* text = element->GetText();
return text ? text : default_value;