From 81e0f143cc602a851c9e86e7dc937d288645f64c Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sat, 12 Oct 2024 14:04:18 +0200 Subject: [PATCH 01/79] added support for loading keyboard config from file --- src/sdl_window.cpp | 422 ++++++++++++++++++++++++++++++++++- src/sdl_window.h | 2 + user/keyboardInputConfig.ini | 57 +++++ 3 files changed, 479 insertions(+), 2 deletions(-) create mode 100644 user/keyboardInputConfig.ini diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index bf29b37f685..980c75e386e 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -20,8 +20,328 @@ namespace Frontend { -WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_, - std::string_view window_title) +bool KeyBinding::operator<(const KeyBinding& other) const { + return std::tie(key, modifier) < std::tie(other.key, other.modifier); +} + +// modifiers are bitwise or-d together, so we need to check if ours is in that +template +typename std::map::const_iterator FindKeyAllowingPartialModifiers(const std::map& map, KeyBinding binding) { + for (typename std::map::const_iterator it = map.cbegin(); it != map.cend(); it++) { + if ((it->first.key == binding.key) && (it->first.modifier & binding.modifier) != 0) { + return it; + } + } + return map.end(); // Return end if no match is found +} +template +typename std::map::const_iterator FindKeyAllowingOnlyNoModifiers(const std::map& map, KeyBinding binding) { + for (typename std::map::const_iterator it = map.cbegin(); it != map.cend(); it++) { + if (it->first.key == binding.key && it->first.modifier == SDL_KMOD_NONE) { + return it; + } + } + return map.end(); // Return end if no match is found +} + +// Axis map: maps key+modifier to controller axis and axis value +struct AxisMapping { + Input::Axis axis; + int value; // Value to set for key press (+127 or -127 for movement) +}; + + +// i strongly suggest you collapse these maps +std::map string_to_cbutton_map = { + {"triangle", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE}, + {"circle", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE}, + {"cross", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS}, + {"square", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE}, + {"l1", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1}, + {"l2", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2}, + {"r1", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1}, + {"r2", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2}, + {"l3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3}, + {"r3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3}, + {"options", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS}, + {"touchpad", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD}, + {"up", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP}, + {"down", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN}, + {"left", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT}, + {"right", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT} +}; +std::map string_to_axis_map = { + {"axis_left_x_plus", {Input::Axis::LeftX, 127}}, + {"axis_left_x_minus", {Input::Axis::LeftX, -127}}, + {"axis_left_y_plus", {Input::Axis::LeftY, 127}}, + {"axis_left_y_minus", {Input::Axis::LeftY, -127}}, + {"axis_right_x_plus", {Input::Axis::RightX, 127}}, + {"axis_right_x_minus", {Input::Axis::RightX, -127}}, + {"axis_right_y_plus", {Input::Axis::RightY, 127}}, + {"axis_right_y_minus", {Input::Axis::RightY, -127}}, +}; +std::map string_to_keyboard_key_map = { + {"a", SDLK_A}, + {"b", SDLK_B}, + {"c", SDLK_C}, + {"d", SDLK_D}, + {"e", SDLK_E}, + {"f", SDLK_F}, + {"g", SDLK_G}, + {"h", SDLK_H}, + {"i", SDLK_I}, + {"j", SDLK_J}, + {"k", SDLK_K}, + {"l", SDLK_L}, + {"m", SDLK_M}, + {"n", SDLK_N}, + {"o", SDLK_O}, + {"p", SDLK_P}, + {"q", SDLK_Q}, + {"r", SDLK_R}, + {"s", SDLK_S}, + {"t", SDLK_T}, + {"u", SDLK_U}, + {"v", SDLK_V}, + {"w", SDLK_W}, + {"x", SDLK_X}, + {"y", SDLK_Y}, + {"z", SDLK_Z}, + {"0", SDLK_0}, + {"1", SDLK_1}, + {"2", SDLK_2}, + {"3", SDLK_3}, + {"4", SDLK_4}, + {"5", SDLK_5}, + {"6", SDLK_6}, + {"7", SDLK_7}, + {"8", SDLK_8}, + {"9", SDLK_9}, + {",", SDLK_COMMA}, + {".", SDLK_PERIOD}, + {"?", SDLK_QUESTION}, + {";", SDLK_SEMICOLON}, + {"-", SDLK_MINUS}, + {"_", SDLK_UNDERSCORE}, + {"(", SDLK_LEFTPAREN}, + {")", SDLK_RIGHTPAREN}, + {"[", SDLK_LEFTBRACKET}, + {"]", SDLK_RIGHTBRACKET}, + {"{", SDLK_LEFTBRACE}, + {"}", SDLK_RIGHTBRACE}, + {"\\", SDLK_BACKSLASH}, + {"/", SDLK_SLASH}, + {"enter", SDLK_RETURN}, + {"space", SDLK_SPACE}, + {"tab", SDLK_TAB}, + {"backspace", SDLK_BACKSPACE}, + {"escape", SDLK_ESCAPE}, + {"left", SDLK_LEFT}, + {"right", SDLK_RIGHT}, + {"up", SDLK_UP}, + {"down", SDLK_DOWN}, + {"lctrl", SDLK_LCTRL}, + {"rctrl", SDLK_RCTRL}, + {"lshift", SDLK_LSHIFT}, + {"rshift", SDLK_RSHIFT}, + {"lalt", SDLK_LALT}, + {"ralt", SDLK_RALT}, + {"lmeta", SDLK_LGUI}, + {"rmeta", SDLK_RGUI}, + {"lwin", SDLK_LGUI}, + {"rwin", SDLK_RGUI}, + {"leftbutton", SDL_BUTTON_LEFT}, + {"rightbutton", SDL_BUTTON_RIGHT}, + {"middlebutton", SDL_BUTTON_MIDDLE}, +}; +std::map string_to_keyboard_mod_key_map = { + {"lshift", SDL_KMOD_LSHIFT}, + {"rshift", SDL_KMOD_RSHIFT}, + {"lctrl", SDL_KMOD_LCTRL}, + {"rctrl", SDL_KMOD_RCTRL}, + {"lalt", SDL_KMOD_LALT}, + {"ralt", SDL_KMOD_RALT}, + {"shift", SDL_KMOD_SHIFT}, + {"ctrl", SDL_KMOD_CTRL}, + {"alt", SDL_KMOD_ALT}, + {"l_meta", SDL_KMOD_LGUI}, + {"r_meta", SDL_KMOD_RGUI}, + {"meta", SDL_KMOD_GUI}, + {"lwin", SDL_KMOD_LGUI}, + {"rwin", SDL_KMOD_RGUI}, + {"win", SDL_KMOD_GUI}, + {"none", SDL_KMOD_NONE}, // if you want to be fancy +}; + + +// Button map: maps key+modifier to controller button +std::map button_map = { + /* + //Taken keys: + //F11: fullscreen + //F10: Fps counter + //F9: toggle mouse capture + // use an other item (healing), change status in inv + {{SDLK_F, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE}, + // dodge, back in inv + {{SDLK_SPACE, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE}, + // interact, select item in inv + {{SDLK_E, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS}, + // use quick item, remove equipped item of change item desc in inv + {{SDLK_R, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE}, + + // arrow keys, but triggers normal wasd too (pls fix) + // emergency extra bullets + {{SDLK_W, SDL_KMOD_LALT}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP}, + // change quick item + {{SDLK_S, SDL_KMOD_LALT}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN}, + // change weapon in left + {{SDLK_a, SDL_KMOD_LALT}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT}, + // change weapon in right + {{SDLK_D, SDL_KMOD_LALT}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT}, + + // menu + {{SDLK_ESCAPE, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS}, + // gestures + {{SDLK_G, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD}, + + // transform + {{SDL_BUTTON_RIGHT, SDL_KMOD_LSHIFT}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1}, + // light attack + {{SDL_BUTTON_LEFT, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1}, + // shoot + {{SDL_BUTTON_RIGHT, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2}, + // heavy attack + {{SDL_BUTTON_LEFT, SDL_KMOD_LSHIFT}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2}, + + // does nothing + {{SDLK_X, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3}, + // center cam, lock on enemy + {{SDLK_Q, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3}, +*/ +}; +std::map axis_map = { + /* + // move + {{SDLK_A, SDL_KMOD_NONE}, {Input::Axis::LeftX, -127}}, + {{SDLK_D, SDL_KMOD_NONE}, {Input::Axis::LeftX, 127}}, + {{SDLK_W, SDL_KMOD_NONE}, {Input::Axis::LeftY, -127}}, + {{SDLK_S, SDL_KMOD_NONE}, {Input::Axis::LeftY, 127}}, + + //this is now using the mouse + {{SDLK_J, SDL_KMOD_NONE}, {Input::Axis::RightX, -127}}, + {{SDLK_L, SDL_KMOD_NONE}, {Input::Axis::RightX, 127}}, + {{SDLK_I, SDL_KMOD_NONE}, {Input::Axis::RightY, -127}}, + {{SDLK_K, SDL_KMOD_NONE}, {Input::Axis::RightY, 127}}, + */ +}; + +void WindowSDL::parseInputConfig(const std::string& filename) { + std::ifstream file(filename); + if (!file.is_open()) { + std::cerr << "Error opening file: " << filename << std::endl; + return; + } + + button_map.clear(); + axis_map.clear(); + int lineCount = 0; + std::string line; + while (std::getline(file, line)) { + lineCount++; + // Ignore comment lines + if (line.empty() || line[0] == '#') { + continue; + } + // Split the line by '=' + std::size_t equal_pos = line.find('='); + if (equal_pos == std::string::npos) { + std::cerr << "Invalid line format: " << line << std::endl; + continue; + } + + std::string controller_input = line.substr(0, equal_pos); + std::string kbm_input = line.substr(equal_pos + 1); + KeyBinding binding = {0, SDL_KMOD_NONE}; // Initialize KeyBinding + + // first we parse the binding, and if its wrong, we skip to the next line + std::size_t comma_pos = kbm_input.find(','); + if (comma_pos != std::string::npos) { + // Handle key + modifier + std::string key = kbm_input.substr(0, comma_pos); + std::string mod = kbm_input.substr(comma_pos + 1); + + auto key_it = string_to_keyboard_key_map.find(key); + auto mod_it = string_to_keyboard_mod_key_map.find(mod); + + if (key_it != string_to_keyboard_key_map.end() && mod_it != string_to_keyboard_mod_key_map.end()) { + binding.key = key_it->second; + binding.modifier = mod_it->second; + } else { + std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount << "\n"; + continue; // skip + } + } else { + // Just a key without modifier + auto key_it = string_to_keyboard_key_map.find(kbm_input); + if (key_it != string_to_keyboard_key_map.end()) { + binding.key = key_it->second; + } else { + std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount << "\n"; + continue; // skip + } + } + + // Check for axis mapping (example: axis_left_x_plus) + auto axis_it = string_to_axis_map.find(controller_input); + auto button_it = string_to_cbutton_map.find(controller_input); + if (axis_it != string_to_axis_map.end()) { + axis_map[binding] = axis_it->second; + } else if(button_it != string_to_cbutton_map.end()) { + button_map[binding] = button_it->second; + } else { + std::cerr << "Syntax error while parsing controller inputs at line " << lineCount << "\n"; + continue; // skip + } + } + file.close(); +} + +Uint32 WindowSDL::keyRepeatCallback(void* param, Uint32 id, Uint32 interval) { + auto* data = (std::pair*)param; + KeyBinding binding = { data->second->key.key, SDL_GetModState() }; + data->first->updateModKeyedInputsManually(binding); + //data->first->onKeyPress(data->second); + delete data->second; + delete data; + return 0; // Return 0 to stop the timer after firing once +} +Uint32 WindowSDL::mousePolling(void* param, Uint32 id, Uint32 interval) { + auto* data = (WindowSDL*)param; + data->updateMouse(); + return 33; // Return 0 to stop the timer after firing once +} + +void WindowSDL::updateMouse() { + float d_x = 0, d_y = 0; + SDL_GetRelativeMouseState(&d_x, &d_y); + //std::cout << "mouse polling yay!\n" << d_x << " " << d_y <<"\n"; + + float angle = atan2(d_y, d_x); + float a_x = cos(angle) * 128.0, a_y = sin(angle) * 128.0; + + if (d_x != 0 && d_y != 0) { + controller->Axis(0, Input::Axis::RightX, Input::GetAxis(-0x80, 0x80, a_x)); + controller->Axis(0, Input::Axis::RightY, Input::GetAxis(-0x80, 0x80, a_y)); + } else { + controller->Axis(0, Input::Axis::RightX, Input::GetAxis(-0x80, 0x80, 0)); + controller->Axis(0, Input::Axis::RightY, Input::GetAxis(-0x80, 0x80, 0)); + } +} + + + +WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_, std::string_view window_title) : width{width_}, height{height_}, controller{controller_} { if (!SDL_Init(SDL_INIT_VIDEO)) { UNREACHABLE_MSG("Failed to initialize SDL video subsystem: {}", SDL_GetError()); @@ -70,6 +390,11 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_ window_info.type = WindowSystemType::Metal; window_info.render_surface = SDL_Metal_GetLayer(SDL_Metal_CreateView(window)); #endif +<<<<<<< HEAD +======= + // initialize kbm controls + parseInputConfig("user/keyboardInputConfig.ini"); +>>>>>>> f031c7e1 (added support for loading keyboard config from file) } WindowSDL::~WindowSDL() = default; @@ -143,6 +468,7 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { u32 button = 0; Input::Axis axis = Input::Axis::AxisMax; +<<<<<<< HEAD int axisvalue = 0; int ax = 0; std::string backButtonBehavior = Config::getBackButtonBehavior(); @@ -313,6 +639,98 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { if (axis != Input::Axis::AxisMax) { controller->Axis(0, axis, ax); } +======= + int axis_value = 0; + + // Handle window controls outside of the input maps + if (event->type == SDL_EVENT_KEY_DOWN) { + // Toggle capture of the mouse + if (binding.key == SDLK_F9) { + SDL_SetWindowRelativeMouseMode(this->GetSdlWindow(), !SDL_GetWindowRelativeMouseMode(this->GetSdlWindow())); + } + // Reparse kbm inputs + if (binding.key == SDLK_F8) { + parseInputConfig("user/keyboardInputConfig.ini"); + } + // Toggle fullscreen + if (binding.key == SDLK_F11) { + SDL_WindowFlags flag = SDL_GetWindowFlags(window); + bool is_fullscreen = flag & SDL_WINDOW_FULLSCREEN; + SDL_SetWindowFullscreen(window, !is_fullscreen); + } + // Trigger rdoc capture + if (binding.key == SDLK_F12) { + VideoCore::TriggerCapture(); + } + } + + + // Check if the current key+modifier is a button mapping + bool button_found = false; + auto button_it = FindKeyAllowingPartialModifiers(button_map, binding); + if (button_it == button_map.end()) { + button_it = FindKeyAllowingOnlyNoModifiers(button_map, binding); + } + if (button_it != button_map.end()) { + button_found = true; + button = button_it->second; + WindowSDL::updateButton(binding, button, event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_MOUSE_BUTTON_DOWN); + } + // Check if the current key+modifier is an axis mapping + auto axis_it = FindKeyAllowingPartialModifiers(axis_map, binding); + if (axis_it == axis_map.end() && !button_found) { + axis_it = FindKeyAllowingOnlyNoModifiers(axis_map, binding); + } + if (axis_it != axis_map.end()) { + axis = axis_it->second.axis; + axis_value = (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) ? axis_it->second.value : 0; + int ax = Input::GetAxis(-0x80, 0x80, axis_value); + controller->Axis(0, axis, ax); + } + + +} + +// if we don't do this, then if we activate a mod keyed input and let go of the mod key first, +// the button will be stuck on the "on" state becuse the "turn off" signal would only come from +// the other key being unpressed +void WindowSDL::updateModKeyedInputsManually(Frontend::KeyBinding& binding) { + bool mod_keyed_input_found = false; + for (auto input : button_map) { + if (input.first.modifier != SDL_KMOD_NONE) { + if ((input.first.modifier & binding.modifier) == 0) { + WindowSDL::updateButton(binding, input.second, false); + } else { + mod_keyed_input_found = true; + } + } + } + for (auto input : axis_map) { + if (input.first.modifier != SDL_KMOD_NONE) { + if((input.first.modifier & binding.modifier) == 0) { + controller->Axis(0, input.second.axis, Input::GetAxis(-0x80, 0x80, 0)); + } else { + mod_keyed_input_found = true; + } + } + } + // if both non mod keyed and mod keyed inputs are used and you press the key and then the mod key in a single frame, + // both will activate but the simple one will not deactivate, unless i use this stupid looking workaround + //return; + if(!mod_keyed_input_found) return; // in this case the fix for the fix for the wrong update order is not needed + for(auto input : button_map) { + if(input.first.modifier == SDL_KMOD_NONE) { + WindowSDL::updateButton(binding, input.second, false); + } + } + for(auto input : axis_map) { + if(input.first.modifier == SDL_KMOD_NONE) { + controller->Axis(0, input.second.axis, Input::GetAxis(-0x80, 0x80, 0)); + } + } + // also this sometimes leads to janky inputs but whoever decides to intentionally create a state where this is needed + // should not deserve a smooth experience anyway +>>>>>>> f031c7e1 (added support for loading keyboard config from file) } void WindowSDL::onGamepadEvent(const SDL_Event* event) { diff --git a/src/sdl_window.h b/src/sdl_window.h index 2a5aeb38c05..a178ac87fd1 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -75,6 +75,8 @@ class WindowSDL { int sdlGamepadToOrbisButton(u8 button); + void parseInputConfig(const std::string& filename); + private: s32 width; s32 height; diff --git a/user/keyboardInputConfig.ini b/user/keyboardInputConfig.ini new file mode 100644 index 00000000000..60b29f5d1ac --- /dev/null +++ b/user/keyboardInputConfig.ini @@ -0,0 +1,57 @@ +# controller button mappings + +# taken keys: +# f11: fullscreen +# f10: fps counter +# f9: toggle mouse capture +# f8: reparse keyboard input (this) + +# use another item (healing), change status in inventory +triangle=f +# dodge, back in inv +circle=space +# interact, select item in inv +cross=e +# use quick item, remove item in inv +square=r + +# arrow keys, but triggers normal wasd too (please fix) +# emergency extra bullets +up=w,lalt +# change quick item +down=s,lalt +# change weapon in left hand +left=a,lalt +# change weapon in right hand +right=d,lalt + +# menu +options=escape +# gestures +touchpad=g + +# transform +l1=rightbutton,lshift +# shoot +r1=leftbutton +# light attack +l2=rightbutton +# heavy attack +r2=leftbutton,lshift + +# does nothing +l3=x +# center cam, lock on +r3=q + +# axis mappings +# move +axis_left_x_minus=a +axis_left_x_plus=d +axis_left_y_minus=w +axis_left_y_plus=s +# og cam input +# axis_right_x_minus=j +# axis_right_x_plus=l +# axis_right_y_minus=i +# axis_right_y_plus=k From 94c076494ae4d3061a57959eb90c3b3dbad3054d Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sat, 12 Oct 2024 15:41:18 +0200 Subject: [PATCH 02/79] final minor update before pull request --- src/sdl_window.cpp | 9 +++------ user/keyboardInputConfig.ini | 3 ++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 980c75e386e..8ec6f85ec22 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -242,7 +242,7 @@ void WindowSDL::parseInputConfig(const std::string& filename) { std::cerr << "Error opening file: " << filename << std::endl; return; } - + button_map.clear(); axis_map.clear(); int lineCount = 0; @@ -687,8 +687,6 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { int ax = Input::GetAxis(-0x80, 0x80, axis_value); controller->Axis(0, axis, ax); } - - } // if we don't do this, then if we activate a mod keyed input and let go of the mod key first, @@ -700,7 +698,7 @@ void WindowSDL::updateModKeyedInputsManually(Frontend::KeyBinding& binding) { if (input.first.modifier != SDL_KMOD_NONE) { if ((input.first.modifier & binding.modifier) == 0) { WindowSDL::updateButton(binding, input.second, false); - } else { + } else if(input.first.key == binding.key) { mod_keyed_input_found = true; } } @@ -709,14 +707,13 @@ void WindowSDL::updateModKeyedInputsManually(Frontend::KeyBinding& binding) { if (input.first.modifier != SDL_KMOD_NONE) { if((input.first.modifier & binding.modifier) == 0) { controller->Axis(0, input.second.axis, Input::GetAxis(-0x80, 0x80, 0)); - } else { + } else if(input.first.key == binding.key) { mod_keyed_input_found = true; } } } // if both non mod keyed and mod keyed inputs are used and you press the key and then the mod key in a single frame, // both will activate but the simple one will not deactivate, unless i use this stupid looking workaround - //return; if(!mod_keyed_input_found) return; // in this case the fix for the fix for the wrong update order is not needed for(auto input : button_map) { if(input.first.modifier == SDL_KMOD_NONE) { diff --git a/user/keyboardInputConfig.ini b/user/keyboardInputConfig.ini index 60b29f5d1ac..0500a163780 100644 --- a/user/keyboardInputConfig.ini +++ b/user/keyboardInputConfig.ini @@ -6,6 +6,8 @@ # f9: toggle mouse capture # f8: reparse keyboard input (this) +# this is a mapping for bloodborne inspired by other souls titles on pc + # use another item (healing), change status in inventory triangle=f # dodge, back in inv @@ -15,7 +17,6 @@ cross=e # use quick item, remove item in inv square=r -# arrow keys, but triggers normal wasd too (please fix) # emergency extra bullets up=w,lalt # change quick item From 37dcdcec3978b1350ac80212037fd8de87894b10 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sat, 12 Oct 2024 16:15:22 +0200 Subject: [PATCH 03/79] fix messing up the merge --- src/sdl_window.cpp | 254 +++++++++++---------------------------------- src/sdl_window.h | 22 +++- 2 files changed, 81 insertions(+), 195 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 8ec6f85ec22..ecb711f0217 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -1,10 +1,21 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +// new includes +#include +//#include +#include +#include +#include +#include +#include +#include + #include #include #include #include +#include #include "common/assert.h" #include "common/config.h" #include "common/version.h" @@ -19,6 +30,7 @@ #endif namespace Frontend { +using Libraries::Pad::OrbisPadButtonDataOffset; bool KeyBinding::operator<(const KeyBinding& other) const { return std::tie(key, modifier) < std::tie(other.key, other.modifier); @@ -390,19 +402,20 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_ window_info.type = WindowSystemType::Metal; window_info.render_surface = SDL_Metal_GetLayer(SDL_Metal_CreateView(window)); #endif -<<<<<<< HEAD -======= // initialize kbm controls parseInputConfig("user/keyboardInputConfig.ini"); ->>>>>>> f031c7e1 (added support for loading keyboard config from file) } WindowSDL::~WindowSDL() = default; - +Uint32 mouse_polling_id = 0; void WindowSDL::waitEvent() { // Called on main thread SDL_Event event; - + if(mouse_polling_id == 0) { + // mouse polling + //std::cout << "Why are we adding new timers?\n\n"; + mouse_polling_id = SDL_AddTimer(33, mousePolling, (void*)this); + } if (!SDL_WaitEvent(&event)) { return; } @@ -410,6 +423,10 @@ void WindowSDL::waitEvent() { if (ImGui::Core::ProcessEvent(&event)) { return; } + SDL_Event* event_copy = new SDL_Event(); + *event_copy = event; + std::pair* payload_to_timer = + new std::pair(this, event_copy); switch (event.type) { case SDL_EVENT_WINDOW_RESIZED: @@ -424,6 +441,9 @@ void WindowSDL::waitEvent() { break; case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: + SDL_AddTimer(33, keyRepeatCallback, (void*)payload_to_timer); // this is intentional passthrough + case SDL_EVENT_MOUSE_BUTTON_UP: + case SDL_EVENT_MOUSE_BUTTON_DOWN: onKeyPress(&event); break; case SDL_EVENT_GAMEPAD_BUTTON_DOWN: @@ -443,203 +463,50 @@ void WindowSDL::waitEvent() { break; } } - void WindowSDL::onResize() { SDL_GetWindowSizeInPixels(window, &width, &height); ImGui::Core::OnResize(); } -void WindowSDL::onKeyPress(const SDL_Event* event) { - using Libraries::Pad::OrbisPadButtonDataOffset; +void WindowSDL::updateButton(KeyBinding& binding, u32 button, bool is_pressed) { + float x; + Input::Axis axis; + switch(button) { + case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2: + case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2: + axis = (button == OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2) ? + Input::Axis::TriggerRight : Input::Axis::TriggerLeft; + //int axis_value = is_pressed ? 255 : 0; + //int ax = Input::GetAxis(0, 0x80, is_pressed ? 255 : 0); + controller->Axis(0, axis, Input::GetAxis(0, 0x80, is_pressed ? 255 : 0)); + break; + case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD: + x = Config::getBackButtonBehavior() == "left" ? 0.25f + : Config::getBackButtonBehavior() == "right" ? 0.75f : 0.5f; + controller->SetTouchpadState(0, true, x, 0.5f); + //button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD; + controller->CheckButton(0, button, is_pressed); + break; + default: // is a normal key + controller->CheckButton(0, button, is_pressed); + break; + } +} -#ifdef __APPLE__ - // Use keys that are more friendly for keyboards without a keypad. - // Once there are key binding options this won't be necessary. - constexpr SDL_Keycode CrossKey = SDLK_N; - constexpr SDL_Keycode CircleKey = SDLK_B; - constexpr SDL_Keycode SquareKey = SDLK_V; - constexpr SDL_Keycode TriangleKey = SDLK_C; -#else - constexpr SDL_Keycode CrossKey = SDLK_KP_2; - constexpr SDL_Keycode CircleKey = SDLK_KP_6; - constexpr SDL_Keycode SquareKey = SDLK_KP_4; - constexpr SDL_Keycode TriangleKey = SDLK_KP_8; -#endif +void WindowSDL::onKeyPress(const SDL_Event* event) { + // Extract key and modifier + KeyBinding binding = {0, SDL_GetModState()}; + if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) { + binding.key = event->key.key; // For keyboard events + } else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || event->type == SDL_EVENT_MOUSE_BUTTON_UP) { + binding.key = event->button.button; // For mouse button events + } else { + std::cout << "Bro something is very wrong with the waitevent switch case as this is the only 4 possible cases\n"; + return; + } u32 button = 0; Input::Axis axis = Input::Axis::AxisMax; -<<<<<<< HEAD - int axisvalue = 0; - int ax = 0; - std::string backButtonBehavior = Config::getBackButtonBehavior(); - switch (event->key.key) { - case SDLK_UP: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP; - break; - case SDLK_DOWN: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN; - break; - case SDLK_LEFT: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT; - break; - case SDLK_RIGHT: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT; - break; - case TriangleKey: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE; - break; - case CircleKey: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE; - break; - case CrossKey: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS; - break; - case SquareKey: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE; - break; - case SDLK_RETURN: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS; - break; - case SDLK_A: - axis = Input::Axis::LeftX; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += -127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_D: - axis = Input::Axis::LeftX; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += 127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_W: - axis = Input::Axis::LeftY; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += -127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_S: - axis = Input::Axis::LeftY; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += 127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_J: - axis = Input::Axis::RightX; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += -127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_L: - axis = Input::Axis::RightX; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += 127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_I: - axis = Input::Axis::RightY; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += -127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_K: - axis = Input::Axis::RightY; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += 127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_X: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3; - break; - case SDLK_M: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3; - break; - case SDLK_Q: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1; - break; - case SDLK_U: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1; - break; - case SDLK_E: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2; - axis = Input::Axis::TriggerLeft; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += 255; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(0, 0x80, axisvalue); - break; - case SDLK_O: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2; - axis = Input::Axis::TriggerRight; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += 255; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(0, 0x80, axisvalue); - break; - case SDLK_SPACE: - if (backButtonBehavior != "none") { - float x = backButtonBehavior == "left" ? 0.25f - : (backButtonBehavior == "right" ? 0.75f : 0.5f); - // trigger a touchpad event so that the touchpad emulation for back button works - controller->SetTouchpadState(0, true, x, 0.5f); - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD; - } else { - button = 0; - } - break; - case SDLK_F11: - if (event->type == SDL_EVENT_KEY_DOWN) { - { - SDL_WindowFlags flag = SDL_GetWindowFlags(window); - bool is_fullscreen = flag & SDL_WINDOW_FULLSCREEN; - SDL_SetWindowFullscreen(window, !is_fullscreen); - } - } - break; - case SDLK_F12: - if (event->type == SDL_EVENT_KEY_DOWN) { - // Trigger rdoc capture - VideoCore::TriggerCapture(); - } - break; - default: - break; - } - if (button != 0) { - controller->CheckButton(0, button, event->type == SDL_EVENT_KEY_DOWN); - } - if (axis != Input::Axis::AxisMax) { - controller->Axis(0, axis, ax); - } -======= int axis_value = 0; // Handle window controls outside of the input maps @@ -727,7 +594,6 @@ void WindowSDL::updateModKeyedInputsManually(Frontend::KeyBinding& binding) { } // also this sometimes leads to janky inputs but whoever decides to intentionally create a state where this is needed // should not deserve a smooth experience anyway ->>>>>>> f031c7e1 (added support for loading keyboard config from file) } void WindowSDL::onGamepadEvent(const SDL_Event* event) { diff --git a/src/sdl_window.h b/src/sdl_window.h index a178ac87fd1..ac18b718d49 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -6,6 +6,8 @@ #include #include "common/types.h" +#include + struct SDL_Window; struct SDL_Gamepad; union SDL_Event; @@ -16,6 +18,16 @@ class GameController; namespace Frontend { + +class KeyBinding { +public: + Uint32 key; + SDL_Keymod modifier; + KeyBinding(SDL_Keycode k, SDL_Keymod m) : key(k), modifier(m){}; + bool operator<(const KeyBinding& other) const; + ~KeyBinding(){}; +}; + enum class WindowSystemType : u8 { Headless, Windows, @@ -40,6 +52,8 @@ struct WindowSystemInfo { WindowSystemType type = WindowSystemType::Headless; }; + + class WindowSDL { public: explicit WindowSDL(s32 width, s32 height, Input::GameController* controller, @@ -67,14 +81,20 @@ class WindowSDL { } void waitEvent(); + void updateMouse(); private: + void onResize(); void onKeyPress(const SDL_Event* event); void onGamepadEvent(const SDL_Event* event); - int sdlGamepadToOrbisButton(u8 button); + void updateModKeyedInputsManually(KeyBinding& binding); + void updateButton(KeyBinding& binding, u32 button, bool isPressed); + static Uint32 keyRepeatCallback(void* param, Uint32 id, Uint32 interval); + static Uint32 mousePolling(void* param, Uint32 id, Uint32 interval); + void parseInputConfig(const std::string& filename); private: From f6d54bf75c28e60e9028fded421047cb6861d589 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sat, 12 Oct 2024 16:18:15 +0200 Subject: [PATCH 04/79] fix waitEvent to correctly handle mouse inputs --- src/sdl_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index ecb711f0217..c90d4951ca4 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -441,9 +441,9 @@ void WindowSDL::waitEvent() { break; case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: - SDL_AddTimer(33, keyRepeatCallback, (void*)payload_to_timer); // this is intentional passthrough case SDL_EVENT_MOUSE_BUTTON_UP: case SDL_EVENT_MOUSE_BUTTON_DOWN: + SDL_AddTimer(33, keyRepeatCallback, (void*)payload_to_timer); // this is intentional passthrough onKeyPress(&event); break; case SDL_EVENT_GAMEPAD_BUTTON_DOWN: From 3dda62fcba19135414ebaacd01d30e945f142e7a Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sat, 12 Oct 2024 17:12:14 +0200 Subject: [PATCH 05/79] add license --- user/keyboardInputConfig.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/user/keyboardInputConfig.ini b/user/keyboardInputConfig.ini index 0500a163780..25e7702ba18 100644 --- a/user/keyboardInputConfig.ini +++ b/user/keyboardInputConfig.ini @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + # controller button mappings # taken keys: From 98200221f59a656b218f3f781073e67c2762c399 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sat, 12 Oct 2024 17:28:52 +0200 Subject: [PATCH 06/79] Applied coding style fixes --- src/sdl_window.cpp | 159 ++++++++++++++++++----------------- src/sdl_window.h | 4 - user/keyboardInputConfig.ini | 126 +++++++++++++-------------- 3 files changed, 145 insertions(+), 144 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index c90d4951ca4..c88461d65c7 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -3,19 +3,18 @@ // new includes #include -//#include -#include -#include +// #include #include #include #include +#include #include #include #include #include -#include #include +#include #include "common/assert.h" #include "common/config.h" #include "common/version.h" @@ -37,32 +36,35 @@ bool KeyBinding::operator<(const KeyBinding& other) const { } // modifiers are bitwise or-d together, so we need to check if ours is in that -template -typename std::map::const_iterator FindKeyAllowingPartialModifiers(const std::map& map, KeyBinding binding) { - for (typename std::map::const_iterator it = map.cbegin(); it != map.cend(); it++) { +template +typename std::map::const_iterator FindKeyAllowingPartialModifiers( + const std::map& map, KeyBinding binding) { + for (typename std::map::const_iterator it = map.cbegin(); it != map.cend(); + it++) { if ((it->first.key == binding.key) && (it->first.modifier & binding.modifier) != 0) { return it; } } - return map.end(); // Return end if no match is found + return map.end(); // Return end if no match is found } -template -typename std::map::const_iterator FindKeyAllowingOnlyNoModifiers(const std::map& map, KeyBinding binding) { - for (typename std::map::const_iterator it = map.cbegin(); it != map.cend(); it++) { +template +typename std::map::const_iterator FindKeyAllowingOnlyNoModifiers( + const std::map& map, KeyBinding binding) { + for (typename std::map::const_iterator it = map.cbegin(); it != map.cend(); + it++) { if (it->first.key == binding.key && it->first.modifier == SDL_KMOD_NONE) { return it; } } - return map.end(); // Return end if no match is found + return map.end(); // Return end if no match is found } // Axis map: maps key+modifier to controller axis and axis value struct AxisMapping { Input::Axis axis; - int value; // Value to set for key press (+127 or -127 for movement) + int value; // Value to set for key press (+127 or -127 for movement) }; - // i strongly suggest you collapse these maps std::map string_to_cbutton_map = { {"triangle", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE}, @@ -80,8 +82,7 @@ std::map string_to_cbutton_map = { {"up", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP}, {"down", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN}, {"left", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT}, - {"right", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT} -}; + {"right", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT}}; std::map string_to_axis_map = { {"axis_left_x_plus", {Input::Axis::LeftX, 127}}, {"axis_left_x_minus", {Input::Axis::LeftX, -127}}, @@ -167,25 +168,14 @@ std::map string_to_keyboard_key_map = { {"middlebutton", SDL_BUTTON_MIDDLE}, }; std::map string_to_keyboard_mod_key_map = { - {"lshift", SDL_KMOD_LSHIFT}, - {"rshift", SDL_KMOD_RSHIFT}, - {"lctrl", SDL_KMOD_LCTRL}, - {"rctrl", SDL_KMOD_RCTRL}, - {"lalt", SDL_KMOD_LALT}, - {"ralt", SDL_KMOD_RALT}, - {"shift", SDL_KMOD_SHIFT}, - {"ctrl", SDL_KMOD_CTRL}, - {"alt", SDL_KMOD_ALT}, - {"l_meta", SDL_KMOD_LGUI}, - {"r_meta", SDL_KMOD_RGUI}, - {"meta", SDL_KMOD_GUI}, - {"lwin", SDL_KMOD_LGUI}, - {"rwin", SDL_KMOD_RGUI}, - {"win", SDL_KMOD_GUI}, + {"lshift", SDL_KMOD_LSHIFT}, {"rshift", SDL_KMOD_RSHIFT}, {"lctrl", SDL_KMOD_LCTRL}, + {"rctrl", SDL_KMOD_RCTRL}, {"lalt", SDL_KMOD_LALT}, {"ralt", SDL_KMOD_RALT}, + {"shift", SDL_KMOD_SHIFT}, {"ctrl", SDL_KMOD_CTRL}, {"alt", SDL_KMOD_ALT}, + {"l_meta", SDL_KMOD_LGUI}, {"r_meta", SDL_KMOD_RGUI}, {"meta", SDL_KMOD_GUI}, + {"lwin", SDL_KMOD_LGUI}, {"rwin", SDL_KMOD_RGUI}, {"win", SDL_KMOD_GUI}, {"none", SDL_KMOD_NONE}, // if you want to be fancy }; - // Button map: maps key+modifier to controller button std::map button_map = { /* @@ -211,7 +201,7 @@ std::map button_map = { {{SDLK_a, SDL_KMOD_LALT}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT}, // change weapon in right {{SDLK_D, SDL_KMOD_LALT}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT}, - + // menu {{SDLK_ESCAPE, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS}, // gestures @@ -274,7 +264,7 @@ void WindowSDL::parseInputConfig(const std::string& filename) { std::string controller_input = line.substr(0, equal_pos); std::string kbm_input = line.substr(equal_pos + 1); - KeyBinding binding = {0, SDL_KMOD_NONE}; // Initialize KeyBinding + KeyBinding binding = {0, SDL_KMOD_NONE}; // Initialize KeyBinding // first we parse the binding, and if its wrong, we skip to the next line std::size_t comma_pos = kbm_input.find(','); @@ -286,7 +276,8 @@ void WindowSDL::parseInputConfig(const std::string& filename) { auto key_it = string_to_keyboard_key_map.find(key); auto mod_it = string_to_keyboard_mod_key_map.find(mod); - if (key_it != string_to_keyboard_key_map.end() && mod_it != string_to_keyboard_mod_key_map.end()) { + if (key_it != string_to_keyboard_key_map.end() && + mod_it != string_to_keyboard_mod_key_map.end()) { binding.key = key_it->second; binding.modifier = mod_it->second; } else { @@ -309,10 +300,11 @@ void WindowSDL::parseInputConfig(const std::string& filename) { auto button_it = string_to_cbutton_map.find(controller_input); if (axis_it != string_to_axis_map.end()) { axis_map[binding] = axis_it->second; - } else if(button_it != string_to_cbutton_map.end()) { + } else if (button_it != string_to_cbutton_map.end()) { button_map[binding] = button_it->second; } else { - std::cerr << "Syntax error while parsing controller inputs at line " << lineCount << "\n"; + std::cerr << "Syntax error while parsing controller inputs at line " << lineCount + << "\n"; continue; // skip } } @@ -321,23 +313,23 @@ void WindowSDL::parseInputConfig(const std::string& filename) { Uint32 WindowSDL::keyRepeatCallback(void* param, Uint32 id, Uint32 interval) { auto* data = (std::pair*)param; - KeyBinding binding = { data->second->key.key, SDL_GetModState() }; + KeyBinding binding = {data->second->key.key, SDL_GetModState()}; data->first->updateModKeyedInputsManually(binding); - //data->first->onKeyPress(data->second); + // data->first->onKeyPress(data->second); delete data->second; delete data; - return 0; // Return 0 to stop the timer after firing once + return 0; // Return 0 to stop the timer after firing once } Uint32 WindowSDL::mousePolling(void* param, Uint32 id, Uint32 interval) { auto* data = (WindowSDL*)param; data->updateMouse(); - return 33; // Return 0 to stop the timer after firing once + return 33; // Return 0 to stop the timer after firing once } void WindowSDL::updateMouse() { float d_x = 0, d_y = 0; SDL_GetRelativeMouseState(&d_x, &d_y); - //std::cout << "mouse polling yay!\n" << d_x << " " << d_y <<"\n"; + // std::cout << "mouse polling yay!\n" << d_x << " " << d_y <<"\n"; float angle = atan2(d_y, d_x); float a_x = cos(angle) * 128.0, a_y = sin(angle) * 128.0; @@ -351,9 +343,8 @@ void WindowSDL::updateMouse() { } } - - -WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_, std::string_view window_title) +WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_, + std::string_view window_title) : width{width_}, height{height_}, controller{controller_} { if (!SDL_Init(SDL_INIT_VIDEO)) { UNREACHABLE_MSG("Failed to initialize SDL video subsystem: {}", SDL_GetError()); @@ -411,9 +402,9 @@ Uint32 mouse_polling_id = 0; void WindowSDL::waitEvent() { // Called on main thread SDL_Event event; - if(mouse_polling_id == 0) { + if (mouse_polling_id == 0) { // mouse polling - //std::cout << "Why are we adding new timers?\n\n"; + // std::cout << "Why are we adding new timers?\n\n"; mouse_polling_id = SDL_AddTimer(33, mousePolling, (void*)this); } if (!SDL_WaitEvent(&event)) { @@ -425,8 +416,8 @@ void WindowSDL::waitEvent() { } SDL_Event* event_copy = new SDL_Event(); *event_copy = event; - std::pair* payload_to_timer = - new std::pair(this, event_copy); + std::pair* payload_to_timer = + new std::pair(this, event_copy); switch (event.type) { case SDL_EVENT_WINDOW_RESIZED: @@ -443,7 +434,7 @@ void WindowSDL::waitEvent() { case SDL_EVENT_KEY_UP: case SDL_EVENT_MOUSE_BUTTON_UP: case SDL_EVENT_MOUSE_BUTTON_DOWN: - SDL_AddTimer(33, keyRepeatCallback, (void*)payload_to_timer); // this is intentional passthrough + SDL_AddTimer(33, keyRepeatCallback, (void*)payload_to_timer); onKeyPress(&event); break; case SDL_EVENT_GAMEPAD_BUTTON_DOWN: @@ -471,20 +462,21 @@ void WindowSDL::onResize() { void WindowSDL::updateButton(KeyBinding& binding, u32 button, bool is_pressed) { float x; Input::Axis axis; - switch(button) { + switch (button) { case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2: case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2: - axis = (button == OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2) ? - Input::Axis::TriggerRight : Input::Axis::TriggerLeft; - //int axis_value = is_pressed ? 255 : 0; - //int ax = Input::GetAxis(0, 0x80, is_pressed ? 255 : 0); + axis = (button == OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2) ? Input::Axis::TriggerRight + : Input::Axis::TriggerLeft; + // int axis_value = is_pressed ? 255 : 0; + // int ax = Input::GetAxis(0, 0x80, is_pressed ? 255 : 0); controller->Axis(0, axis, Input::GetAxis(0, 0x80, is_pressed ? 255 : 0)); break; case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD: - x = Config::getBackButtonBehavior() == "left" ? 0.25f - : Config::getBackButtonBehavior() == "right" ? 0.75f : 0.5f; + x = Config::getBackButtonBehavior() == "left" ? 0.25f + : Config::getBackButtonBehavior() == "right" ? 0.75f + : 0.5f; controller->SetTouchpadState(0, true, x, 0.5f); - //button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD; + // button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD; controller->CheckButton(0, button, is_pressed); break; default: // is a normal key @@ -497,11 +489,13 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { // Extract key and modifier KeyBinding binding = {0, SDL_GetModState()}; if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) { - binding.key = event->key.key; // For keyboard events - } else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || event->type == SDL_EVENT_MOUSE_BUTTON_UP) { - binding.key = event->button.button; // For mouse button events + binding.key = event->key.key; // For keyboard events + } else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || + event->type == SDL_EVENT_MOUSE_BUTTON_UP) { + binding.key = event->button.button; // For mouse button events } else { - std::cout << "Bro something is very wrong with the waitevent switch case as this is the only 4 possible cases\n"; + std::cout << "Bro something is very wrong with the waitevent switch case as this is the " + "only 4 possible cases\n"; return; } @@ -513,7 +507,8 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { if (event->type == SDL_EVENT_KEY_DOWN) { // Toggle capture of the mouse if (binding.key == SDLK_F9) { - SDL_SetWindowRelativeMouseMode(this->GetSdlWindow(), !SDL_GetWindowRelativeMouseMode(this->GetSdlWindow())); + SDL_SetWindowRelativeMouseMode(this->GetSdlWindow(), + !SDL_GetWindowRelativeMouseMode(this->GetSdlWindow())); } // Reparse kbm inputs if (binding.key == SDLK_F8) { @@ -527,10 +522,9 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { } // Trigger rdoc capture if (binding.key == SDLK_F12) { - VideoCore::TriggerCapture(); + VideoCore::TriggerCapture(); } } - // Check if the current key+modifier is a button mapping bool button_found = false; @@ -541,7 +535,9 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { if (button_it != button_map.end()) { button_found = true; button = button_it->second; - WindowSDL::updateButton(binding, button, event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_MOUSE_BUTTON_DOWN); + WindowSDL::updateButton(binding, button, + event->type == SDL_EVENT_KEY_DOWN || + event->type == SDL_EVENT_MOUSE_BUTTON_DOWN); } // Check if the current key+modifier is an axis mapping auto axis_it = FindKeyAllowingPartialModifiers(axis_map, binding); @@ -550,7 +546,10 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { } if (axis_it != axis_map.end()) { axis = axis_it->second.axis; - axis_value = (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) ? axis_it->second.value : 0; + axis_value = + (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) + ? axis_it->second.value + : 0; int ax = Input::GetAxis(-0x80, 0x80, axis_value); controller->Axis(0, axis, ax); } @@ -565,35 +564,37 @@ void WindowSDL::updateModKeyedInputsManually(Frontend::KeyBinding& binding) { if (input.first.modifier != SDL_KMOD_NONE) { if ((input.first.modifier & binding.modifier) == 0) { WindowSDL::updateButton(binding, input.second, false); - } else if(input.first.key == binding.key) { + } else if (input.first.key == binding.key) { mod_keyed_input_found = true; } } } for (auto input : axis_map) { if (input.first.modifier != SDL_KMOD_NONE) { - if((input.first.modifier & binding.modifier) == 0) { + if ((input.first.modifier & binding.modifier) == 0) { controller->Axis(0, input.second.axis, Input::GetAxis(-0x80, 0x80, 0)); - } else if(input.first.key == binding.key) { + } else if (input.first.key == binding.key) { mod_keyed_input_found = true; } } } - // if both non mod keyed and mod keyed inputs are used and you press the key and then the mod key in a single frame, - // both will activate but the simple one will not deactivate, unless i use this stupid looking workaround - if(!mod_keyed_input_found) return; // in this case the fix for the fix for the wrong update order is not needed - for(auto input : button_map) { - if(input.first.modifier == SDL_KMOD_NONE) { + // if both non mod keyed and mod keyed inputs are used and you press the key and then the mod + // key in a single frame, both will activate but the simple one will not deactivate, unless i + // use this stupid looking workaround + if (!mod_keyed_input_found) + return; // in this case the fix for the fix for the wrong update order is not needed + for (auto input : button_map) { + if (input.first.modifier == SDL_KMOD_NONE) { WindowSDL::updateButton(binding, input.second, false); } } - for(auto input : axis_map) { - if(input.first.modifier == SDL_KMOD_NONE) { + for (auto input : axis_map) { + if (input.first.modifier == SDL_KMOD_NONE) { controller->Axis(0, input.second.axis, Input::GetAxis(-0x80, 0x80, 0)); } } - // also this sometimes leads to janky inputs but whoever decides to intentionally create a state where this is needed - // should not deserve a smooth experience anyway + // also this sometimes leads to janky inputs but whoever decides to intentionally create a state + // where this is needed should not deserve a smooth experience anyway } void WindowSDL::onGamepadEvent(const SDL_Event* event) { diff --git a/src/sdl_window.h b/src/sdl_window.h index ac18b718d49..b19703e7d9d 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -18,7 +18,6 @@ class GameController; namespace Frontend { - class KeyBinding { public: Uint32 key; @@ -52,8 +51,6 @@ struct WindowSystemInfo { WindowSystemType type = WindowSystemType::Headless; }; - - class WindowSDL { public: explicit WindowSDL(s32 width, s32 height, Input::GameController* controller, @@ -84,7 +81,6 @@ class WindowSDL { void updateMouse(); private: - void onResize(); void onKeyPress(const SDL_Event* event); void onGamepadEvent(const SDL_Event* event); diff --git a/user/keyboardInputConfig.ini b/user/keyboardInputConfig.ini index 25e7702ba18..096f3a3f09c 100644 --- a/user/keyboardInputConfig.ini +++ b/user/keyboardInputConfig.ini @@ -1,61 +1,65 @@ -# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project -# SPDX-License-Identifier: GPL-2.0-or-later - -# controller button mappings - -# taken keys: -# f11: fullscreen -# f10: fps counter -# f9: toggle mouse capture -# f8: reparse keyboard input (this) - -# this is a mapping for bloodborne inspired by other souls titles on pc - -# use another item (healing), change status in inventory -triangle=f -# dodge, back in inv -circle=space -# interact, select item in inv -cross=e -# use quick item, remove item in inv -square=r - -# emergency extra bullets -up=w,lalt -# change quick item -down=s,lalt -# change weapon in left hand -left=a,lalt -# change weapon in right hand -right=d,lalt - -# menu -options=escape -# gestures -touchpad=g - -# transform -l1=rightbutton,lshift -# shoot -r1=leftbutton -# light attack -l2=rightbutton -# heavy attack -r2=leftbutton,lshift - -# does nothing -l3=x -# center cam, lock on -r3=q - -# axis mappings -# move -axis_left_x_minus=a -axis_left_x_plus=d -axis_left_y_minus=w -axis_left_y_plus=s -# og cam input -# axis_right_x_minus=j -# axis_right_x_plus=l -# axis_right_y_minus=i -# axis_right_y_plus=k +#SPDX - FileCopyrightText : Copyright 2024 shadPS4 Emulator Project +#SPDX - License - Identifier : GPL - 2.0 - or -later + +#controller button mappings + +#taken keys: +#f11 : fullscreen +#f10 : fps counter +#f9 : toggle mouse capture +#f8 : reparse keyboard input(this) + +#this is a mapping for bloodborne inspired by other souls titles on pc + +#use another item(healing), change status in inventory +triangle = f +#dodge, back in inv + circle = space +#interact, select item in inv + cross = e +#use quick item, remove item in inv + square = r + +#emergency extra bullets + up = w, + lalt +#change quick item + down = s, + lalt +#change weapon in left hand + left = a, + lalt +#change weapon in right hand + right = d, + lalt + +#menu + options = escape +#gestures + touchpad = g + +#transform + l1 = rightbutton, + lshift +#shoot + r1 = leftbutton +#light attack + l2 = rightbutton +#heavy attack + r2 = leftbutton, + lshift + +#does nothing + l3 = x +#center cam, lock on + r3 = q + +#axis mappings +#move + axis_left_x_minus = a axis_left_x_plus = d axis_left_y_minus = + w axis_left_y_plus = s +#og cam input +#axis_right_x_minus = j +#axis_right_x_plus = l +#axis_right_y_minus = i +#axis_right_y_plus = k From 22e4ab866bd9e5019b3055d5682de45dd89a07cd Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sat, 12 Oct 2024 17:41:23 +0200 Subject: [PATCH 07/79] clang-format fucked up the .ini file --- src/sdl_window.cpp | 2 + user/keyboardInputConfig.ini | 124 +++++++++++++++++++---------------- 2 files changed, 68 insertions(+), 58 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index c88461d65c7..acc042af0f6 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -261,6 +261,8 @@ void WindowSDL::parseInputConfig(const std::string& filename) { std::cerr << "Invalid line format: " << line << std::endl; continue; } + // strip the ; that we put there so that the braindead clang-format is happy + line = line.substr(0, line.length() - 1); std::string controller_input = line.substr(0, equal_pos); std::string kbm_input = line.substr(equal_pos + 1); diff --git a/user/keyboardInputConfig.ini b/user/keyboardInputConfig.ini index 096f3a3f09c..8f9f47b8264 100644 --- a/user/keyboardInputConfig.ini +++ b/user/keyboardInputConfig.ini @@ -1,64 +1,72 @@ #SPDX - FileCopyrightText : Copyright 2024 shadPS4 Emulator Project #SPDX - License - Identifier : GPL - 2.0 - or -later -#controller button mappings - -#taken keys: -#f11 : fullscreen -#f10 : fps counter -#f9 : toggle mouse capture -#f8 : reparse keyboard input(this) - -#this is a mapping for bloodborne inspired by other souls titles on pc - -#use another item(healing), change status in inventory -triangle = f -#dodge, back in inv - circle = space -#interact, select item in inv - cross = e -#use quick item, remove item in inv - square = r - -#emergency extra bullets - up = w, - lalt -#change quick item - down = s, - lalt -#change weapon in left hand - left = a, - lalt -#change weapon in right hand - right = d, - lalt - -#menu - options = escape -#gestures - touchpad = g - -#transform - l1 = rightbutton, - lshift -#shoot - r1 = leftbutton -#light attack - l2 = rightbutton -#heavy attack - r2 = leftbutton, - lshift - -#does nothing - l3 = x -#center cam, lock on - r3 = q - -#axis mappings -#move - axis_left_x_minus = a axis_left_x_plus = d axis_left_y_minus = - w axis_left_y_plus = s -#og cam input +#Controller button mappings + +#Taken keys: +#F11 : fullscreen +#F10 : FPS counter +#F9 : toggle mouse capture +#F8 : reparse keyboard input(this) + +#This is a mapping for Bloodborne, inspired by other Souls titles on PC. + +#Use another item(healing), change status in inventory +triangle = f; + +#Dodge, back in inventory +circle = space; + +#Interact, select item in inventory +cross = e; + +#Use quick item, remove item in inventory +square = r; + +#Emergency extra bullets +up = w, lalt; + +#Change quick item +down = s, lalt; + +#Change weapon in left hand +left = a, lalt; + +#Change weapon in right hand +right = d, lalt; + +#Menu +options = escape; + +#Gestures +touchpad = g; + +#Transform +l1 = rightbutton, lshift; + +#Shoot +r1 = leftbutton; + +#Light attack +l2 = rightbutton; + +#Heavy attack +r2 = leftbutton, lshift; + +#Does nothing +l3 = x; + +#Center cam, lock on +r3 = q; + +#Axis mappings +#Move +axis_left_x_minus = a; +axis_left_x_plus = d; +axis_left_y_minus = w; +axis_left_y_plus = s; + +#Original camera input(disabled in current config) #axis_right_x_minus = j #axis_right_x_plus = l #axis_right_y_minus = i From 45f05c067d1175c208e546ea61c0d3142e64471c Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sat, 12 Oct 2024 22:29:10 +0200 Subject: [PATCH 08/79] actually fix clang changing ini syntax use relative path for the ini file --- src/sdl_window.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index acc042af0f6..166c7069517 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -17,7 +17,9 @@ #include #include "common/assert.h" #include "common/config.h" +#include "common/io_file.h" #include "common/version.h" +#include "common/path_util.h" #include "core/libraries/pad/pad.h" #include "imgui/renderer/imgui_core.h" #include "input/controller.h" @@ -239,11 +241,15 @@ std::map axis_map = { }; void WindowSDL::parseInputConfig(const std::string& filename) { - std::ifstream file(filename); + // Read configuration file. + std::cout << "Reading keyboard config...\n"; + const std::filesystem::__cxx11::path user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); + std::ifstream file(user_dir / filename); if (!file.is_open()) { std::cerr << "Error opening file: " << filename << std::endl; return; } + std::cout << "File opened at " << user_dir.c_str() << "\n"; button_map.clear(); axis_map.clear(); @@ -255,14 +261,16 @@ void WindowSDL::parseInputConfig(const std::string& filename) { if (line.empty() || line[0] == '#') { continue; } + // strip the ; and whitespace that we put there so that the braindead clang-format is happy + line = line.substr(0, line.length() - 1); + line.erase(std::remove(line.begin(), line.end(), ' '), line.end()); + // Split the line by '=' std::size_t equal_pos = line.find('='); if (equal_pos == std::string::npos) { std::cerr << "Invalid line format: " << line << std::endl; continue; } - // strip the ; that we put there so that the braindead clang-format is happy - line = line.substr(0, line.length() - 1); std::string controller_input = line.substr(0, equal_pos); std::string kbm_input = line.substr(equal_pos + 1); @@ -283,7 +291,7 @@ void WindowSDL::parseInputConfig(const std::string& filename) { binding.key = key_it->second; binding.modifier = mod_it->second; } else { - std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount << "\n"; + std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount << " line data: " << line << "\n"; continue; // skip } } else { @@ -292,7 +300,7 @@ void WindowSDL::parseInputConfig(const std::string& filename) { if (key_it != string_to_keyboard_key_map.end()) { binding.key = key_it->second; } else { - std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount << "\n"; + std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount << " line data: " << line << "\n"; continue; // skip } } @@ -305,8 +313,7 @@ void WindowSDL::parseInputConfig(const std::string& filename) { } else if (button_it != string_to_cbutton_map.end()) { button_map[binding] = button_it->second; } else { - std::cerr << "Syntax error while parsing controller inputs at line " << lineCount - << "\n"; + std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount << " line data: " << line << "\n"; continue; // skip } } @@ -396,7 +403,7 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_ window_info.render_surface = SDL_Metal_GetLayer(SDL_Metal_CreateView(window)); #endif // initialize kbm controls - parseInputConfig("user/keyboardInputConfig.ini"); + parseInputConfig("keyboardInputConfig.ini"); } WindowSDL::~WindowSDL() = default; @@ -514,7 +521,7 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { } // Reparse kbm inputs if (binding.key == SDLK_F8) { - parseInputConfig("user/keyboardInputConfig.ini"); + parseInputConfig("keyboardInputConfig.ini"); } // Toggle fullscreen if (binding.key == SDLK_F11) { From b15810d56f44e199aeb7fd67e660beffa6262e45 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sun, 13 Oct 2024 07:40:21 +0200 Subject: [PATCH 09/79] remove big commented out code blocks, and fixed platform-dependent code --- src/sdl_window.cpp | 64 +++------------------------------------------- 1 file changed, 3 insertions(+), 61 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 166c7069517..23bdc5efba7 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -179,71 +179,13 @@ std::map string_to_keyboard_mod_key_map = { }; // Button map: maps key+modifier to controller button -std::map button_map = { - /* - //Taken keys: - //F11: fullscreen - //F10: Fps counter - //F9: toggle mouse capture - // use an other item (healing), change status in inv - {{SDLK_F, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE}, - // dodge, back in inv - {{SDLK_SPACE, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE}, - // interact, select item in inv - {{SDLK_E, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS}, - // use quick item, remove equipped item of change item desc in inv - {{SDLK_R, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE}, - - // arrow keys, but triggers normal wasd too (pls fix) - // emergency extra bullets - {{SDLK_W, SDL_KMOD_LALT}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP}, - // change quick item - {{SDLK_S, SDL_KMOD_LALT}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN}, - // change weapon in left - {{SDLK_a, SDL_KMOD_LALT}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT}, - // change weapon in right - {{SDLK_D, SDL_KMOD_LALT}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT}, - - // menu - {{SDLK_ESCAPE, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS}, - // gestures - {{SDLK_G, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD}, - - // transform - {{SDL_BUTTON_RIGHT, SDL_KMOD_LSHIFT}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1}, - // light attack - {{SDL_BUTTON_LEFT, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1}, - // shoot - {{SDL_BUTTON_RIGHT, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2}, - // heavy attack - {{SDL_BUTTON_LEFT, SDL_KMOD_LSHIFT}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2}, - - // does nothing - {{SDLK_X, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3}, - // center cam, lock on enemy - {{SDLK_Q, SDL_KMOD_NONE}, OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3}, -*/ -}; -std::map axis_map = { - /* - // move - {{SDLK_A, SDL_KMOD_NONE}, {Input::Axis::LeftX, -127}}, - {{SDLK_D, SDL_KMOD_NONE}, {Input::Axis::LeftX, 127}}, - {{SDLK_W, SDL_KMOD_NONE}, {Input::Axis::LeftY, -127}}, - {{SDLK_S, SDL_KMOD_NONE}, {Input::Axis::LeftY, 127}}, - - //this is now using the mouse - {{SDLK_J, SDL_KMOD_NONE}, {Input::Axis::RightX, -127}}, - {{SDLK_L, SDL_KMOD_NONE}, {Input::Axis::RightX, 127}}, - {{SDLK_I, SDL_KMOD_NONE}, {Input::Axis::RightY, -127}}, - {{SDLK_K, SDL_KMOD_NONE}, {Input::Axis::RightY, 127}}, - */ -}; +std::map button_map = {}; +std::map axis_map = {}; void WindowSDL::parseInputConfig(const std::string& filename) { // Read configuration file. std::cout << "Reading keyboard config...\n"; - const std::filesystem::__cxx11::path user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); + const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); std::ifstream file(user_dir / filename); if (!file.is_open()) { std::cerr << "Error opening file: " << filename << std::endl; From 719a36c9e5e43d7be7179c27fb488b0cc83fa65b Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sun, 13 Oct 2024 07:58:36 +0200 Subject: [PATCH 10/79] fix windows hating me --- src/sdl_window.cpp | 2 +- user/keyboardInputConfig.ini | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 23bdc5efba7..b5f4bcf947c 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -191,7 +191,7 @@ void WindowSDL::parseInputConfig(const std::string& filename) { std::cerr << "Error opening file: " << filename << std::endl; return; } - std::cout << "File opened at " << user_dir.c_str() << "\n"; + std::cout << "File opened.\n"; button_map.clear(); axis_map.clear(); diff --git a/user/keyboardInputConfig.ini b/user/keyboardInputConfig.ini index 8f9f47b8264..93e49d19f7a 100644 --- a/user/keyboardInputConfig.ini +++ b/user/keyboardInputConfig.ini @@ -1,5 +1,5 @@ -#SPDX - FileCopyrightText : Copyright 2024 shadPS4 Emulator Project -#SPDX - License - Identifier : GPL - 2.0 - or -later +## SPDX - FileCopyrightText : Copyright 2024 shadPS4 Emulator Project +## SPDX - License - Identifier : GPL - 2.0 - or -later #Controller button mappings From 607514eb86ef48dc6c2d9f31f85522f0915e4d9b Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sun, 13 Oct 2024 09:48:37 +0200 Subject: [PATCH 11/79] added mouse config option --- src/sdl_window.cpp | 60 +++++++++++++++++++++++++++--------- user/keyboardInputConfig.ini | 7 +++-- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index b5f4bcf947c..5410fa272a2 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -1,11 +1,9 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -// new includes -#include -// #include #include #include +#include #include #include #include @@ -18,8 +16,8 @@ #include "common/assert.h" #include "common/config.h" #include "common/io_file.h" -#include "common/version.h" #include "common/path_util.h" +#include "common/version.h" #include "core/libraries/pad/pad.h" #include "imgui/renderer/imgui_core.h" #include "input/controller.h" @@ -182,16 +180,18 @@ std::map string_to_keyboard_mod_key_map = { std::map button_map = {}; std::map axis_map = {}; +int mouse_joystick_binding = 0; +Uint32 mouse_polling_id = 0; void WindowSDL::parseInputConfig(const std::string& filename) { + // Read configuration file. - std::cout << "Reading keyboard config...\n"; + // std::cout << "Reading keyboard config...\n"; const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); std::ifstream file(user_dir / filename); if (!file.is_open()) { std::cerr << "Error opening file: " << filename << std::endl; return; } - std::cout << "File opened.\n"; button_map.clear(); axis_map.clear(); @@ -218,6 +218,22 @@ void WindowSDL::parseInputConfig(const std::string& filename) { std::string kbm_input = line.substr(equal_pos + 1); KeyBinding binding = {0, SDL_KMOD_NONE}; // Initialize KeyBinding + // quick hack to configure the mouse + if (controller_input == "mouse_to_joystick") { + switch (kbm_input[0]) { + case 'l': + mouse_joystick_binding = 1; + break; + case 'r': + mouse_joystick_binding = 2; + break; + case 'n': + default: + mouse_joystick_binding = 0; + break; + } + continue; + } // first we parse the binding, and if its wrong, we skip to the next line std::size_t comma_pos = kbm_input.find(','); if (comma_pos != std::string::npos) { @@ -233,7 +249,8 @@ void WindowSDL::parseInputConfig(const std::string& filename) { binding.key = key_it->second; binding.modifier = mod_it->second; } else { - std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount << " line data: " << line << "\n"; + std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount + << " line data: " << line << "\n"; continue; // skip } } else { @@ -242,7 +259,8 @@ void WindowSDL::parseInputConfig(const std::string& filename) { if (key_it != string_to_keyboard_key_map.end()) { binding.key = key_it->second; } else { - std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount << " line data: " << line << "\n"; + std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount + << " line data: " << line << "\n"; continue; // skip } } @@ -255,7 +273,8 @@ void WindowSDL::parseInputConfig(const std::string& filename) { } else if (button_it != string_to_cbutton_map.end()) { button_map[binding] = button_it->second; } else { - std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount << " line data: " << line << "\n"; + std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount + << " line data: " << line << "\n"; continue; // skip } } @@ -278,9 +297,24 @@ Uint32 WindowSDL::mousePolling(void* param, Uint32 id, Uint32 interval) { } void WindowSDL::updateMouse() { + + Input::Axis axis_x, axis_y; + switch (mouse_joystick_binding) { + case 1: + axis_x = Input::Axis::LeftX; + axis_y = Input::Axis::LeftY; + break; + case 2: + axis_x = Input::Axis::RightX; + axis_y = Input::Axis::RightY; + break; + case 0: + default: + return; // no update needed + } + float d_x = 0, d_y = 0; SDL_GetRelativeMouseState(&d_x, &d_y); - // std::cout << "mouse polling yay!\n" << d_x << " " << d_y <<"\n"; float angle = atan2(d_y, d_x); float a_x = cos(angle) * 128.0, a_y = sin(angle) * 128.0; @@ -349,15 +383,14 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_ } WindowSDL::~WindowSDL() = default; -Uint32 mouse_polling_id = 0; + void WindowSDL::waitEvent() { // Called on main thread SDL_Event event; if (mouse_polling_id == 0) { - // mouse polling - // std::cout << "Why are we adding new timers?\n\n"; mouse_polling_id = SDL_AddTimer(33, mousePolling, (void*)this); } + if (!SDL_WaitEvent(&event)) { return; } @@ -427,7 +460,6 @@ void WindowSDL::updateButton(KeyBinding& binding, u32 button, bool is_pressed) { : Config::getBackButtonBehavior() == "right" ? 0.75f : 0.5f; controller->SetTouchpadState(0, true, x, 0.5f); - // button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD; controller->CheckButton(0, button, is_pressed); break; default: // is a normal key diff --git a/user/keyboardInputConfig.ini b/user/keyboardInputConfig.ini index 93e49d19f7a..03f842e916f 100644 --- a/user/keyboardInputConfig.ini +++ b/user/keyboardInputConfig.ini @@ -1,5 +1,5 @@ -## SPDX - FileCopyrightText : Copyright 2024 shadPS4 Emulator Project -## SPDX - License - Identifier : GPL - 2.0 - or -later +## SPDX-FileCopyrightText : Copyright 2024 shadPS4 Emulator Project +## SPDX-License-Identifier : GPL-2.0-or-later #Controller button mappings @@ -11,6 +11,9 @@ #This is a mapping for Bloodborne, inspired by other Souls titles on PC. +#This is a quick and dirty implementation of binding the mouse to a user-specified joystick +mouse_to_joystick = left; + #Use another item(healing), change status in inventory triangle = f; From 6a2eab3f6586304365bf5499cd3186d5e68de93d Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sun, 13 Oct 2024 10:08:28 +0200 Subject: [PATCH 12/79] added toggle for mouse movement input (f7) --- src/sdl_window.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 5410fa272a2..63444e93fb7 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -182,6 +182,7 @@ std::map axis_map = {}; int mouse_joystick_binding = 0; Uint32 mouse_polling_id = 0; +bool mouse_enabled = true; void WindowSDL::parseInputConfig(const std::string& filename) { // Read configuration file. @@ -297,7 +298,7 @@ Uint32 WindowSDL::mousePolling(void* param, Uint32 id, Uint32 interval) { } void WindowSDL::updateMouse() { - + if(!mouse_enabled) return; Input::Axis axis_x, axis_y; switch (mouse_joystick_binding) { case 1: @@ -497,6 +498,10 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { if (binding.key == SDLK_F8) { parseInputConfig("keyboardInputConfig.ini"); } + // Toggle mouse movement input + if (binding.key == SDLK_F7) { + mouse_enabled = !mouse_enabled; + } // Toggle fullscreen if (binding.key == SDLK_F11) { SDL_WindowFlags flag = SDL_GetWindowFlags(window); From b300ffe9592fececb69b043cc44e16e6d60b4e0f Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sun, 13 Oct 2024 10:49:54 +0200 Subject: [PATCH 13/79] fix license and style --- src/sdl_window.cpp | 7 ++++--- user/keyboardInputConfig.ini | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 63444e93fb7..60c4234ba42 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -184,7 +184,7 @@ int mouse_joystick_binding = 0; Uint32 mouse_polling_id = 0; bool mouse_enabled = true; void WindowSDL::parseInputConfig(const std::string& filename) { - + // Read configuration file. // std::cout << "Reading keyboard config...\n"; const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); @@ -298,7 +298,8 @@ Uint32 WindowSDL::mousePolling(void* param, Uint32 id, Uint32 interval) { } void WindowSDL::updateMouse() { - if(!mouse_enabled) return; + if (!mouse_enabled) + return; Input::Axis axis_x, axis_y; switch (mouse_joystick_binding) { case 1: @@ -391,7 +392,7 @@ void WindowSDL::waitEvent() { if (mouse_polling_id == 0) { mouse_polling_id = SDL_AddTimer(33, mousePolling, (void*)this); } - + if (!SDL_WaitEvent(&event)) { return; } diff --git a/user/keyboardInputConfig.ini b/user/keyboardInputConfig.ini index 03f842e916f..af44beef3ce 100644 --- a/user/keyboardInputConfig.ini +++ b/user/keyboardInputConfig.ini @@ -1,6 +1,6 @@ -## SPDX-FileCopyrightText : Copyright 2024 shadPS4 Emulator Project -## SPDX-License-Identifier : GPL-2.0-or-later - +## SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +## SPDX-License-Identifier: GPL-2.0-or-later + #Controller button mappings #Taken keys: From ef7b0ad6835e3859fbd8eb82c6c18e79937e8a17 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sun, 13 Oct 2024 21:33:12 +0200 Subject: [PATCH 14/79] add numpad support i accidentally left out --- src/sdl_window.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 60c4234ba42..ceea3f91b55 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -166,6 +166,24 @@ std::map string_to_keyboard_key_map = { {"leftbutton", SDL_BUTTON_LEFT}, {"rightbutton", SDL_BUTTON_RIGHT}, {"middlebutton", SDL_BUTTON_MIDDLE}, + {"kp0", SDLK_KP_0}, + {"kp1", SDLK_KP_1}, + {"kp2", SDLK_KP_2}, + {"kp3", SDLK_KP_3}, + {"kp4", SDLK_KP_4}, + {"kp5", SDLK_KP_5}, + {"kp6", SDLK_KP_6}, + {"kp7", SDLK_KP_7}, + {"kp8", SDLK_KP_8}, + {"kp9", SDLK_KP_9}, + {"kpperiod", SDLK_KP_PERIOD}, + {"kpdivide", SDLK_KP_DIVIDE}, + {"kpmultiply", SDLK_KP_MULTIPLY}, + {"kpminus", SDLK_KP_MINUS}, + {"kpplus", SDLK_KP_PLUS}, + {"kpenter", SDLK_KP_ENTER}, + {"kpequals", SDLK_KP_EQUALS}, + {"kpcomma", SDLK_KP_COMMA}, }; std::map string_to_keyboard_mod_key_map = { {"lshift", SDL_KMOD_LSHIFT}, {"rshift", SDL_KMOD_RSHIFT}, {"lctrl", SDL_KMOD_LCTRL}, From 17e44de58fdbee60adb724523b18a32cb1f9f0b1 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:45:51 +0200 Subject: [PATCH 15/79] added support for mouse wheel (to buttons only) --- src/sdl_window.cpp | 109 +++++++++++++++++++++++++++++++-------------- src/sdl_window.h | 1 + 2 files changed, 76 insertions(+), 34 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index ceea3f91b55..09ae311e81a 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -28,9 +28,45 @@ #include #endif +// +1 and +2 is taken +#define SDL_EVENT_MOUSE_WHEEL_UP SDL_EVENT_MOUSE_WHEEL + 3 +#define SDL_EVENT_MOUSE_WHEEL_DOWN SDL_EVENT_MOUSE_WHEEL + 4 +#define SDL_EVENT_MOUSE_WHEEL_LEFT SDL_EVENT_MOUSE_WHEEL + 5 +#define SDL_EVENT_MOUSE_WHEEL_RIGHT SDL_EVENT_MOUSE_WHEEL + 6 + +Uint32 getMouseWheelEvent(const SDL_Event* event) { + if(event->type != SDL_EVENT_MOUSE_WHEEL) return 0; + // std::cout << "We got a wheel event! "; + if(event->wheel.y > 0) { + return SDL_EVENT_MOUSE_WHEEL_UP; + } else if(event->wheel.y < 0) { + return SDL_EVENT_MOUSE_WHEEL_DOWN; + } else if(event->wheel.x > 0) { + return SDL_EVENT_MOUSE_WHEEL_RIGHT; + } else if(event->wheel.x < 0) { + return SDL_EVENT_MOUSE_WHEEL_LEFT; + } + return 0; +} + namespace Frontend { using Libraries::Pad::OrbisPadButtonDataOffset; +KeyBinding::KeyBinding(const SDL_Event* event) { + modifier = SDL_GetModState(); + key = 0; + // std::cout << "Someone called the new binding ctor!\n"; + if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) { + key = event->key.key; + } else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || + event->type == SDL_EVENT_MOUSE_BUTTON_UP) { + key = event->button.button; + } else if(event->type == SDL_EVENT_MOUSE_WHEEL) { + key = getMouseWheelEvent(event); + } else { + std::cout << "We don't support this event type!\n"; + } +} bool KeyBinding::operator<(const KeyBinding& other) const { return std::tie(key, modifier) < std::tie(other.key, other.modifier); } @@ -166,6 +202,10 @@ std::map string_to_keyboard_key_map = { {"leftbutton", SDL_BUTTON_LEFT}, {"rightbutton", SDL_BUTTON_RIGHT}, {"middlebutton", SDL_BUTTON_MIDDLE}, + {"mousewheelup", SDL_EVENT_MOUSE_WHEEL_UP}, + {"mousewheeldown", SDL_EVENT_MOUSE_WHEEL_DOWN}, + {"mousewheelleft", SDL_EVENT_MOUSE_WHEEL_LEFT}, + {"mousewheelright", SDL_EVENT_MOUSE_WHEEL_RIGHT}, {"kp0", SDLK_KP_0}, {"kp1", SDLK_KP_1}, {"kp2", SDLK_KP_2}, @@ -202,7 +242,7 @@ int mouse_joystick_binding = 0; Uint32 mouse_polling_id = 0; bool mouse_enabled = true; void WindowSDL::parseInputConfig(const std::string& filename) { - + // Read configuration file. // std::cout << "Reading keyboard config...\n"; const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); @@ -302,13 +342,23 @@ void WindowSDL::parseInputConfig(const std::string& filename) { Uint32 WindowSDL::keyRepeatCallback(void* param, Uint32 id, Uint32 interval) { auto* data = (std::pair*)param; - KeyBinding binding = {data->second->key.key, SDL_GetModState()}; + KeyBinding binding(data->second); + if(data->second->type == SDL_EVENT_MOUSE_WHEEL) { + auto button_it = button_map.find(binding); + auto axis_it = axis_map.find(binding); + if(button_it != button_map.end()) { + data->first->updateButton(binding, button_it->second, false); + } else if(axis_it != axis_map.end()) { + data->first->controller->Axis(0, axis_it->second.axis, Input::GetAxis(-0x80, 0x80, 0)); + } + + } data->first->updateModKeyedInputsManually(binding); - // data->first->onKeyPress(data->second); - delete data->second; + delete data->second; delete data; return 0; // Return 0 to stop the timer after firing once } + Uint32 WindowSDL::mousePolling(void* param, Uint32 id, Uint32 interval) { auto* data = (WindowSDL*)param; data->updateMouse(); @@ -316,8 +366,7 @@ Uint32 WindowSDL::mousePolling(void* param, Uint32 id, Uint32 interval) { } void WindowSDL::updateMouse() { - if (!mouse_enabled) - return; + if(!mouse_enabled) return; Input::Axis axis_x, axis_y; switch (mouse_joystick_binding) { case 1: @@ -410,7 +459,7 @@ void WindowSDL::waitEvent() { if (mouse_polling_id == 0) { mouse_polling_id = SDL_AddTimer(33, mousePolling, (void*)this); } - + if (!SDL_WaitEvent(&event)) { return; } @@ -434,10 +483,13 @@ void WindowSDL::waitEvent() { is_shown = event.type == SDL_EVENT_WINDOW_EXPOSED; onResize(); break; - case SDL_EVENT_KEY_DOWN: - case SDL_EVENT_KEY_UP: + case SDL_EVENT_MOUSE_WHEEL: case SDL_EVENT_MOUSE_BUTTON_UP: case SDL_EVENT_MOUSE_BUTTON_DOWN: + // native mouse update function goes here + // as seen in pr #633 + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: SDL_AddTimer(33, keyRepeatCallback, (void*)payload_to_timer); onKeyPress(&event); break; @@ -490,17 +542,10 @@ void WindowSDL::updateButton(KeyBinding& binding, u32 button, bool is_pressed) { void WindowSDL::onKeyPress(const SDL_Event* event) { // Extract key and modifier - KeyBinding binding = {0, SDL_GetModState()}; - if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) { - binding.key = event->key.key; // For keyboard events - } else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || - event->type == SDL_EVENT_MOUSE_BUTTON_UP) { - binding.key = event->button.button; // For mouse button events - } else { - std::cout << "Bro something is very wrong with the waitevent switch case as this is the " - "only 4 possible cases\n"; - return; - } + KeyBinding binding(event); + bool input_down = event->type == SDL_EVENT_KEY_DOWN || + event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || + event->type == SDL_EVENT_MOUSE_WHEEL; u32 button = 0; Input::Axis axis = Input::Axis::AxisMax; @@ -533,28 +578,24 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { } } - // Check if the current key+modifier is a button mapping - bool button_found = false; + // Check if the current key+modifier is a button or axis mapping + // first only exact matches auto button_it = FindKeyAllowingPartialModifiers(button_map, binding); - if (button_it == button_map.end()) { + auto axis_it = FindKeyAllowingPartialModifiers(axis_map, binding); + // then no mod key matches if we didn't find it in the previous pass + if (button_it == button_map.end() && axis_it == axis_map.end() ) { button_it = FindKeyAllowingOnlyNoModifiers(button_map, binding); } + if (axis_it == axis_map.end() && button_it == button_map.end()) { + axis_it = FindKeyAllowingOnlyNoModifiers(axis_map, binding); + } if (button_it != button_map.end()) { - button_found = true; button = button_it->second; - WindowSDL::updateButton(binding, button, - event->type == SDL_EVENT_KEY_DOWN || - event->type == SDL_EVENT_MOUSE_BUTTON_DOWN); - } - // Check if the current key+modifier is an axis mapping - auto axis_it = FindKeyAllowingPartialModifiers(axis_map, binding); - if (axis_it == axis_map.end() && !button_found) { - axis_it = FindKeyAllowingOnlyNoModifiers(axis_map, binding); + WindowSDL::updateButton(binding, button, input_down); } if (axis_it != axis_map.end()) { axis = axis_it->second.axis; - axis_value = - (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) + axis_value = (input_down) ? axis_it->second.value : 0; int ax = Input::GetAxis(-0x80, 0x80, axis_value); diff --git a/src/sdl_window.h b/src/sdl_window.h index b19703e7d9d..9900125bf77 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -23,6 +23,7 @@ class KeyBinding { Uint32 key; SDL_Keymod modifier; KeyBinding(SDL_Keycode k, SDL_Keymod m) : key(k), modifier(m){}; + KeyBinding(const SDL_Event* event); bool operator<(const KeyBinding& other) const; ~KeyBinding(){}; }; From 1ec9dc085a58c4035e9c54c176a9624e60b2379e Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Mon, 14 Oct 2024 18:53:09 +0200 Subject: [PATCH 16/79] if keyboard config doesn't exist, autogenerate it --- src/sdl_window.cpp | 149 +++++++++++++++++++++++++++++++++------------ 1 file changed, 111 insertions(+), 38 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 09ae311e81a..72028c668e5 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -35,15 +35,16 @@ #define SDL_EVENT_MOUSE_WHEEL_RIGHT SDL_EVENT_MOUSE_WHEEL + 6 Uint32 getMouseWheelEvent(const SDL_Event* event) { - if(event->type != SDL_EVENT_MOUSE_WHEEL) return 0; + if (event->type != SDL_EVENT_MOUSE_WHEEL) + return 0; // std::cout << "We got a wheel event! "; - if(event->wheel.y > 0) { + if (event->wheel.y > 0) { return SDL_EVENT_MOUSE_WHEEL_UP; - } else if(event->wheel.y < 0) { + } else if (event->wheel.y < 0) { return SDL_EVENT_MOUSE_WHEEL_DOWN; - } else if(event->wheel.x > 0) { + } else if (event->wheel.x > 0) { return SDL_EVENT_MOUSE_WHEEL_RIGHT; - } else if(event->wheel.x < 0) { + } else if (event->wheel.x < 0) { return SDL_EVENT_MOUSE_WHEEL_LEFT; } return 0; @@ -61,7 +62,7 @@ KeyBinding::KeyBinding(const SDL_Event* event) { } else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || event->type == SDL_EVENT_MOUSE_BUTTON_UP) { key = event->button.button; - } else if(event->type == SDL_EVENT_MOUSE_WHEEL) { + } else if (event->type == SDL_EVENT_MOUSE_WHEEL) { key = getMouseWheelEvent(event); } else { std::cout << "We don't support this event type!\n"; @@ -241,12 +242,87 @@ std::map axis_map = {}; int mouse_joystick_binding = 0; Uint32 mouse_polling_id = 0; bool mouse_enabled = true; +const std::string default_config = + R"(## SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +## SPDX-License-Identifier: GPL-2.0-or-later + +#Default controller button mappings + +#Taken keys: +#F11 : fullscreen +#F10 : FPS counter +#F9 : toggle mouse capture +#F8 : reparse keyboard input(this) +#F7 : toggle mouse-to-joystick input +# (it overwrites everything else to that joystick, so this is required) + +#This is a mapping for Bloodborne, inspired by other Souls titles on PC. + +#This is a quick and dirty implementation of binding the mouse to a user-specified joystick +mouse_to_joystick = left; + +#Use another item(healing), change status in inventory +triangle = f; +#Dodge, back in inventory +circle = space; +#Interact, select item in inventory +cross = e; +#Use quick item, remove item in inventory +square = r; + +#Emergency extra bullets +up = w, lalt; +#Change quick item +down = s, lalt; +#Change weapon in left hand +left = a, lalt; +#Change weapon in right hand +right = d, lalt; + +#Menu +options = escape; +#Gestures +touchpad = g; + +#Transform +l1 = rightbutton, lshift; +#Shoot +r1 = leftbutton; +#Light attack +l2 = rightbutton; +#Heavy attack +r2 = leftbutton, lshift; +#Does nothing +l3 = x; +#Center cam, lock on +r3 = q; + +#Axis mappings +#Move +axis_left_x_minus = a; +axis_left_x_plus = d; +axis_left_y_minus = w; +axis_left_y_plus = s; +)"; + void WindowSDL::parseInputConfig(const std::string& filename) { - + // Read configuration file. // std::cout << "Reading keyboard config...\n"; - const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); - std::ifstream file(user_dir / filename); + const auto config_file = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / filename; + if (!std::filesystem::exists(config_file)) { + // create it + std::ofstream file; + file.open(config_file, std::ios::out); + if (file.is_open()) { + file << default_config; + file.close(); + std::cout << "Config file generated.\n"; + } else { + std::cerr << "Error creating file!\n"; + } + } + std::ifstream file(config_file); if (!file.is_open()) { std::cerr << "Error opening file: " << filename << std::endl; return; @@ -258,38 +334,35 @@ void WindowSDL::parseInputConfig(const std::string& filename) { std::string line; while (std::getline(file, line)) { lineCount++; + // strip the ; and whitespace + line.erase(std::remove(line.begin(), line.end(), ' '), line.end()); + if (line[line.length() - 1] == ';') { + line = line.substr(0, line.length() - 1); + } // Ignore comment lines if (line.empty() || line[0] == '#') { continue; } - // strip the ; and whitespace that we put there so that the braindead clang-format is happy - line = line.substr(0, line.length() - 1); - line.erase(std::remove(line.begin(), line.end(), ' '), line.end()); - // Split the line by '=' std::size_t equal_pos = line.find('='); if (equal_pos == std::string::npos) { - std::cerr << "Invalid line format: " << line << std::endl; + std::cerr << "Invalid line format at line: " << lineCount << " data: " << line + << std::endl; continue; } std::string controller_input = line.substr(0, equal_pos); std::string kbm_input = line.substr(equal_pos + 1); - KeyBinding binding = {0, SDL_KMOD_NONE}; // Initialize KeyBinding + KeyBinding binding = {0, SDL_KMOD_NONE}; - // quick hack to configure the mouse + // special check for mouse to joystick input if (controller_input == "mouse_to_joystick") { - switch (kbm_input[0]) { - case 'l': + if (kbm_input == "left") { mouse_joystick_binding = 1; - break; - case 'r': + } else if (kbm_input == "right") { mouse_joystick_binding = 2; - break; - case 'n': - default: - mouse_joystick_binding = 0; - break; + } else { + mouse_joystick_binding = 0; // default to 'none' or invalid } continue; } @@ -343,18 +416,19 @@ void WindowSDL::parseInputConfig(const std::string& filename) { Uint32 WindowSDL::keyRepeatCallback(void* param, Uint32 id, Uint32 interval) { auto* data = (std::pair*)param; KeyBinding binding(data->second); - if(data->second->type == SDL_EVENT_MOUSE_WHEEL) { + if (data->second->type == SDL_EVENT_MOUSE_WHEEL) { + // send an off signal a frame later auto button_it = button_map.find(binding); auto axis_it = axis_map.find(binding); - if(button_it != button_map.end()) { + if (button_it != button_map.end()) { data->first->updateButton(binding, button_it->second, false); - } else if(axis_it != axis_map.end()) { + } else if (axis_it != axis_map.end()) { data->first->controller->Axis(0, axis_it->second.axis, Input::GetAxis(-0x80, 0x80, 0)); } - + return 0; } data->first->updateModKeyedInputsManually(binding); - delete data->second; + delete data->second; delete data; return 0; // Return 0 to stop the timer after firing once } @@ -366,7 +440,8 @@ Uint32 WindowSDL::mousePolling(void* param, Uint32 id, Uint32 interval) { } void WindowSDL::updateMouse() { - if(!mouse_enabled) return; + if (!mouse_enabled) + return; Input::Axis axis_x, axis_y; switch (mouse_joystick_binding) { case 1: @@ -459,7 +534,7 @@ void WindowSDL::waitEvent() { if (mouse_polling_id == 0) { mouse_polling_id = SDL_AddTimer(33, mousePolling, (void*)this); } - + if (!SDL_WaitEvent(&event)) { return; } @@ -544,8 +619,8 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { // Extract key and modifier KeyBinding binding(event); bool input_down = event->type == SDL_EVENT_KEY_DOWN || - event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || - event->type == SDL_EVENT_MOUSE_WHEEL; + event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || + event->type == SDL_EVENT_MOUSE_WHEEL; u32 button = 0; Input::Axis axis = Input::Axis::AxisMax; @@ -583,7 +658,7 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { auto button_it = FindKeyAllowingPartialModifiers(button_map, binding); auto axis_it = FindKeyAllowingPartialModifiers(axis_map, binding); // then no mod key matches if we didn't find it in the previous pass - if (button_it == button_map.end() && axis_it == axis_map.end() ) { + if (button_it == button_map.end() && axis_it == axis_map.end()) { button_it = FindKeyAllowingOnlyNoModifiers(button_map, binding); } if (axis_it == axis_map.end() && button_it == button_map.end()) { @@ -595,9 +670,7 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { } if (axis_it != axis_map.end()) { axis = axis_it->second.axis; - axis_value = (input_down) - ? axis_it->second.value - : 0; + axis_value = (input_down) ? axis_it->second.value : 0; int ax = Input::GetAxis(-0x80, 0x80, axis_value); controller->Axis(0, axis, ax); } From f486663c8903f38c01f8672063ab9bcabc675e04 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Mon, 14 Oct 2024 20:47:14 +0200 Subject: [PATCH 17/79] added keybinds for "walk mode" --- src/sdl_window.cpp | 73 +++++++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 72028c668e5..013c6dadeaa 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -34,6 +34,9 @@ #define SDL_EVENT_MOUSE_WHEEL_LEFT SDL_EVENT_MOUSE_WHEEL + 5 #define SDL_EVENT_MOUSE_WHEEL_RIGHT SDL_EVENT_MOUSE_WHEEL + 6 +#define LEFTJOYSTICK_HALFMODE 0x00010000 +#define RIGHTJOYSTICK_HALFMODE 0x00020000 + Uint32 getMouseWheelEvent(const SDL_Event* event) { if (event->type != SDL_EVENT_MOUSE_WHEEL) return 0; @@ -119,7 +122,10 @@ std::map string_to_cbutton_map = { {"up", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP}, {"down", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN}, {"left", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT}, - {"right", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT}}; + {"right", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT}, + {"leftjoystick_halfmode", LEFTJOYSTICK_HALFMODE}, + {"rightjoystick_halfmode", RIGHTJOYSTICK_HALFMODE}, +}; std::map string_to_axis_map = { {"axis_left_x_plus", {Input::Axis::LeftX, 127}}, {"axis_left_x_minus", {Input::Axis::LeftX, -127}}, @@ -241,9 +247,12 @@ std::map axis_map = {}; int mouse_joystick_binding = 0; Uint32 mouse_polling_id = 0; -bool mouse_enabled = true; -const std::string default_config = - R"(## SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +bool mouse_enabled = true, leftjoystick_halfmode = false, rightjoystick_halfmode = false; + +// i wrapped it in a function so I can collapse it +std::string getDefaultConfig() { + std::string default_config = + R"(## SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project ## SPDX-License-Identifier: GPL-2.0-or-later #Default controller button mappings @@ -259,7 +268,7 @@ const std::string default_config = #This is a mapping for Bloodborne, inspired by other Souls titles on PC. #This is a quick and dirty implementation of binding the mouse to a user-specified joystick -mouse_to_joystick = left; +mouse_to_joystick = right; #Use another item(healing), change status in inventory triangle = f; @@ -304,6 +313,8 @@ axis_left_x_plus = d; axis_left_y_minus = w; axis_left_y_plus = s; )"; + return default_config; +} void WindowSDL::parseInputConfig(const std::string& filename) { @@ -315,7 +326,7 @@ void WindowSDL::parseInputConfig(const std::string& filename) { std::ofstream file; file.open(config_file, std::ios::out); if (file.is_open()) { - file << default_config; + file << getDefaultConfig(); file.close(); std::cout << "Config file generated.\n"; } else { @@ -464,11 +475,11 @@ void WindowSDL::updateMouse() { float a_x = cos(angle) * 128.0, a_y = sin(angle) * 128.0; if (d_x != 0 && d_y != 0) { - controller->Axis(0, Input::Axis::RightX, Input::GetAxis(-0x80, 0x80, a_x)); - controller->Axis(0, Input::Axis::RightY, Input::GetAxis(-0x80, 0x80, a_y)); + controller->Axis(0, axis_x, Input::GetAxis(-0x80, 0x80, a_x)); + controller->Axis(0, axis_y, Input::GetAxis(-0x80, 0x80, a_y)); } else { - controller->Axis(0, Input::Axis::RightX, Input::GetAxis(-0x80, 0x80, 0)); - controller->Axis(0, Input::Axis::RightY, Input::GetAxis(-0x80, 0x80, 0)); + controller->Axis(0, axis_x, Input::GetAxis(-0x80, 0x80, 0)); + controller->Axis(0, axis_y, Input::GetAxis(-0x80, 0x80, 0)); } } @@ -622,10 +633,6 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || event->type == SDL_EVENT_MOUSE_WHEEL; - u32 button = 0; - Input::Axis axis = Input::Axis::AxisMax; - int axis_value = 0; - // Handle window controls outside of the input maps if (event->type == SDL_EVENT_KEY_DOWN) { // Toggle capture of the mouse @@ -634,21 +641,21 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { !SDL_GetWindowRelativeMouseMode(this->GetSdlWindow())); } // Reparse kbm inputs - if (binding.key == SDLK_F8) { + else if (binding.key == SDLK_F8) { parseInputConfig("keyboardInputConfig.ini"); } // Toggle mouse movement input - if (binding.key == SDLK_F7) { + else if (binding.key == SDLK_F7) { mouse_enabled = !mouse_enabled; } // Toggle fullscreen - if (binding.key == SDLK_F11) { + else if (binding.key == SDLK_F11) { SDL_WindowFlags flag = SDL_GetWindowFlags(window); bool is_fullscreen = flag & SDL_WINDOW_FULLSCREEN; SDL_SetWindowFullscreen(window, !is_fullscreen); } // Trigger rdoc capture - if (binding.key == SDLK_F12) { + else if (binding.key == SDLK_F12) { VideoCore::TriggerCapture(); } } @@ -664,13 +671,37 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { if (axis_it == axis_map.end() && button_it == button_map.end()) { axis_it = FindKeyAllowingOnlyNoModifiers(axis_map, binding); } + if (button_it != button_map.end()) { - button = button_it->second; - WindowSDL::updateButton(binding, button, input_down); + // test + if (button_it->second == LEFTJOYSTICK_HALFMODE) { + leftjoystick_halfmode = input_down; + // std::cout << "walk mode is " << (joystick_halfmode ? "on" : "off") << "\n"; + } else if (button_it->second == RIGHTJOYSTICK_HALFMODE) { + rightjoystick_halfmode = input_down; + } else { + WindowSDL::updateButton(binding, button_it->second, input_down); + } } if (axis_it != axis_map.end()) { + Input::Axis axis = Input::Axis::AxisMax; + int axis_value = 0; axis = axis_it->second.axis; - axis_value = (input_down) ? axis_it->second.value : 0; + float multiplier = 1.0; + switch (axis) { + case Input::Axis::LeftX: + case Input::Axis::LeftY: + multiplier = leftjoystick_halfmode ? 0.5 : 1.0; + break; + case Input::Axis::RightX: + case Input::Axis::RightY: + multiplier = rightjoystick_halfmode ? 0.5 : 1.0; + break; + default: + break; + } + multiplier = leftjoystick_halfmode ? 0.5 : 1.0; + axis_value = (input_down ? axis_it->second.value : 0) * multiplier; int ax = Input::GetAxis(-0x80, 0x80, axis_value); controller->Axis(0, axis, ax); } From bd2acfa34968c119c68c3f0e89b040e90e5bce26 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Tue, 15 Oct 2024 07:25:44 +0200 Subject: [PATCH 18/79] Mouse movement input is now off by default --- src/sdl_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 013c6dadeaa..88a611538b0 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -247,7 +247,7 @@ std::map axis_map = {}; int mouse_joystick_binding = 0; Uint32 mouse_polling_id = 0; -bool mouse_enabled = true, leftjoystick_halfmode = false, rightjoystick_halfmode = false; +bool mouse_enabled = false, leftjoystick_halfmode = false, rightjoystick_halfmode = false; // i wrapped it in a function so I can collapse it std::string getDefaultConfig() { From 4c6bee815e53dbd783e9d7c3dc5daea969528c74 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Tue, 15 Oct 2024 08:44:12 +0200 Subject: [PATCH 19/79] code cleanup and misc fixes --- src/sdl_window.cpp | 36 +++++++++++++++++------------------- src/sdl_window.h | 2 +- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 88a611538b0..8373f44eb12 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -245,6 +245,7 @@ std::map string_to_keyboard_mod_key_map = { std::map button_map = {}; std::map axis_map = {}; +// Flags for varying purposes int mouse_joystick_binding = 0; Uint32 mouse_polling_id = 0; bool mouse_enabled = false, leftjoystick_halfmode = false, rightjoystick_halfmode = false; @@ -319,7 +320,6 @@ axis_left_y_plus = s; void WindowSDL::parseInputConfig(const std::string& filename) { // Read configuration file. - // std::cout << "Reading keyboard config...\n"; const auto config_file = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / filename; if (!std::filesystem::exists(config_file)) { // create it @@ -342,7 +342,7 @@ void WindowSDL::parseInputConfig(const std::string& filename) { button_map.clear(); axis_map.clear(); int lineCount = 0; - std::string line; + std::string line = ""; while (std::getline(file, line)) { lineCount++; // strip the ; and whitespace @@ -418,7 +418,6 @@ void WindowSDL::parseInputConfig(const std::string& filename) { } else { std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount << " line data: " << line << "\n"; - continue; // skip } } file.close(); @@ -541,7 +540,7 @@ WindowSDL::~WindowSDL() = default; void WindowSDL::waitEvent() { // Called on main thread - SDL_Event event; + SDL_Event event{}; if (mouse_polling_id == 0) { mouse_polling_id = SDL_AddTimer(33, mousePolling, (void*)this); } @@ -577,7 +576,7 @@ void WindowSDL::waitEvent() { case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: SDL_AddTimer(33, keyRepeatCallback, (void*)payload_to_timer); - onKeyPress(&event); + onKeyboardMouseEvent(&event); break; case SDL_EVENT_GAMEPAD_BUTTON_DOWN: case SDL_EVENT_GAMEPAD_BUTTON_UP: @@ -601,9 +600,10 @@ void WindowSDL::onResize() { ImGui::Core::OnResize(); } +// for L2/R2, touchpad and normal buttons void WindowSDL::updateButton(KeyBinding& binding, u32 button, bool is_pressed) { - float x; - Input::Axis axis; + float touchpad_x = 0; + Input::Axis axis = Input::Axis::AxisMax; switch (button) { case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2: case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2: @@ -614,10 +614,10 @@ void WindowSDL::updateButton(KeyBinding& binding, u32 button, bool is_pressed) { controller->Axis(0, axis, Input::GetAxis(0, 0x80, is_pressed ? 255 : 0)); break; case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD: - x = Config::getBackButtonBehavior() == "left" ? 0.25f - : Config::getBackButtonBehavior() == "right" ? 0.75f - : 0.5f; - controller->SetTouchpadState(0, true, x, 0.5f); + touchpad_x = Config::getBackButtonBehavior() == "left" ? 0.25f + : Config::getBackButtonBehavior() == "right" ? 0.75f + : 0.5f; + controller->SetTouchpadState(0, true, touchpad_x, 0.5f); controller->CheckButton(0, button, is_pressed); break; default: // is a normal key @@ -626,9 +626,11 @@ void WindowSDL::updateButton(KeyBinding& binding, u32 button, bool is_pressed) { } } -void WindowSDL::onKeyPress(const SDL_Event* event) { +// previously onKeyPress +void WindowSDL::onKeyboardMouseEvent(const SDL_Event* event) { // Extract key and modifier KeyBinding binding(event); + bool input_down = event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || event->type == SDL_EVENT_MOUSE_WHEEL; @@ -673,10 +675,9 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { } if (button_it != button_map.end()) { - // test + // joystick_halfmode is not a button update so we handle it differently if (button_it->second == LEFTJOYSTICK_HALFMODE) { leftjoystick_halfmode = input_down; - // std::cout << "walk mode is " << (joystick_halfmode ? "on" : "off") << "\n"; } else if (button_it->second == RIGHTJOYSTICK_HALFMODE) { rightjoystick_halfmode = input_down; } else { @@ -684,9 +685,7 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { } } if (axis_it != axis_map.end()) { - Input::Axis axis = Input::Axis::AxisMax; - int axis_value = 0; - axis = axis_it->second.axis; + Input::Axis axis = axis_it->second.axis; float multiplier = 1.0; switch (axis) { case Input::Axis::LeftX: @@ -700,8 +699,7 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { default: break; } - multiplier = leftjoystick_halfmode ? 0.5 : 1.0; - axis_value = (input_down ? axis_it->second.value : 0) * multiplier; + int axis_value = (input_down ? axis_it->second.value : 0) * multiplier; int ax = Input::GetAxis(-0x80, 0x80, axis_value); controller->Axis(0, axis, ax); } diff --git a/src/sdl_window.h b/src/sdl_window.h index 9900125bf77..6d716f551da 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -83,7 +83,7 @@ class WindowSDL { private: void onResize(); - void onKeyPress(const SDL_Event* event); + void onKeyboardMouseEvent(const SDL_Event* event); void onGamepadEvent(const SDL_Event* event); int sdlGamepadToOrbisButton(u8 button); From 60d9e7b88973094fc392646a7ce75022bb919698 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Tue, 15 Oct 2024 09:00:50 +0200 Subject: [PATCH 20/79] delete config file since it is now autogenerated --- user/keyboardInputConfig.ini | 76 ------------------------------------ 1 file changed, 76 deletions(-) delete mode 100644 user/keyboardInputConfig.ini diff --git a/user/keyboardInputConfig.ini b/user/keyboardInputConfig.ini deleted file mode 100644 index af44beef3ce..00000000000 --- a/user/keyboardInputConfig.ini +++ /dev/null @@ -1,76 +0,0 @@ -## SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project -## SPDX-License-Identifier: GPL-2.0-or-later - -#Controller button mappings - -#Taken keys: -#F11 : fullscreen -#F10 : FPS counter -#F9 : toggle mouse capture -#F8 : reparse keyboard input(this) - -#This is a mapping for Bloodborne, inspired by other Souls titles on PC. - -#This is a quick and dirty implementation of binding the mouse to a user-specified joystick -mouse_to_joystick = left; - -#Use another item(healing), change status in inventory -triangle = f; - -#Dodge, back in inventory -circle = space; - -#Interact, select item in inventory -cross = e; - -#Use quick item, remove item in inventory -square = r; - -#Emergency extra bullets -up = w, lalt; - -#Change quick item -down = s, lalt; - -#Change weapon in left hand -left = a, lalt; - -#Change weapon in right hand -right = d, lalt; - -#Menu -options = escape; - -#Gestures -touchpad = g; - -#Transform -l1 = rightbutton, lshift; - -#Shoot -r1 = leftbutton; - -#Light attack -l2 = rightbutton; - -#Heavy attack -r2 = leftbutton, lshift; - -#Does nothing -l3 = x; - -#Center cam, lock on -r3 = q; - -#Axis mappings -#Move -axis_left_x_minus = a; -axis_left_x_plus = d; -axis_left_y_minus = w; -axis_left_y_plus = s; - -#Original camera input(disabled in current config) -#axis_right_x_minus = j -#axis_right_x_plus = l -#axis_right_y_minus = i -#axis_right_y_plus = k From a76b79204da74c72bb89261fb1713cf8aa9e4625 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Tue, 15 Oct 2024 19:05:54 +0200 Subject: [PATCH 21/79] F6 = F7 + F9 --- src/sdl_window.cpp | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 8373f44eb12..03b6431e5f9 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -173,20 +173,20 @@ std::map string_to_keyboard_key_map = { {"7", SDLK_7}, {"8", SDLK_8}, {"9", SDLK_9}, - {",", SDLK_COMMA}, - {".", SDLK_PERIOD}, - {"?", SDLK_QUESTION}, - {";", SDLK_SEMICOLON}, - {"-", SDLK_MINUS}, - {"_", SDLK_UNDERSCORE}, - {"(", SDLK_LEFTPAREN}, - {")", SDLK_RIGHTPAREN}, - {"[", SDLK_LEFTBRACKET}, - {"]", SDLK_RIGHTBRACKET}, - {"{", SDLK_LEFTBRACE}, - {"}", SDLK_RIGHTBRACE}, - {"\\", SDLK_BACKSLASH}, - {"/", SDLK_SLASH}, + {"comma", SDLK_COMMA}, + {"period", SDLK_PERIOD}, + {"question", SDLK_QUESTION}, + {"semicolon", SDLK_SEMICOLON}, + {"minus", SDLK_MINUS}, + {"underscore", SDLK_UNDERSCORE}, + {"lparenthesis", SDLK_LEFTPAREN}, + {"rparenthesis", SDLK_RIGHTPAREN}, + {"lbracket", SDLK_LEFTBRACKET}, + {"rbracket", SDLK_RIGHTBRACKET}, + {"lbrace", SDLK_LEFTBRACE}, + {"rbrace", SDLK_RIGHTBRACE}, + {"backslash", SDLK_BACKSLASH}, + {"dash", SDLK_SLASH}, {"enter", SDLK_RETURN}, {"space", SDLK_SPACE}, {"tab", SDLK_TAB}, @@ -650,6 +650,12 @@ void WindowSDL::onKeyboardMouseEvent(const SDL_Event* event) { else if (binding.key == SDLK_F7) { mouse_enabled = !mouse_enabled; } + // F7 + F9 + else if (binding.key == SDLK_F6) { + mouse_enabled = !mouse_enabled; + SDL_SetWindowRelativeMouseMode(this->GetSdlWindow(), + !SDL_GetWindowRelativeMouseMode(this->GetSdlWindow())); + } // Toggle fullscreen else if (binding.key == SDLK_F11) { SDL_WindowFlags flag = SDL_GetWindowFlags(window); From 92bbe40d8e716e3ae9cf5d9f93c42ac39e211b0c Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Wed, 16 Oct 2024 14:54:59 +0200 Subject: [PATCH 22/79] added better mouse handling with config options --- src/sdl_window.cpp | 168 ++++++++++++++++++++------------------------- 1 file changed, 76 insertions(+), 92 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 03b6431e5f9..a07dab0182a 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -137,75 +137,45 @@ std::map string_to_axis_map = { {"axis_right_y_minus", {Input::Axis::RightY, -127}}, }; std::map string_to_keyboard_key_map = { - {"a", SDLK_A}, - {"b", SDLK_B}, - {"c", SDLK_C}, - {"d", SDLK_D}, - {"e", SDLK_E}, - {"f", SDLK_F}, - {"g", SDLK_G}, - {"h", SDLK_H}, - {"i", SDLK_I}, - {"j", SDLK_J}, - {"k", SDLK_K}, - {"l", SDLK_L}, - {"m", SDLK_M}, - {"n", SDLK_N}, - {"o", SDLK_O}, - {"p", SDLK_P}, - {"q", SDLK_Q}, - {"r", SDLK_R}, - {"s", SDLK_S}, - {"t", SDLK_T}, - {"u", SDLK_U}, - {"v", SDLK_V}, - {"w", SDLK_W}, - {"x", SDLK_X}, - {"y", SDLK_Y}, - {"z", SDLK_Z}, - {"0", SDLK_0}, - {"1", SDLK_1}, - {"2", SDLK_2}, - {"3", SDLK_3}, - {"4", SDLK_4}, - {"5", SDLK_5}, - {"6", SDLK_6}, - {"7", SDLK_7}, - {"8", SDLK_8}, - {"9", SDLK_9}, - {"comma", SDLK_COMMA}, - {"period", SDLK_PERIOD}, - {"question", SDLK_QUESTION}, - {"semicolon", SDLK_SEMICOLON}, - {"minus", SDLK_MINUS}, - {"underscore", SDLK_UNDERSCORE}, - {"lparenthesis", SDLK_LEFTPAREN}, - {"rparenthesis", SDLK_RIGHTPAREN}, - {"lbracket", SDLK_LEFTBRACKET}, - {"rbracket", SDLK_RIGHTBRACKET}, - {"lbrace", SDLK_LEFTBRACE}, - {"rbrace", SDLK_RIGHTBRACE}, - {"backslash", SDLK_BACKSLASH}, - {"dash", SDLK_SLASH}, + {"a", SDLK_A}, {"b", SDLK_B}, {"c", SDLK_C}, {"d", SDLK_D}, + {"e", SDLK_E}, {"f", SDLK_F}, {"g", SDLK_G}, {"h", SDLK_H}, + {"i", SDLK_I}, {"j", SDLK_J}, {"k", SDLK_K}, {"l", SDLK_L}, + {"m", SDLK_M}, {"n", SDLK_N}, {"o", SDLK_O}, {"p", SDLK_P}, + {"q", SDLK_Q}, {"r", SDLK_R}, {"s", SDLK_S}, {"t", SDLK_T}, + {"u", SDLK_U}, {"v", SDLK_V}, {"w", SDLK_W}, {"x", SDLK_X}, + {"y", SDLK_Y}, {"z", SDLK_Z}, + {"0", SDLK_0}, {"1", SDLK_1}, {"2", SDLK_2}, {"3", SDLK_3}, + {"4", SDLK_4}, {"5", SDLK_5}, {"6", SDLK_6}, {"7", SDLK_7}, + {"8", SDLK_8}, {"9", SDLK_9}, + {"kp0", SDLK_KP_0}, {"kp1", SDLK_KP_1}, {"kp2", SDLK_KP_2}, {"kp3", SDLK_KP_3}, + {"kp4", SDLK_KP_4}, {"kp5", SDLK_KP_5}, {"kp6", SDLK_KP_6}, {"kp7", SDLK_KP_7}, + {"kp8", SDLK_KP_8}, {"kp9", SDLK_KP_9}, + {",", SDLK_COMMA}, + {".", SDLK_PERIOD}, + {"?", SDLK_QUESTION}, + {";", SDLK_SEMICOLON}, + {"-", SDLK_MINUS}, + {"_", SDLK_UNDERSCORE}, + {"(", SDLK_LEFTPAREN}, + {")", SDLK_RIGHTPAREN}, + {"[", SDLK_LEFTBRACKET}, + {"]", SDLK_RIGHTBRACKET}, + {"{", SDLK_LEFTBRACE}, + {"}", SDLK_RIGHTBRACE}, + {"\\", SDLK_BACKSLASH}, + {"/", SDLK_SLASH}, {"enter", SDLK_RETURN}, {"space", SDLK_SPACE}, {"tab", SDLK_TAB}, {"backspace", SDLK_BACKSPACE}, {"escape", SDLK_ESCAPE}, - {"left", SDLK_LEFT}, - {"right", SDLK_RIGHT}, - {"up", SDLK_UP}, - {"down", SDLK_DOWN}, - {"lctrl", SDLK_LCTRL}, - {"rctrl", SDLK_RCTRL}, - {"lshift", SDLK_LSHIFT}, - {"rshift", SDLK_RSHIFT}, - {"lalt", SDLK_LALT}, - {"ralt", SDLK_RALT}, - {"lmeta", SDLK_LGUI}, - {"rmeta", SDLK_RGUI}, - {"lwin", SDLK_LGUI}, - {"rwin", SDLK_RGUI}, + {"left", SDLK_LEFT}, {"right", SDLK_RIGHT}, + {"up", SDLK_UP}, {"down", SDLK_DOWN}, + {"lctrl", SDLK_LCTRL}, {"rctrl", SDLK_RCTRL}, + {"lshift", SDLK_LSHIFT}, {"rshift", SDLK_RSHIFT}, + {"lalt", SDLK_LALT}, {"ralt", SDLK_RALT}, + {"lmeta", SDLK_LGUI}, {"rmeta", SDLK_RGUI}, + {"lwin", SDLK_LGUI}, {"rwin", SDLK_RGUI}, {"leftbutton", SDL_BUTTON_LEFT}, {"rightbutton", SDL_BUTTON_RIGHT}, {"middlebutton", SDL_BUTTON_MIDDLE}, @@ -213,24 +183,10 @@ std::map string_to_keyboard_key_map = { {"mousewheeldown", SDL_EVENT_MOUSE_WHEEL_DOWN}, {"mousewheelleft", SDL_EVENT_MOUSE_WHEEL_LEFT}, {"mousewheelright", SDL_EVENT_MOUSE_WHEEL_RIGHT}, - {"kp0", SDLK_KP_0}, - {"kp1", SDLK_KP_1}, - {"kp2", SDLK_KP_2}, - {"kp3", SDLK_KP_3}, - {"kp4", SDLK_KP_4}, - {"kp5", SDLK_KP_5}, - {"kp6", SDLK_KP_6}, - {"kp7", SDLK_KP_7}, - {"kp8", SDLK_KP_8}, - {"kp9", SDLK_KP_9}, - {"kpperiod", SDLK_KP_PERIOD}, - {"kpdivide", SDLK_KP_DIVIDE}, - {"kpmultiply", SDLK_KP_MULTIPLY}, - {"kpminus", SDLK_KP_MINUS}, - {"kpplus", SDLK_KP_PLUS}, - {"kpenter", SDLK_KP_ENTER}, - {"kpequals", SDLK_KP_EQUALS}, - {"kpcomma", SDLK_KP_COMMA}, + {"kpperiod", SDLK_KP_PERIOD}, {"kpcomma", SDLK_KP_COMMA}, + {"kpdivide", SDLK_KP_DIVIDE}, {"kpmultiply", SDLK_KP_MULTIPLY}, + {"kpminus", SDLK_KP_MINUS}, {"kpplus", SDLK_KP_PLUS}, + {"kpenter", SDLK_KP_ENTER}, {"kpequals", SDLK_KP_EQUALS}, }; std::map string_to_keyboard_mod_key_map = { {"lshift", SDL_KMOD_LSHIFT}, {"rshift", SDL_KMOD_RSHIFT}, {"lctrl", SDL_KMOD_LCTRL}, @@ -245,13 +201,14 @@ std::map string_to_keyboard_mod_key_map = { std::map button_map = {}; std::map axis_map = {}; -// Flags for varying purposes +// Flags and values for varying purposes int mouse_joystick_binding = 0; +float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.125; Uint32 mouse_polling_id = 0; bool mouse_enabled = false, leftjoystick_halfmode = false, rightjoystick_halfmode = false; // i wrapped it in a function so I can collapse it -std::string getDefaultConfig() { +std::string getDefaultKeyboardConfig() { std::string default_config = R"(## SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project ## SPDX-License-Identifier: GPL-2.0-or-later @@ -318,7 +275,6 @@ axis_left_y_plus = s; } void WindowSDL::parseInputConfig(const std::string& filename) { - // Read configuration file. const auto config_file = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / filename; if (!std::filesystem::exists(config_file)) { @@ -326,7 +282,7 @@ void WindowSDL::parseInputConfig(const std::string& filename) { std::ofstream file; file.open(config_file, std::ios::out); if (file.is_open()) { - file << getDefaultConfig(); + file << getDefaultKeyboardConfig(); file.close(); std::cout << "Config file generated.\n"; } else { @@ -338,7 +294,10 @@ void WindowSDL::parseInputConfig(const std::string& filename) { std::cerr << "Error opening file: " << filename << std::endl; return; } - + // we reset this here so in case the user fucks up we can fall back to default + mouse_deadzone_offset = 0.5; + mouse_speed = 1; + mouse_speed_offset = 0.125; button_map.clear(); axis_map.clear(); int lineCount = 0; @@ -391,6 +350,26 @@ void WindowSDL::parseInputConfig(const std::string& filename) { mod_it != string_to_keyboard_mod_key_map.end()) { binding.key = key_it->second; binding.modifier = mod_it->second; + } else if (controller_input == "mouse_movement_params") { + // handle mouse movement params + float p1 = 0.5, p2 = 1, p3 = 0.125; + std::size_t second_comma_pos = kbm_input.find(','); + try{ + p1 = std::stof(key); + p2 = std::stof(mod.substr(0, second_comma_pos)); + p3 = std::stof(mod.substr(second_comma_pos + 1)); + mouse_deadzone_offset = p1; + mouse_speed = p2; + mouse_speed_offset = p3; + } catch (...) { + // fallback to default values + mouse_deadzone_offset = 0.5; + mouse_speed = 1; + mouse_speed_offset = 0.125; + std::cerr << "Parsing error while parsing kbm inputs at line " << lineCount + << " line data: " << line << "\n"; + } + continue; } else { std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount << " line data: " << line << "\n"; @@ -470,8 +449,11 @@ void WindowSDL::updateMouse() { float d_x = 0, d_y = 0; SDL_GetRelativeMouseState(&d_x, &d_y); + float output_speed = SDL_clamp((sqrt(d_x*d_x + d_y*d_y) + mouse_speed_offset * 128) * mouse_speed, mouse_deadzone_offset * 128, 128.0); + //std::cout << "speed: " << mouse_speed << "\n"; + float angle = atan2(d_y, d_x); - float a_x = cos(angle) * 128.0, a_y = sin(angle) * 128.0; + float a_x = cos(angle) * output_speed, a_y = sin(angle) * output_speed; if (d_x != 0 && d_y != 0) { controller->Axis(0, axis_x, Input::GetAxis(-0x80, 0x80, a_x)); @@ -534,6 +516,10 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_ #endif // initialize kbm controls parseInputConfig("keyboardInputConfig.ini"); + // Start polling the mouse + if (mouse_polling_id == 0) { + mouse_polling_id = SDL_AddTimer(33, mousePolling, (void*)this); + } } WindowSDL::~WindowSDL() = default; @@ -541,14 +527,12 @@ WindowSDL::~WindowSDL() = default; void WindowSDL::waitEvent() { // Called on main thread SDL_Event event{}; - if (mouse_polling_id == 0) { - mouse_polling_id = SDL_AddTimer(33, mousePolling, (void*)this); - } + + if (!SDL_WaitEvent(&event)) { return; } - if (ImGui::Core::ProcessEvent(&event)) { return; } From 1788aed1fda17f79a9df0b9e570e53c5a11132b7 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Wed, 16 Oct 2024 21:12:55 +0200 Subject: [PATCH 23/79] Added capslock support --- src/sdl_window.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index a07dab0182a..d623076bcab 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -187,6 +187,7 @@ std::map string_to_keyboard_key_map = { {"kpdivide", SDLK_KP_DIVIDE}, {"kpmultiply", SDLK_KP_MULTIPLY}, {"kpminus", SDLK_KP_MINUS}, {"kpplus", SDLK_KP_PLUS}, {"kpenter", SDLK_KP_ENTER}, {"kpequals", SDLK_KP_EQUALS}, + {"capslock", SDLK_CAPSLOCK}, }; std::map string_to_keyboard_mod_key_map = { {"lshift", SDL_KMOD_LSHIFT}, {"rshift", SDL_KMOD_RSHIFT}, {"lctrl", SDL_KMOD_LCTRL}, @@ -194,6 +195,7 @@ std::map string_to_keyboard_mod_key_map = { {"shift", SDL_KMOD_SHIFT}, {"ctrl", SDL_KMOD_CTRL}, {"alt", SDL_KMOD_ALT}, {"l_meta", SDL_KMOD_LGUI}, {"r_meta", SDL_KMOD_RGUI}, {"meta", SDL_KMOD_GUI}, {"lwin", SDL_KMOD_LGUI}, {"rwin", SDL_KMOD_RGUI}, {"win", SDL_KMOD_GUI}, + {"capslock", SDL_KMOD_CAPS}, {"none", SDL_KMOD_NONE}, // if you want to be fancy }; From b00ebf317ab3e81c10a22ca32db2971d3388bf84 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Thu, 17 Oct 2024 10:36:45 +0200 Subject: [PATCH 24/79] fix clang-format --- src/sdl_window.cpp | 137 +++++++++++++++++++++++++++++---------------- 1 file changed, 90 insertions(+), 47 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index d623076bcab..51ca8d2171c 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -137,45 +137,85 @@ std::map string_to_axis_map = { {"axis_right_y_minus", {Input::Axis::RightY, -127}}, }; std::map string_to_keyboard_key_map = { - {"a", SDLK_A}, {"b", SDLK_B}, {"c", SDLK_C}, {"d", SDLK_D}, - {"e", SDLK_E}, {"f", SDLK_F}, {"g", SDLK_G}, {"h", SDLK_H}, - {"i", SDLK_I}, {"j", SDLK_J}, {"k", SDLK_K}, {"l", SDLK_L}, - {"m", SDLK_M}, {"n", SDLK_N}, {"o", SDLK_O}, {"p", SDLK_P}, - {"q", SDLK_Q}, {"r", SDLK_R}, {"s", SDLK_S}, {"t", SDLK_T}, - {"u", SDLK_U}, {"v", SDLK_V}, {"w", SDLK_W}, {"x", SDLK_X}, - {"y", SDLK_Y}, {"z", SDLK_Z}, - {"0", SDLK_0}, {"1", SDLK_1}, {"2", SDLK_2}, {"3", SDLK_3}, - {"4", SDLK_4}, {"5", SDLK_5}, {"6", SDLK_6}, {"7", SDLK_7}, - {"8", SDLK_8}, {"9", SDLK_9}, - {"kp0", SDLK_KP_0}, {"kp1", SDLK_KP_1}, {"kp2", SDLK_KP_2}, {"kp3", SDLK_KP_3}, - {"kp4", SDLK_KP_4}, {"kp5", SDLK_KP_5}, {"kp6", SDLK_KP_6}, {"kp7", SDLK_KP_7}, - {"kp8", SDLK_KP_8}, {"kp9", SDLK_KP_9}, - {",", SDLK_COMMA}, - {".", SDLK_PERIOD}, - {"?", SDLK_QUESTION}, - {";", SDLK_SEMICOLON}, - {"-", SDLK_MINUS}, - {"_", SDLK_UNDERSCORE}, - {"(", SDLK_LEFTPAREN}, - {")", SDLK_RIGHTPAREN}, - {"[", SDLK_LEFTBRACKET}, - {"]", SDLK_RIGHTBRACKET}, - {"{", SDLK_LEFTBRACE}, - {"}", SDLK_RIGHTBRACE}, - {"\\", SDLK_BACKSLASH}, - {"/", SDLK_SLASH}, + {"a", SDLK_A}, + {"b", SDLK_B}, + {"c", SDLK_C}, + {"d", SDLK_D}, + {"e", SDLK_E}, + {"f", SDLK_F}, + {"g", SDLK_G}, + {"h", SDLK_H}, + {"i", SDLK_I}, + {"j", SDLK_J}, + {"k", SDLK_K}, + {"l", SDLK_L}, + {"m", SDLK_M}, + {"n", SDLK_N}, + {"o", SDLK_O}, + {"p", SDLK_P}, + {"q", SDLK_Q}, + {"r", SDLK_R}, + {"s", SDLK_S}, + {"t", SDLK_T}, + {"u", SDLK_U}, + {"v", SDLK_V}, + {"w", SDLK_W}, + {"x", SDLK_X}, + {"y", SDLK_Y}, + {"z", SDLK_Z}, + {"0", SDLK_0}, + {"1", SDLK_1}, + {"2", SDLK_2}, + {"3", SDLK_3}, + {"4", SDLK_4}, + {"5", SDLK_5}, + {"6", SDLK_6}, + {"7", SDLK_7}, + {"8", SDLK_8}, + {"9", SDLK_9}, + {"kp0", SDLK_KP_0}, + {"kp1", SDLK_KP_1}, + {"kp2", SDLK_KP_2}, + {"kp3", SDLK_KP_3}, + {"kp4", SDLK_KP_4}, + {"kp5", SDLK_KP_5}, + {"kp6", SDLK_KP_6}, + {"kp7", SDLK_KP_7}, + {"kp8", SDLK_KP_8}, + {"kp9", SDLK_KP_9}, + {"comma", SDLK_COMMA}, + {"period", SDLK_PERIOD}, + {"question", SDLK_QUESTION}, + {"semicolon", SDLK_SEMICOLON}, + {"minus", SDLK_MINUS}, + {"underscore", SDLK_UNDERSCORE}, + {"lparenthesis", SDLK_LEFTPAREN}, + {"rparenthesis", SDLK_RIGHTPAREN}, + {"lbracket", SDLK_LEFTBRACKET}, + {"rbracket", SDLK_RIGHTBRACKET}, + {"lbrace", SDLK_LEFTBRACE}, + {"rbrace", SDLK_RIGHTBRACE}, + {"backslash", SDLK_BACKSLASH}, + {"dash", SDLK_SLASH}, {"enter", SDLK_RETURN}, {"space", SDLK_SPACE}, {"tab", SDLK_TAB}, {"backspace", SDLK_BACKSPACE}, {"escape", SDLK_ESCAPE}, - {"left", SDLK_LEFT}, {"right", SDLK_RIGHT}, - {"up", SDLK_UP}, {"down", SDLK_DOWN}, - {"lctrl", SDLK_LCTRL}, {"rctrl", SDLK_RCTRL}, - {"lshift", SDLK_LSHIFT}, {"rshift", SDLK_RSHIFT}, - {"lalt", SDLK_LALT}, {"ralt", SDLK_RALT}, - {"lmeta", SDLK_LGUI}, {"rmeta", SDLK_RGUI}, - {"lwin", SDLK_LGUI}, {"rwin", SDLK_RGUI}, + {"left", SDLK_LEFT}, + {"right", SDLK_RIGHT}, + {"up", SDLK_UP}, + {"down", SDLK_DOWN}, + {"lctrl", SDLK_LCTRL}, + {"rctrl", SDLK_RCTRL}, + {"lshift", SDLK_LSHIFT}, + {"rshift", SDLK_RSHIFT}, + {"lalt", SDLK_LALT}, + {"ralt", SDLK_RALT}, + {"lmeta", SDLK_LGUI}, + {"rmeta", SDLK_RGUI}, + {"lwin", SDLK_LGUI}, + {"rwin", SDLK_RGUI}, {"leftbutton", SDL_BUTTON_LEFT}, {"rightbutton", SDL_BUTTON_RIGHT}, {"middlebutton", SDL_BUTTON_MIDDLE}, @@ -183,10 +223,14 @@ std::map string_to_keyboard_key_map = { {"mousewheeldown", SDL_EVENT_MOUSE_WHEEL_DOWN}, {"mousewheelleft", SDL_EVENT_MOUSE_WHEEL_LEFT}, {"mousewheelright", SDL_EVENT_MOUSE_WHEEL_RIGHT}, - {"kpperiod", SDLK_KP_PERIOD}, {"kpcomma", SDLK_KP_COMMA}, - {"kpdivide", SDLK_KP_DIVIDE}, {"kpmultiply", SDLK_KP_MULTIPLY}, - {"kpminus", SDLK_KP_MINUS}, {"kpplus", SDLK_KP_PLUS}, - {"kpenter", SDLK_KP_ENTER}, {"kpequals", SDLK_KP_EQUALS}, + {"kpperiod", SDLK_KP_PERIOD}, + {"kpcomma", SDLK_KP_COMMA}, + {"kpdivide", SDLK_KP_DIVIDE}, + {"kpmultiply", SDLK_KP_MULTIPLY}, + {"kpminus", SDLK_KP_MINUS}, + {"kpplus", SDLK_KP_PLUS}, + {"kpenter", SDLK_KP_ENTER}, + {"kpequals", SDLK_KP_EQUALS}, {"capslock", SDLK_CAPSLOCK}, }; std::map string_to_keyboard_mod_key_map = { @@ -195,8 +239,7 @@ std::map string_to_keyboard_mod_key_map = { {"shift", SDL_KMOD_SHIFT}, {"ctrl", SDL_KMOD_CTRL}, {"alt", SDL_KMOD_ALT}, {"l_meta", SDL_KMOD_LGUI}, {"r_meta", SDL_KMOD_RGUI}, {"meta", SDL_KMOD_GUI}, {"lwin", SDL_KMOD_LGUI}, {"rwin", SDL_KMOD_RGUI}, {"win", SDL_KMOD_GUI}, - {"capslock", SDL_KMOD_CAPS}, - {"none", SDL_KMOD_NONE}, // if you want to be fancy + {"capslock", SDL_KMOD_CAPS}, {"none", SDL_KMOD_NONE}, // if you want to be fancy }; // Button map: maps key+modifier to controller button @@ -352,11 +395,11 @@ void WindowSDL::parseInputConfig(const std::string& filename) { mod_it != string_to_keyboard_mod_key_map.end()) { binding.key = key_it->second; binding.modifier = mod_it->second; - } else if (controller_input == "mouse_movement_params") { + } else if (controller_input == "mouse_movement_params") { // handle mouse movement params float p1 = 0.5, p2 = 1, p3 = 0.125; std::size_t second_comma_pos = kbm_input.find(','); - try{ + try { p1 = std::stof(key); p2 = std::stof(mod.substr(0, second_comma_pos)); p3 = std::stof(mod.substr(second_comma_pos + 1)); @@ -451,9 +494,11 @@ void WindowSDL::updateMouse() { float d_x = 0, d_y = 0; SDL_GetRelativeMouseState(&d_x, &d_y); - float output_speed = SDL_clamp((sqrt(d_x*d_x + d_y*d_y) + mouse_speed_offset * 128) * mouse_speed, mouse_deadzone_offset * 128, 128.0); - //std::cout << "speed: " << mouse_speed << "\n"; - + float output_speed = + SDL_clamp((sqrt(d_x * d_x + d_y * d_y) + mouse_speed_offset * 128) * mouse_speed, + mouse_deadzone_offset * 128, 128.0); + // std::cout << "speed: " << mouse_speed << "\n"; + float angle = atan2(d_y, d_x); float a_x = cos(angle) * output_speed, a_y = sin(angle) * output_speed; @@ -530,8 +575,6 @@ void WindowSDL::waitEvent() { // Called on main thread SDL_Event event{}; - - if (!SDL_WaitEvent(&event)) { return; } From 5fdaea80720765430205a974638c2848b2a9c563 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Thu, 17 Oct 2024 19:27:59 +0200 Subject: [PATCH 25/79] Added support for mod key toggle key --- src/sdl_window.cpp | 96 ++++++++++++++++++++++++++++++---------------- src/sdl_window.h | 1 + 2 files changed, 64 insertions(+), 33 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 51ca8d2171c..d2379511b7b 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -57,7 +57,7 @@ namespace Frontend { using Libraries::Pad::OrbisPadButtonDataOffset; KeyBinding::KeyBinding(const SDL_Event* event) { - modifier = SDL_GetModState(); + modifier = getCustomModState(); key = 0; // std::cout << "Someone called the new binding ctor!\n"; if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) { @@ -71,6 +71,7 @@ KeyBinding::KeyBinding(const SDL_Event* event) { std::cout << "We don't support this event type!\n"; } } + bool KeyBinding::operator<(const KeyBinding& other) const { return std::tie(key, modifier) < std::tie(other.key, other.modifier); } @@ -234,17 +235,31 @@ std::map string_to_keyboard_key_map = { {"capslock", SDLK_CAPSLOCK}, }; std::map string_to_keyboard_mod_key_map = { - {"lshift", SDL_KMOD_LSHIFT}, {"rshift", SDL_KMOD_RSHIFT}, {"lctrl", SDL_KMOD_LCTRL}, - {"rctrl", SDL_KMOD_RCTRL}, {"lalt", SDL_KMOD_LALT}, {"ralt", SDL_KMOD_RALT}, - {"shift", SDL_KMOD_SHIFT}, {"ctrl", SDL_KMOD_CTRL}, {"alt", SDL_KMOD_ALT}, - {"l_meta", SDL_KMOD_LGUI}, {"r_meta", SDL_KMOD_RGUI}, {"meta", SDL_KMOD_GUI}, - {"lwin", SDL_KMOD_LGUI}, {"rwin", SDL_KMOD_RGUI}, {"win", SDL_KMOD_GUI}, - {"capslock", SDL_KMOD_CAPS}, {"none", SDL_KMOD_NONE}, // if you want to be fancy + {"lshift", SDL_KMOD_LSHIFT}, {"rshift", SDL_KMOD_RSHIFT}, + {"lctrl", SDL_KMOD_LCTRL}, {"rctrl", SDL_KMOD_RCTRL}, + {"lalt", SDL_KMOD_LALT}, {"ralt", SDL_KMOD_RALT}, + {"shift", SDL_KMOD_SHIFT}, {"ctrl", SDL_KMOD_CTRL}, + {"alt", SDL_KMOD_ALT}, {"l_meta", SDL_KMOD_LGUI}, + {"r_meta", SDL_KMOD_RGUI}, {"meta", SDL_KMOD_GUI}, + {"lwin", SDL_KMOD_LGUI}, {"rwin", SDL_KMOD_RGUI}, + {"win", SDL_KMOD_GUI}, {"capslock", SDL_KMOD_CAPS}, + {"numlock", SDL_KMOD_NUM}, {"none", SDL_KMOD_NONE}, // if you want to be fancy }; // Button map: maps key+modifier to controller button std::map button_map = {}; std::map axis_map = {}; +std::map> key_to_modkey_toggle_map = {}; + +SDL_Keymod KeyBinding::getCustomModState() { + SDL_Keymod state = SDL_GetModState(); + for (auto mod_flag : key_to_modkey_toggle_map) { + if (mod_flag.second.second) { + state |= mod_flag.second.first; + } + } + return state; +} // Flags and values for varying purposes int mouse_joystick_binding = 0; @@ -339,12 +354,15 @@ void WindowSDL::parseInputConfig(const std::string& filename) { std::cerr << "Error opening file: " << filename << std::endl; return; } - // we reset this here so in case the user fucks up we can fall back to default + + // we reset these here so in case the user fucks up or doesn't include this we can fall back to + // default mouse_deadzone_offset = 0.5; mouse_speed = 1; mouse_speed_offset = 0.125; button_map.clear(); axis_map.clear(); + key_to_modkey_toggle_map.clear(); int lineCount = 0; std::string line = ""; while (std::getline(file, line)) { @@ -366,27 +384,42 @@ void WindowSDL::parseInputConfig(const std::string& filename) { continue; } - std::string controller_input = line.substr(0, equal_pos); - std::string kbm_input = line.substr(equal_pos + 1); + std::string before_equals = line.substr(0, equal_pos); + std::string after_equals = line.substr(equal_pos + 1); + std::size_t comma_pos = after_equals.find(','); KeyBinding binding = {0, SDL_KMOD_NONE}; // special check for mouse to joystick input - if (controller_input == "mouse_to_joystick") { - if (kbm_input == "left") { + if (before_equals == "mouse_to_joystick") { + if (after_equals == "left") { mouse_joystick_binding = 1; - } else if (kbm_input == "right") { + } else if (after_equals == "right") { mouse_joystick_binding = 2; } else { mouse_joystick_binding = 0; // default to 'none' or invalid } continue; } + // mod key toggle + if (before_equals == "modkey_toggle") { + if (comma_pos != std::string::npos) { + auto k = string_to_keyboard_key_map.find(after_equals.substr(0, comma_pos)); + auto m = string_to_keyboard_mod_key_map.find(after_equals.substr(comma_pos + 1)); + if (k != string_to_keyboard_key_map.end() && + m != string_to_keyboard_mod_key_map.end()) { + key_to_modkey_toggle_map[k->second] = {m->second, false}; + continue; + } + } + std::cerr << "Invalid line format at line: " << lineCount << " data: " << line + << std::endl; + continue; + } // first we parse the binding, and if its wrong, we skip to the next line - std::size_t comma_pos = kbm_input.find(','); if (comma_pos != std::string::npos) { // Handle key + modifier - std::string key = kbm_input.substr(0, comma_pos); - std::string mod = kbm_input.substr(comma_pos + 1); + std::string key = after_equals.substr(0, comma_pos); + std::string mod = after_equals.substr(comma_pos + 1); auto key_it = string_to_keyboard_key_map.find(key); auto mod_it = string_to_keyboard_mod_key_map.find(mod); @@ -395,10 +428,10 @@ void WindowSDL::parseInputConfig(const std::string& filename) { mod_it != string_to_keyboard_mod_key_map.end()) { binding.key = key_it->second; binding.modifier = mod_it->second; - } else if (controller_input == "mouse_movement_params") { + } else if (before_equals == "mouse_movement_params") { // handle mouse movement params float p1 = 0.5, p2 = 1, p3 = 0.125; - std::size_t second_comma_pos = kbm_input.find(','); + std::size_t second_comma_pos = after_equals.find(','); try { p1 = std::stof(key); p2 = std::stof(mod.substr(0, second_comma_pos)); @@ -422,7 +455,7 @@ void WindowSDL::parseInputConfig(const std::string& filename) { } } else { // Just a key without modifier - auto key_it = string_to_keyboard_key_map.find(kbm_input); + auto key_it = string_to_keyboard_key_map.find(after_equals); if (key_it != string_to_keyboard_key_map.end()) { binding.key = key_it->second; } else { @@ -433,8 +466,8 @@ void WindowSDL::parseInputConfig(const std::string& filename) { } // Check for axis mapping (example: axis_left_x_plus) - auto axis_it = string_to_axis_map.find(controller_input); - auto button_it = string_to_cbutton_map.find(controller_input); + auto axis_it = string_to_axis_map.find(before_equals); + auto button_it = string_to_cbutton_map.find(before_equals); if (axis_it != string_to_axis_map.end()) { axis_map[binding] = axis_it->second; } else if (button_it != string_to_cbutton_map.end()) { @@ -666,21 +699,12 @@ void WindowSDL::onKeyboardMouseEvent(const SDL_Event* event) { // Handle window controls outside of the input maps if (event->type == SDL_EVENT_KEY_DOWN) { - // Toggle capture of the mouse - if (binding.key == SDLK_F9) { - SDL_SetWindowRelativeMouseMode(this->GetSdlWindow(), - !SDL_GetWindowRelativeMouseMode(this->GetSdlWindow())); - } // Reparse kbm inputs - else if (binding.key == SDLK_F8) { + if (binding.key == SDLK_F8) { parseInputConfig("keyboardInputConfig.ini"); } - // Toggle mouse movement input - else if (binding.key == SDLK_F7) { - mouse_enabled = !mouse_enabled; - } - // F7 + F9 - else if (binding.key == SDLK_F6) { + // Toggle mouse capture and movement input + else if (binding.key == SDLK_F9) { mouse_enabled = !mouse_enabled; SDL_SetWindowRelativeMouseMode(this->GetSdlWindow(), !SDL_GetWindowRelativeMouseMode(this->GetSdlWindow())); @@ -697,6 +721,12 @@ void WindowSDL::onKeyboardMouseEvent(const SDL_Event* event) { } } + // Check for modifier toggle + auto modkey_toggle_it = key_to_modkey_toggle_map.find(binding.key); + modkey_toggle_it->second.second ^= + (modkey_toggle_it != key_to_modkey_toggle_map.end() && + (binding.modifier & (~modkey_toggle_it->second.first)) == SDL_KMOD_NONE && input_down); + // Check if the current key+modifier is a button or axis mapping // first only exact matches auto button_it = FindKeyAllowingPartialModifiers(button_map, binding); diff --git a/src/sdl_window.h b/src/sdl_window.h index 6d716f551da..87ba43bd41f 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -26,6 +26,7 @@ class KeyBinding { KeyBinding(const SDL_Event* event); bool operator<(const KeyBinding& other) const; ~KeyBinding(){}; + static SDL_Keymod getCustomModState(); }; enum class WindowSystemType : u8 { From 52b06c4f7b155d9d7aa561d8f81d1d68d4ebda8a Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Thu, 17 Oct 2024 19:32:02 +0200 Subject: [PATCH 26/79] F6 and F7 are removed, F9 captures and enables the mouse From 24348f6990db7be95e62347d9175d44aed2088bc Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:44:19 +0200 Subject: [PATCH 27/79] Encapsulated globals and new classes in a new namespace --- src/sdl_window.cpp | 145 +++++++++++++++++++++++---------------------- src/sdl_window.h | 16 ++++- 2 files changed, 87 insertions(+), 74 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index d2379511b7b..7cbc5864618 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -53,61 +53,11 @@ Uint32 getMouseWheelEvent(const SDL_Event* event) { return 0; } -namespace Frontend { +namespace KBMConfig { using Libraries::Pad::OrbisPadButtonDataOffset; -KeyBinding::KeyBinding(const SDL_Event* event) { - modifier = getCustomModState(); - key = 0; - // std::cout << "Someone called the new binding ctor!\n"; - if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) { - key = event->key.key; - } else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || - event->type == SDL_EVENT_MOUSE_BUTTON_UP) { - key = event->button.button; - } else if (event->type == SDL_EVENT_MOUSE_WHEEL) { - key = getMouseWheelEvent(event); - } else { - std::cout << "We don't support this event type!\n"; - } -} - -bool KeyBinding::operator<(const KeyBinding& other) const { - return std::tie(key, modifier) < std::tie(other.key, other.modifier); -} - -// modifiers are bitwise or-d together, so we need to check if ours is in that -template -typename std::map::const_iterator FindKeyAllowingPartialModifiers( - const std::map& map, KeyBinding binding) { - for (typename std::map::const_iterator it = map.cbegin(); it != map.cend(); - it++) { - if ((it->first.key == binding.key) && (it->first.modifier & binding.modifier) != 0) { - return it; - } - } - return map.end(); // Return end if no match is found -} -template -typename std::map::const_iterator FindKeyAllowingOnlyNoModifiers( - const std::map& map, KeyBinding binding) { - for (typename std::map::const_iterator it = map.cbegin(); it != map.cend(); - it++) { - if (it->first.key == binding.key && it->first.modifier == SDL_KMOD_NONE) { - return it; - } - } - return map.end(); // Return end if no match is found -} - -// Axis map: maps key+modifier to controller axis and axis value -struct AxisMapping { - Input::Axis axis; - int value; // Value to set for key press (+127 or -127 for movement) -}; - // i strongly suggest you collapse these maps -std::map string_to_cbutton_map = { +const std::map string_to_cbutton_map = { {"triangle", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE}, {"circle", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE}, {"cross", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS}, @@ -127,7 +77,7 @@ std::map string_to_cbutton_map = { {"leftjoystick_halfmode", LEFTJOYSTICK_HALFMODE}, {"rightjoystick_halfmode", RIGHTJOYSTICK_HALFMODE}, }; -std::map string_to_axis_map = { +const std::map string_to_axis_map = { {"axis_left_x_plus", {Input::Axis::LeftX, 127}}, {"axis_left_x_minus", {Input::Axis::LeftX, -127}}, {"axis_left_y_plus", {Input::Axis::LeftY, 127}}, @@ -137,7 +87,7 @@ std::map string_to_axis_map = { {"axis_right_y_plus", {Input::Axis::RightY, 127}}, {"axis_right_y_minus", {Input::Axis::RightY, -127}}, }; -std::map string_to_keyboard_key_map = { +const std::map string_to_keyboard_key_map = { {"a", SDLK_A}, {"b", SDLK_B}, {"c", SDLK_C}, @@ -234,7 +184,7 @@ std::map string_to_keyboard_key_map = { {"kpequals", SDLK_KP_EQUALS}, {"capslock", SDLK_CAPSLOCK}, }; -std::map string_to_keyboard_mod_key_map = { +const std::map string_to_keyboard_mod_key_map = { {"lshift", SDL_KMOD_LSHIFT}, {"rshift", SDL_KMOD_RSHIFT}, {"lctrl", SDL_KMOD_LCTRL}, {"rctrl", SDL_KMOD_RCTRL}, {"lalt", SDL_KMOD_LALT}, {"ralt", SDL_KMOD_RALT}, @@ -251,22 +201,6 @@ std::map button_map = {}; std::map axis_map = {}; std::map> key_to_modkey_toggle_map = {}; -SDL_Keymod KeyBinding::getCustomModState() { - SDL_Keymod state = SDL_GetModState(); - for (auto mod_flag : key_to_modkey_toggle_map) { - if (mod_flag.second.second) { - state |= mod_flag.second.first; - } - } - return state; -} - -// Flags and values for varying purposes -int mouse_joystick_binding = 0; -float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.125; -Uint32 mouse_polling_id = 0; -bool mouse_enabled = false, leftjoystick_halfmode = false, rightjoystick_halfmode = false; - // i wrapped it in a function so I can collapse it std::string getDefaultKeyboardConfig() { std::string default_config = @@ -334,6 +268,75 @@ axis_left_y_plus = s; return default_config; } +// Flags and values for varying purposes +int mouse_joystick_binding = 0; +float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.125; +Uint32 mouse_polling_id = 0; +bool mouse_enabled = false, leftjoystick_halfmode = false, rightjoystick_halfmode = false; + +KeyBinding::KeyBinding(const SDL_Event* event) { + modifier = getCustomModState(); + key = 0; + // std::cout << "Someone called the new binding ctor!\n"; + if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) { + key = event->key.key; + } else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || + event->type == SDL_EVENT_MOUSE_BUTTON_UP) { + key = event->button.button; + } else if (event->type == SDL_EVENT_MOUSE_WHEEL) { + key = getMouseWheelEvent(event); + } else { + std::cout << "We don't support this event type!\n"; + } +} + +bool KeyBinding::operator<(const KeyBinding& other) const { + return std::tie(key, modifier) < std::tie(other.key, other.modifier); +} + +SDL_Keymod KeyBinding::getCustomModState() { + SDL_Keymod state = SDL_GetModState(); + for (auto mod_flag : KBMConfig::key_to_modkey_toggle_map) { + if (mod_flag.second.second) { + state |= mod_flag.second.first; + } + } + return state; +} + +} // namespace KBMConfig + +namespace Frontend { +using Libraries::Pad::OrbisPadButtonDataOffset; + +using namespace KBMConfig; +using KBMConfig::AxisMapping; +using KBMConfig::KeyBinding; + +// modifiers are bitwise or-d together, so we need to check if ours is in that +template +typename std::map::const_iterator FindKeyAllowingPartialModifiers( + const std::map& map, KeyBinding binding) { + for (typename std::map::const_iterator it = map.cbegin(); it != map.cend(); + it++) { + if ((it->first.key == binding.key) && (it->first.modifier & binding.modifier) != 0) { + return it; + } + } + return map.end(); // Return end if no match is found +} +template +typename std::map::const_iterator FindKeyAllowingOnlyNoModifiers( + const std::map& map, KeyBinding binding) { + for (typename std::map::const_iterator it = map.cbegin(); it != map.cend(); + it++) { + if (it->first.key == binding.key && it->first.modifier == SDL_KMOD_NONE) { + return it; + } + } + return map.end(); // Return end if no match is found +} + void WindowSDL::parseInputConfig(const std::string& filename) { // Read configuration file. const auto config_file = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / filename; diff --git a/src/sdl_window.h b/src/sdl_window.h index 87ba43bd41f..4cee2369f09 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -5,6 +5,7 @@ #include #include "common/types.h" +#include "input/controller.h" #include @@ -16,7 +17,8 @@ namespace Input { class GameController; } -namespace Frontend { +namespace KBMConfig { +std::string getDefaultKeyboardConfig(); class KeyBinding { public: @@ -29,6 +31,14 @@ class KeyBinding { static SDL_Keymod getCustomModState(); }; +struct AxisMapping { + Input::Axis axis; + int value; // Value to set for key press (+127 or -127 for movement) +}; +} // namespace KBMConfig + +namespace Frontend { + enum class WindowSystemType : u8 { Headless, Windows, @@ -88,8 +98,8 @@ class WindowSDL { void onGamepadEvent(const SDL_Event* event); int sdlGamepadToOrbisButton(u8 button); - void updateModKeyedInputsManually(KeyBinding& binding); - void updateButton(KeyBinding& binding, u32 button, bool isPressed); + void updateModKeyedInputsManually(KBMConfig::KeyBinding& binding); + void updateButton(KBMConfig::KeyBinding& binding, u32 button, bool isPressed); static Uint32 keyRepeatCallback(void* param, Uint32 id, Uint32 interval); static Uint32 mousePolling(void* param, Uint32 id, Uint32 interval); From 2c913a1940f4d2b38a1a0027fdbbff66bf14df1c Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Fri, 18 Oct 2024 13:50:48 +0200 Subject: [PATCH 28/79] Added mouse side button support --- src/sdl_window.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 7cbc5864618..1c887ced760 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -170,6 +170,8 @@ const std::map string_to_keyboard_key_map = { {"leftbutton", SDL_BUTTON_LEFT}, {"rightbutton", SDL_BUTTON_RIGHT}, {"middlebutton", SDL_BUTTON_MIDDLE}, + {"sidebuttonback", SDL_BUTTON_X1}, + {"sidebuttonforward", SDL_BUTTON_X2}, {"mousewheelup", SDL_EVENT_MOUSE_WHEEL_UP}, {"mousewheeldown", SDL_EVENT_MOUSE_WHEEL_DOWN}, {"mousewheelleft", SDL_EVENT_MOUSE_WHEEL_LEFT}, From e0b288ac68388675c89f7fa0ad1356a4c030aec2 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:25:44 +0200 Subject: [PATCH 29/79] Added per-game config --- src/sdl_window.cpp | 53 +++++++++++++++++++++++++++++----------------- src/sdl_window.h | 2 +- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 1c887ced760..63f292137af 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -15,6 +15,7 @@ #include #include "common/assert.h" #include "common/config.h" +#include "common/elf_info.h" #include "common/io_file.h" #include "common/path_util.h" #include "common/version.h" @@ -210,6 +211,7 @@ std::string getDefaultKeyboardConfig() { ## SPDX-License-Identifier: GPL-2.0-or-later #Default controller button mappings +#I will update this later #Taken keys: #F11 : fullscreen @@ -339,25 +341,36 @@ typename std::map::const_iterator FindKeyAllowingOnlyNoModifiers( return map.end(); // Return end if no match is found } -void WindowSDL::parseInputConfig(const std::string& filename) { - // Read configuration file. - const auto config_file = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / filename; +void WindowSDL::parseInputConfig() { + // Read configuration file of the game, and if it doesn't exist, generate it from default + // If that doesn't exist either, generate that from getDefaultConfig() and try again + // If even the folder is missing, we start with that. + const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "kbmConfig"; + const auto config_file = + config_dir / (std::string(Common::ElfInfo::Instance().GameSerial()) + ".ini"); + const auto default_config_file = config_dir / "default.ini"; + + // Ensure the config directory exists + if (!std::filesystem::exists(config_dir)) { + std::filesystem::create_directories(config_dir); + } + + // Try loading the game-specific config file if (!std::filesystem::exists(config_file)) { - // create it - std::ofstream file; - file.open(config_file, std::ios::out); - if (file.is_open()) { - file << getDefaultKeyboardConfig(); - file.close(); - std::cout << "Config file generated.\n"; - } else { - std::cerr << "Error creating file!\n"; + // If game-specific config doesn't exist, check for the default config + if (!std::filesystem::exists(default_config_file)) { + // If the default config is also missing, create it from getDefaultConfig() + const auto default_config = getDefaultKeyboardConfig(); + std::ofstream default_config_stream(default_config_file); + if (default_config_stream) { + default_config_stream << default_config; + } + } + + // If default config now exists, copy it to the game-specific config file + if (std::filesystem::exists(default_config_file)) { + std::filesystem::copy(default_config_file, config_file); } - } - std::ifstream file(config_file); - if (!file.is_open()) { - std::cerr << "Error opening file: " << filename << std::endl; - return; } // we reset these here so in case the user fucks up or doesn't include this we can fall back to @@ -369,6 +382,8 @@ void WindowSDL::parseInputConfig(const std::string& filename) { axis_map.clear(); key_to_modkey_toggle_map.clear(); int lineCount = 0; + + std::ifstream file(config_file); std::string line = ""; while (std::getline(file, line)) { lineCount++; @@ -600,7 +615,7 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_ window_info.render_surface = SDL_Metal_GetLayer(SDL_Metal_CreateView(window)); #endif // initialize kbm controls - parseInputConfig("keyboardInputConfig.ini"); + parseInputConfig(); // Start polling the mouse if (mouse_polling_id == 0) { mouse_polling_id = SDL_AddTimer(33, mousePolling, (void*)this); @@ -706,7 +721,7 @@ void WindowSDL::onKeyboardMouseEvent(const SDL_Event* event) { if (event->type == SDL_EVENT_KEY_DOWN) { // Reparse kbm inputs if (binding.key == SDLK_F8) { - parseInputConfig("keyboardInputConfig.ini"); + parseInputConfig(); } // Toggle mouse capture and movement input else if (binding.key == SDLK_F9) { diff --git a/src/sdl_window.h b/src/sdl_window.h index 4cee2369f09..757f3891ff5 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -103,7 +103,7 @@ class WindowSDL { static Uint32 keyRepeatCallback(void* param, Uint32 id, Uint32 interval); static Uint32 mousePolling(void* param, Uint32 id, Uint32 interval); - void parseInputConfig(const std::string& filename); + void parseInputConfig(); private: s32 width; From 942c1d8471e3856cfd05898daa391b97f4e282ec Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:41:19 +0200 Subject: [PATCH 30/79] relocated input parser to the new namespace --- src/sdl_window.cpp | 68 +++++++++++++++++++++++----------------------- src/sdl_window.h | 3 +- 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 63f292137af..19128a468fb 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -308,40 +308,7 @@ SDL_Keymod KeyBinding::getCustomModState() { return state; } -} // namespace KBMConfig - -namespace Frontend { -using Libraries::Pad::OrbisPadButtonDataOffset; - -using namespace KBMConfig; -using KBMConfig::AxisMapping; -using KBMConfig::KeyBinding; - -// modifiers are bitwise or-d together, so we need to check if ours is in that -template -typename std::map::const_iterator FindKeyAllowingPartialModifiers( - const std::map& map, KeyBinding binding) { - for (typename std::map::const_iterator it = map.cbegin(); it != map.cend(); - it++) { - if ((it->first.key == binding.key) && (it->first.modifier & binding.modifier) != 0) { - return it; - } - } - return map.end(); // Return end if no match is found -} -template -typename std::map::const_iterator FindKeyAllowingOnlyNoModifiers( - const std::map& map, KeyBinding binding) { - for (typename std::map::const_iterator it = map.cbegin(); it != map.cend(); - it++) { - if (it->first.key == binding.key && it->first.modifier == SDL_KMOD_NONE) { - return it; - } - } - return map.end(); // Return end if no match is found -} - -void WindowSDL::parseInputConfig() { +void parseInputConfig() { // Read configuration file of the game, and if it doesn't exist, generate it from default // If that doesn't exist either, generate that from getDefaultConfig() and try again // If even the folder is missing, we start with that. @@ -500,6 +467,39 @@ void WindowSDL::parseInputConfig() { file.close(); } +} // namespace KBMConfig + +namespace Frontend { +using Libraries::Pad::OrbisPadButtonDataOffset; + +using namespace KBMConfig; +using KBMConfig::AxisMapping; +using KBMConfig::KeyBinding; + +// modifiers are bitwise or-d together, so we need to check if ours is in that +template +typename std::map::const_iterator FindKeyAllowingPartialModifiers( + const std::map& map, KeyBinding binding) { + for (typename std::map::const_iterator it = map.cbegin(); it != map.cend(); + it++) { + if ((it->first.key == binding.key) && (it->first.modifier & binding.modifier) != 0) { + return it; + } + } + return map.end(); // Return end if no match is found +} +template +typename std::map::const_iterator FindKeyAllowingOnlyNoModifiers( + const std::map& map, KeyBinding binding) { + for (typename std::map::const_iterator it = map.cbegin(); it != map.cend(); + it++) { + if (it->first.key == binding.key && it->first.modifier == SDL_KMOD_NONE) { + return it; + } + } + return map.end(); // Return end if no match is found +} + Uint32 WindowSDL::keyRepeatCallback(void* param, Uint32 id, Uint32 interval) { auto* data = (std::pair*)param; KeyBinding binding(data->second); diff --git a/src/sdl_window.h b/src/sdl_window.h index 757f3891ff5..6062569ed9f 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -19,6 +19,7 @@ class GameController; namespace KBMConfig { std::string getDefaultKeyboardConfig(); +void parseInputConfig(); class KeyBinding { public: @@ -103,8 +104,6 @@ class WindowSDL { static Uint32 keyRepeatCallback(void* param, Uint32 id, Uint32 interval); static Uint32 mousePolling(void* param, Uint32 id, Uint32 interval); - void parseInputConfig(); - private: s32 width; s32 height; From 52ad7e0a96a1291531adecd2b2a128d7891d7e95 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Fri, 18 Oct 2024 18:04:43 +0200 Subject: [PATCH 31/79] changed parser parameters to make it possible to use it from the gui --- src/sdl_window.cpp | 24 +++++++++++++++--------- src/sdl_window.h | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 19128a468fb..2e89b036a2c 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -204,6 +204,7 @@ std::map button_map = {}; std::map axis_map = {}; std::map> key_to_modkey_toggle_map = {}; + // i wrapped it in a function so I can collapse it std::string getDefaultKeyboardConfig() { std::string default_config = @@ -272,6 +273,8 @@ axis_left_y_plus = s; return default_config; } + + // Flags and values for varying purposes int mouse_joystick_binding = 0; float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.125; @@ -308,13 +311,12 @@ SDL_Keymod KeyBinding::getCustomModState() { return state; } -void parseInputConfig() { +void parseInputConfig(const std::string game_id = "") { // Read configuration file of the game, and if it doesn't exist, generate it from default // If that doesn't exist either, generate that from getDefaultConfig() and try again // If even the folder is missing, we start with that. const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "kbmConfig"; - const auto config_file = - config_dir / (std::string(Common::ElfInfo::Instance().GameSerial()) + ".ini"); + const auto config_file = config_dir / (game_id + ".ini"); const auto default_config_file = config_dir / "default.ini"; // Ensure the config directory exists @@ -327,7 +329,7 @@ void parseInputConfig() { // If game-specific config doesn't exist, check for the default config if (!std::filesystem::exists(default_config_file)) { // If the default config is also missing, create it from getDefaultConfig() - const auto default_config = getDefaultKeyboardConfig(); + const auto default_config = getDefaultKeyboardConfig(); std::ofstream default_config_stream(default_config_file); if (default_config_stream) { default_config_stream << default_config; @@ -335,10 +337,14 @@ void parseInputConfig() { } // If default config now exists, copy it to the game-specific config file - if (std::filesystem::exists(default_config_file)) { + if (std::filesystem::exists(default_config_file) && !game_id.empty()) { std::filesystem::copy(default_config_file, config_file); } } + // if we just called the function to generate the directory and the default .ini + if(game_id.empty()) { + return; + } // we reset these here so in case the user fucks up or doesn't include this we can fall back to // default @@ -467,14 +473,14 @@ void parseInputConfig() { file.close(); } -} // namespace KBMConfig +} namespace Frontend { using Libraries::Pad::OrbisPadButtonDataOffset; using namespace KBMConfig; -using KBMConfig::AxisMapping; using KBMConfig::KeyBinding; +using KBMConfig::AxisMapping; // modifiers are bitwise or-d together, so we need to check if ours is in that template @@ -615,7 +621,7 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_ window_info.render_surface = SDL_Metal_GetLayer(SDL_Metal_CreateView(window)); #endif // initialize kbm controls - parseInputConfig(); + parseInputConfig(std::string(Common::ElfInfo::Instance().GameSerial())); // Start polling the mouse if (mouse_polling_id == 0) { mouse_polling_id = SDL_AddTimer(33, mousePolling, (void*)this); @@ -721,7 +727,7 @@ void WindowSDL::onKeyboardMouseEvent(const SDL_Event* event) { if (event->type == SDL_EVENT_KEY_DOWN) { // Reparse kbm inputs if (binding.key == SDLK_F8) { - parseInputConfig(); + parseInputConfig(std::string(Common::ElfInfo::Instance().GameSerial())); } // Toggle mouse capture and movement input else if (binding.key == SDLK_F9) { diff --git a/src/sdl_window.h b/src/sdl_window.h index 6062569ed9f..f85f66ceea5 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -19,7 +19,7 @@ class GameController; namespace KBMConfig { std::string getDefaultKeyboardConfig(); -void parseInputConfig(); +void parseInputConfig(const std::string game_id); class KeyBinding { public: From 050ba2e3b0ae0f6eec155357e27966ab6be01214 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Fri, 18 Oct 2024 21:23:07 +0200 Subject: [PATCH 32/79] added home, end, pgup and pgdown --- src/sdl_window.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 2e89b036a2c..42cad4c5742 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -168,6 +168,10 @@ const std::map string_to_keyboard_key_map = { {"rmeta", SDLK_RGUI}, {"lwin", SDLK_LGUI}, {"rwin", SDLK_RGUI}, + {"home", SDLK_HOME}, + {"end", SDLK_END}, + {"pgup", SDLK_PAGEUP}, + {"pgdown", SDLK_PAGEDOWN}, {"leftbutton", SDL_BUTTON_LEFT}, {"rightbutton", SDL_BUTTON_RIGHT}, {"middlebutton", SDL_BUTTON_MIDDLE}, @@ -204,7 +208,6 @@ std::map button_map = {}; std::map axis_map = {}; std::map> key_to_modkey_toggle_map = {}; - // i wrapped it in a function so I can collapse it std::string getDefaultKeyboardConfig() { std::string default_config = @@ -273,8 +276,6 @@ axis_left_y_plus = s; return default_config; } - - // Flags and values for varying purposes int mouse_joystick_binding = 0; float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.125; @@ -329,7 +330,7 @@ void parseInputConfig(const std::string game_id = "") { // If game-specific config doesn't exist, check for the default config if (!std::filesystem::exists(default_config_file)) { // If the default config is also missing, create it from getDefaultConfig() - const auto default_config = getDefaultKeyboardConfig(); + const auto default_config = getDefaultKeyboardConfig(); std::ofstream default_config_stream(default_config_file); if (default_config_stream) { default_config_stream << default_config; @@ -342,7 +343,7 @@ void parseInputConfig(const std::string game_id = "") { } } // if we just called the function to generate the directory and the default .ini - if(game_id.empty()) { + if (game_id.empty()) { return; } @@ -473,14 +474,14 @@ void parseInputConfig(const std::string game_id = "") { file.close(); } -} +} // namespace KBMConfig namespace Frontend { using Libraries::Pad::OrbisPadButtonDataOffset; using namespace KBMConfig; -using KBMConfig::KeyBinding; using KBMConfig::AxisMapping; +using KBMConfig::KeyBinding; // modifiers are bitwise or-d together, so we need to check if ours is in that template From f7b8f5e73c58d0fcbc730880681bb1afe1e1e086 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sun, 20 Oct 2024 10:47:20 +0200 Subject: [PATCH 33/79] Resolved merge conflict and refactored code --- src/sdl_window.cpp | 181 +++------------------------------------------ src/sdl_window.h | 169 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 177 insertions(+), 173 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index df11d69de09..55b868078e8 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -29,27 +29,18 @@ #include #endif -// +1 and +2 is taken -#define SDL_EVENT_MOUSE_WHEEL_UP SDL_EVENT_MOUSE_WHEEL + 3 -#define SDL_EVENT_MOUSE_WHEEL_DOWN SDL_EVENT_MOUSE_WHEEL + 4 -#define SDL_EVENT_MOUSE_WHEEL_LEFT SDL_EVENT_MOUSE_WHEEL + 5 -#define SDL_EVENT_MOUSE_WHEEL_RIGHT SDL_EVENT_MOUSE_WHEEL + 6 - -#define LEFTJOYSTICK_HALFMODE 0x00010000 -#define RIGHTJOYSTICK_HALFMODE 0x00020000 - Uint32 getMouseWheelEvent(const SDL_Event* event) { if (event->type != SDL_EVENT_MOUSE_WHEEL) return 0; // std::cout << "We got a wheel event! "; if (event->wheel.y > 0) { - return SDL_EVENT_MOUSE_WHEEL_UP; + return SDL_MOUSE_WHEEL_UP; } else if (event->wheel.y < 0) { - return SDL_EVENT_MOUSE_WHEEL_DOWN; + return SDL_MOUSE_WHEEL_DOWN; } else if (event->wheel.x > 0) { - return SDL_EVENT_MOUSE_WHEEL_RIGHT; + return SDL_MOUSE_WHEEL_RIGHT; } else if (event->wheel.x < 0) { - return SDL_EVENT_MOUSE_WHEEL_LEFT; + return SDL_MOUSE_WHEEL_LEFT; } return 0; } @@ -57,157 +48,6 @@ Uint32 getMouseWheelEvent(const SDL_Event* event) { namespace KBMConfig { using Libraries::Pad::OrbisPadButtonDataOffset; -// i strongly suggest you collapse these maps -const std::map string_to_cbutton_map = { - {"triangle", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE}, - {"circle", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE}, - {"cross", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS}, - {"square", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE}, - {"l1", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1}, - {"l2", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2}, - {"r1", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1}, - {"r2", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2}, - {"l3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3}, - {"r3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3}, - {"options", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS}, - {"touchpad", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD}, - {"up", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP}, - {"down", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN}, - {"left", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT}, - {"right", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT}, - {"leftjoystick_halfmode", LEFTJOYSTICK_HALFMODE}, - {"rightjoystick_halfmode", RIGHTJOYSTICK_HALFMODE}, -}; -const std::map string_to_axis_map = { - {"axis_left_x_plus", {Input::Axis::LeftX, 127}}, - {"axis_left_x_minus", {Input::Axis::LeftX, -127}}, - {"axis_left_y_plus", {Input::Axis::LeftY, 127}}, - {"axis_left_y_minus", {Input::Axis::LeftY, -127}}, - {"axis_right_x_plus", {Input::Axis::RightX, 127}}, - {"axis_right_x_minus", {Input::Axis::RightX, -127}}, - {"axis_right_y_plus", {Input::Axis::RightY, 127}}, - {"axis_right_y_minus", {Input::Axis::RightY, -127}}, -}; -const std::map string_to_keyboard_key_map = { - {"a", SDLK_A}, - {"b", SDLK_B}, - {"c", SDLK_C}, - {"d", SDLK_D}, - {"e", SDLK_E}, - {"f", SDLK_F}, - {"g", SDLK_G}, - {"h", SDLK_H}, - {"i", SDLK_I}, - {"j", SDLK_J}, - {"k", SDLK_K}, - {"l", SDLK_L}, - {"m", SDLK_M}, - {"n", SDLK_N}, - {"o", SDLK_O}, - {"p", SDLK_P}, - {"q", SDLK_Q}, - {"r", SDLK_R}, - {"s", SDLK_S}, - {"t", SDLK_T}, - {"u", SDLK_U}, - {"v", SDLK_V}, - {"w", SDLK_W}, - {"x", SDLK_X}, - {"y", SDLK_Y}, - {"z", SDLK_Z}, - {"0", SDLK_0}, - {"1", SDLK_1}, - {"2", SDLK_2}, - {"3", SDLK_3}, - {"4", SDLK_4}, - {"5", SDLK_5}, - {"6", SDLK_6}, - {"7", SDLK_7}, - {"8", SDLK_8}, - {"9", SDLK_9}, - {"kp0", SDLK_KP_0}, - {"kp1", SDLK_KP_1}, - {"kp2", SDLK_KP_2}, - {"kp3", SDLK_KP_3}, - {"kp4", SDLK_KP_4}, - {"kp5", SDLK_KP_5}, - {"kp6", SDLK_KP_6}, - {"kp7", SDLK_KP_7}, - {"kp8", SDLK_KP_8}, - {"kp9", SDLK_KP_9}, - {"comma", SDLK_COMMA}, - {"period", SDLK_PERIOD}, - {"question", SDLK_QUESTION}, - {"semicolon", SDLK_SEMICOLON}, - {"minus", SDLK_MINUS}, - {"underscore", SDLK_UNDERSCORE}, - {"lparenthesis", SDLK_LEFTPAREN}, - {"rparenthesis", SDLK_RIGHTPAREN}, - {"lbracket", SDLK_LEFTBRACKET}, - {"rbracket", SDLK_RIGHTBRACKET}, - {"lbrace", SDLK_LEFTBRACE}, - {"rbrace", SDLK_RIGHTBRACE}, - {"backslash", SDLK_BACKSLASH}, - {"dash", SDLK_SLASH}, - {"enter", SDLK_RETURN}, - {"space", SDLK_SPACE}, - {"tab", SDLK_TAB}, - {"backspace", SDLK_BACKSPACE}, - {"escape", SDLK_ESCAPE}, - {"left", SDLK_LEFT}, - {"right", SDLK_RIGHT}, - {"up", SDLK_UP}, - {"down", SDLK_DOWN}, - {"lctrl", SDLK_LCTRL}, - {"rctrl", SDLK_RCTRL}, - {"lshift", SDLK_LSHIFT}, - {"rshift", SDLK_RSHIFT}, - {"lalt", SDLK_LALT}, - {"ralt", SDLK_RALT}, - {"lmeta", SDLK_LGUI}, - {"rmeta", SDLK_RGUI}, - {"lwin", SDLK_LGUI}, - {"rwin", SDLK_RGUI}, - {"home", SDLK_HOME}, - {"end", SDLK_END}, - {"pgup", SDLK_PAGEUP}, - {"pgdown", SDLK_PAGEDOWN}, - {"leftbutton", SDL_BUTTON_LEFT}, - {"rightbutton", SDL_BUTTON_RIGHT}, - {"middlebutton", SDL_BUTTON_MIDDLE}, - {"sidebuttonback", SDL_BUTTON_X1}, - {"sidebuttonforward", SDL_BUTTON_X2}, - {"mousewheelup", SDL_EVENT_MOUSE_WHEEL_UP}, - {"mousewheeldown", SDL_EVENT_MOUSE_WHEEL_DOWN}, - {"mousewheelleft", SDL_EVENT_MOUSE_WHEEL_LEFT}, - {"mousewheelright", SDL_EVENT_MOUSE_WHEEL_RIGHT}, - {"kpperiod", SDLK_KP_PERIOD}, - {"kpcomma", SDLK_KP_COMMA}, - {"kpdivide", SDLK_KP_DIVIDE}, - {"kpmultiply", SDLK_KP_MULTIPLY}, - {"kpminus", SDLK_KP_MINUS}, - {"kpplus", SDLK_KP_PLUS}, - {"kpenter", SDLK_KP_ENTER}, - {"kpequals", SDLK_KP_EQUALS}, - {"capslock", SDLK_CAPSLOCK}, -}; -const std::map string_to_keyboard_mod_key_map = { - {"lshift", SDL_KMOD_LSHIFT}, {"rshift", SDL_KMOD_RSHIFT}, - {"lctrl", SDL_KMOD_LCTRL}, {"rctrl", SDL_KMOD_RCTRL}, - {"lalt", SDL_KMOD_LALT}, {"ralt", SDL_KMOD_RALT}, - {"shift", SDL_KMOD_SHIFT}, {"ctrl", SDL_KMOD_CTRL}, - {"alt", SDL_KMOD_ALT}, {"l_meta", SDL_KMOD_LGUI}, - {"r_meta", SDL_KMOD_RGUI}, {"meta", SDL_KMOD_GUI}, - {"lwin", SDL_KMOD_LGUI}, {"rwin", SDL_KMOD_RGUI}, - {"win", SDL_KMOD_GUI}, {"capslock", SDL_KMOD_CAPS}, - {"numlock", SDL_KMOD_NUM}, {"none", SDL_KMOD_NONE}, // if you want to be fancy -}; - -// Button map: maps key+modifier to controller button -std::map button_map = {}; -std::map axis_map = {}; -std::map> key_to_modkey_toggle_map = {}; - // i wrapped it in a function so I can collapse it std::string getDefaultKeyboardConfig() { std::string default_config = @@ -276,6 +116,11 @@ axis_left_y_plus = s; return default_config; } +// Button map: maps key+modifier to controller button +std::map button_map = {}; +std::map axis_map = {}; +std::map> key_to_modkey_toggle_map = {}; + // Flags and values for varying purposes int mouse_joystick_binding = 0; float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.125; @@ -628,10 +473,6 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_ #endif // initialize kbm controls parseInputConfig(std::string(Common::ElfInfo::Instance().GameSerial())); - // Start polling the mouse - if (mouse_polling_id == 0) { - mouse_polling_id = SDL_AddTimer(33, mousePolling, (void*)this); - } } WindowSDL::~WindowSDL() = default; @@ -689,14 +530,12 @@ void WindowSDL::waitEvent() { break; } } -<<<<<<< HEAD -======= void WindowSDL::initTimers() { SDL_AddTimer(100, &PollController, controller); + SDL_AddTimer(33, mousePolling, (void*)this); } ->>>>>>> upstreamMain void WindowSDL::onResize() { SDL_GetWindowSizeInPixels(window, &width, &height); ImGui::Core::OnResize(); diff --git a/src/sdl_window.h b/src/sdl_window.h index 624f1b3450c..53152b10f82 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -3,12 +3,23 @@ #pragma once +#include #include #include "common/types.h" +#include "core/libraries/pad/pad.h" #include "input/controller.h" #include +// +1 and +2 is taken +#define SDL_MOUSE_WHEEL_UP SDL_EVENT_MOUSE_WHEEL + 3 +#define SDL_MOUSE_WHEEL_DOWN SDL_EVENT_MOUSE_WHEEL + 4 +#define SDL_MOUSE_WHEEL_LEFT SDL_EVENT_MOUSE_WHEEL + 5 +#define SDL_MOUSE_WHEEL_RIGHT SDL_EVENT_MOUSE_WHEEL + 6 + +#define LEFTJOYSTICK_HALFMODE 0x00010000 +#define RIGHTJOYSTICK_HALFMODE 0x00020000 + struct SDL_Window; struct SDL_Gamepad; union SDL_Event; @@ -18,8 +29,6 @@ class GameController; } namespace KBMConfig { -std::string getDefaultKeyboardConfig(); -void parseInputConfig(const std::string game_id); class KeyBinding { public: @@ -36,6 +45,162 @@ struct AxisMapping { Input::Axis axis; int value; // Value to set for key press (+127 or -127 for movement) }; + +std::string getDefaultKeyboardConfig(); +void parseInputConfig(const std::string game_id); + +using Libraries::Pad::OrbisPadButtonDataOffset; +// i strongly suggest you collapse these maps +const std::map string_to_cbutton_map = { + {"triangle", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE}, + {"circle", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE}, + {"cross", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS}, + {"square", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE}, + {"l1", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1}, + {"l2", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2}, + {"r1", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1}, + {"r2", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2}, + {"l3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3}, + {"r3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3}, + {"options", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS}, + {"touchpad", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD}, + {"up", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP}, + {"down", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN}, + {"left", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT}, + {"right", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT}, + {"leftjoystick_halfmode", LEFTJOYSTICK_HALFMODE}, + {"rightjoystick_halfmode", RIGHTJOYSTICK_HALFMODE}, +}; +const std::map string_to_axis_map = { + {"axis_left_x_plus", {Input::Axis::LeftX, 127}}, + {"axis_left_x_minus", {Input::Axis::LeftX, -127}}, + {"axis_left_y_plus", {Input::Axis::LeftY, 127}}, + {"axis_left_y_minus", {Input::Axis::LeftY, -127}}, + {"axis_right_x_plus", {Input::Axis::RightX, 127}}, + {"axis_right_x_minus", {Input::Axis::RightX, -127}}, + {"axis_right_y_plus", {Input::Axis::RightY, 127}}, + {"axis_right_y_minus", {Input::Axis::RightY, -127}}, +}; +const std::map string_to_keyboard_key_map = { + {"a", SDLK_A}, + {"b", SDLK_B}, + {"c", SDLK_C}, + {"d", SDLK_D}, + {"e", SDLK_E}, + {"f", SDLK_F}, + {"g", SDLK_G}, + {"h", SDLK_H}, + {"i", SDLK_I}, + {"j", SDLK_J}, + {"k", SDLK_K}, + {"l", SDLK_L}, + {"m", SDLK_M}, + {"n", SDLK_N}, + {"o", SDLK_O}, + {"p", SDLK_P}, + {"q", SDLK_Q}, + {"r", SDLK_R}, + {"s", SDLK_S}, + {"t", SDLK_T}, + {"u", SDLK_U}, + {"v", SDLK_V}, + {"w", SDLK_W}, + {"x", SDLK_X}, + {"y", SDLK_Y}, + {"z", SDLK_Z}, + {"0", SDLK_0}, + {"1", SDLK_1}, + {"2", SDLK_2}, + {"3", SDLK_3}, + {"4", SDLK_4}, + {"5", SDLK_5}, + {"6", SDLK_6}, + {"7", SDLK_7}, + {"8", SDLK_8}, + {"9", SDLK_9}, + {"kp0", SDLK_KP_0}, + {"kp1", SDLK_KP_1}, + {"kp2", SDLK_KP_2}, + {"kp3", SDLK_KP_3}, + {"kp4", SDLK_KP_4}, + {"kp5", SDLK_KP_5}, + {"kp6", SDLK_KP_6}, + {"kp7", SDLK_KP_7}, + {"kp8", SDLK_KP_8}, + {"kp9", SDLK_KP_9}, + {"comma", SDLK_COMMA}, + {"period", SDLK_PERIOD}, + {"question", SDLK_QUESTION}, + {"semicolon", SDLK_SEMICOLON}, + {"minus", SDLK_MINUS}, + {"underscore", SDLK_UNDERSCORE}, + {"lparenthesis", SDLK_LEFTPAREN}, + {"rparenthesis", SDLK_RIGHTPAREN}, + {"lbracket", SDLK_LEFTBRACKET}, + {"rbracket", SDLK_RIGHTBRACKET}, + {"lbrace", SDLK_LEFTBRACE}, + {"rbrace", SDLK_RIGHTBRACE}, + {"backslash", SDLK_BACKSLASH}, + {"dash", SDLK_SLASH}, + {"enter", SDLK_RETURN}, + {"space", SDLK_SPACE}, + {"tab", SDLK_TAB}, + {"backspace", SDLK_BACKSPACE}, + {"escape", SDLK_ESCAPE}, + {"left", SDLK_LEFT}, + {"right", SDLK_RIGHT}, + {"up", SDLK_UP}, + {"down", SDLK_DOWN}, + {"lctrl", SDLK_LCTRL}, + {"rctrl", SDLK_RCTRL}, + {"lshift", SDLK_LSHIFT}, + {"rshift", SDLK_RSHIFT}, + {"lalt", SDLK_LALT}, + {"ralt", SDLK_RALT}, + {"lmeta", SDLK_LGUI}, + {"rmeta", SDLK_RGUI}, + {"lwin", SDLK_LGUI}, + {"rwin", SDLK_RGUI}, + {"home", SDLK_HOME}, + {"end", SDLK_END}, + {"pgup", SDLK_PAGEUP}, + {"pgdown", SDLK_PAGEDOWN}, + {"leftbutton", SDL_BUTTON_LEFT}, + {"rightbutton", SDL_BUTTON_RIGHT}, + {"middlebutton", SDL_BUTTON_MIDDLE}, + {"sidebuttonback", SDL_BUTTON_X1}, + {"sidebuttonforward", SDL_BUTTON_X2}, + {"mousewheelup", SDL_MOUSE_WHEEL_UP}, + {"mousewheeldown", SDL_MOUSE_WHEEL_DOWN}, + {"mousewheelleft", SDL_MOUSE_WHEEL_LEFT}, + {"mousewheelright", SDL_MOUSE_WHEEL_RIGHT}, + {"kpperiod", SDLK_KP_PERIOD}, + {"kpcomma", SDLK_KP_COMMA}, + {"kpdivide", SDLK_KP_DIVIDE}, + {"kpmultiply", SDLK_KP_MULTIPLY}, + {"kpminus", SDLK_KP_MINUS}, + {"kpplus", SDLK_KP_PLUS}, + {"kpenter", SDLK_KP_ENTER}, + {"kpequals", SDLK_KP_EQUALS}, + {"capslock", SDLK_CAPSLOCK}, +}; +const std::map string_to_keyboard_mod_key_map = { + {"lshift", SDL_KMOD_LSHIFT}, {"rshift", SDL_KMOD_RSHIFT}, + {"lctrl", SDL_KMOD_LCTRL}, {"rctrl", SDL_KMOD_RCTRL}, + {"lalt", SDL_KMOD_LALT}, {"ralt", SDL_KMOD_RALT}, + {"shift", SDL_KMOD_SHIFT}, {"ctrl", SDL_KMOD_CTRL}, + {"alt", SDL_KMOD_ALT}, {"l_meta", SDL_KMOD_LGUI}, + {"r_meta", SDL_KMOD_RGUI}, {"meta", SDL_KMOD_GUI}, + {"lwin", SDL_KMOD_LGUI}, {"rwin", SDL_KMOD_RGUI}, + {"win", SDL_KMOD_GUI}, {"capslock", SDL_KMOD_CAPS}, + {"numlock", SDL_KMOD_NUM}, {"none", SDL_KMOD_NONE}, // if you want to be fancy +}; + +// Button map: maps key+modifier to controller button +extern std::map button_map; +extern std::map axis_map; +extern std::map> key_to_modkey_toggle_map; + } // namespace KBMConfig namespace Frontend { From 7ab50857aea8043d8b49a124e2382b988f7b248b Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sun, 20 Oct 2024 11:13:02 +0200 Subject: [PATCH 34/79] Updated default keybindings --- src/sdl_window.cpp | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 55b868078e8..16027c563da 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -54,23 +54,26 @@ std::string getDefaultKeyboardConfig() { R"(## SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project ## SPDX-License-Identifier: GPL-2.0-or-later -#Default controller button mappings -#I will update this later - -#Taken keys: +#This is the default keybinding config +#To change per-game configs, modify the CUSAXXXXX.ini files +#To change the default config that applies to new games without already existing configs, modify default.ini +#If you don't like certain mappings, delete, change or comment them out. +#You can add any amount of KBM keybinds to a single controller input, +#but you can use each KBM keybind for one controller input. + +#Keybinds used by the emulator (these are unchangeable): #F11 : fullscreen #F10 : FPS counter -#F9 : toggle mouse capture +#F9 : toggle mouse-to-joystick input +# (it overwrites everything else to that joystick, so this is required) #F8 : reparse keyboard input(this) -#F7 : toggle mouse-to-joystick input -# (it overwrites everything else to that joystick, so this is required) #This is a mapping for Bloodborne, inspired by other Souls titles on PC. -#This is a quick and dirty implementation of binding the mouse to a user-specified joystick +#Specifies which joystick the mouse movement controls. mouse_to_joystick = right; -#Use another item(healing), change status in inventory +#Use healing item, change status in inventory triangle = f; #Dodge, back in inventory circle = space; @@ -81,12 +84,18 @@ square = r; #Emergency extra bullets up = w, lalt; +up = mousewheelup; #Change quick item down = s, lalt; +down = mousewheeldown; #Change weapon in left hand left = a, lalt; +left = mousewheelleft; #Change weapon in right hand right = d, lalt; +right = mousewheelright; +#Change into 'inventory mode', so you don't have to hold lalt every time you go into menus +modkey_toggle = i, lalt; #Menu options = escape; @@ -105,6 +114,7 @@ r2 = leftbutton, lshift; l3 = x; #Center cam, lock on r3 = q; +r3 = middlebutton; #Axis mappings #Move @@ -112,6 +122,8 @@ axis_left_x_minus = a; axis_left_x_plus = d; axis_left_y_minus = w; axis_left_y_plus = s; +#Change to 'walk mode' by holding the following key: +leftjoystick_halfmode = lctrl; )"; return default_config; } From cd4d3c59cfdc978776fbd888eba09667d962d200 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Thu, 31 Oct 2024 21:34:31 +0100 Subject: [PATCH 35/79] Changed input handling to be single-threaded --- src/sdl_window.cpp | 49 ++++++++++++++++++++++++++++++++++++++++------ src/sdl_window.h | 7 +++++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 16027c563da..084ea74ce13 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -139,6 +139,9 @@ float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.125; Uint32 mouse_polling_id = 0; bool mouse_enabled = false, leftjoystick_halfmode = false, rightjoystick_halfmode = false; +// A vector to store delayed actions by event ID +std::vector delayedActions; + KeyBinding::KeyBinding(const SDL_Event* event) { modifier = getCustomModState(); key = 0; @@ -384,6 +387,36 @@ Uint32 WindowSDL::keyRepeatCallback(void* param, Uint32 id, Uint32 interval) { return 0; // Return 0 to stop the timer after firing once } +void WindowSDL::handleDelayedActions() { + // Uncomment at your own terminal's risk + // std::cout << "I fear the amount of spam this line will generate\n"; + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + Uint32 currentTime = SDL_GetTicks(); + for (auto it = delayedActions.begin(); it != delayedActions.end();) { + if (currentTime >= it->triggerTime) { + if (it->event.type == SDL_EVENT_MOUSE_WHEEL) { + SDL_Event* mouseEvent = &(it->event); + KeyBinding binding(mouseEvent); + + auto button_it = button_map.find(binding); + auto axis_it = axis_map.find(binding); + + if (button_it != button_map.end()) { + updateButton(binding, button_it->second, false); + } else if (axis_it != axis_map.end()) { + controller->Axis(0, axis_it->second.axis, Input::GetAxis(-0x80, 0x80, 0)); + } + } else { + KeyBinding b(&(it->event)); + updateModKeyedInputsManually(b); + } + it = delayedActions.erase(it); // Erase returns the next iterator + } else { + ++it; + } + } +} + Uint32 WindowSDL::mousePolling(void* param, Uint32 id, Uint32 interval) { auto* data = (WindowSDL*)param; data->updateMouse(); @@ -491,18 +524,22 @@ WindowSDL::~WindowSDL() = default; void WindowSDL::waitEvent() { // Called on main thread + + handleDelayedActions(); + SDL_Event event{}; - if (!SDL_WaitEvent(&event)) { + // waitEvent locks the execution here until the next event, + // but we want to poll handleDelayedActions too + if (!SDL_PollEvent(&event)) { return; } if (ImGui::Core::ProcessEvent(&event)) { return; } - SDL_Event* event_copy = new SDL_Event(); - *event_copy = event; - std::pair* payload_to_timer = - new std::pair(this, event_copy); + + // Set execution time to 33 ms later than 'now' + DelayedAction d = {SDL_GetTicks() + 33, event}; switch (event.type) { case SDL_EVENT_WINDOW_RESIZED: @@ -522,7 +559,7 @@ void WindowSDL::waitEvent() { // as seen in pr #633 case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: - SDL_AddTimer(33, keyRepeatCallback, (void*)payload_to_timer); + delayedActions.push_back(d); onKeyboardMouseEvent(&event); break; case SDL_EVENT_GAMEPAD_BUTTON_DOWN: diff --git a/src/sdl_window.h b/src/sdl_window.h index 53152b10f82..60c748c3599 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -46,6 +46,12 @@ struct AxisMapping { int value; // Value to set for key press (+127 or -127 for movement) }; +// Define a struct to hold any necessary timing information for delayed actions +struct DelayedAction { + Uint64 triggerTime; // When the action should be triggered + SDL_Event event; // Event data +}; + std::string getDefaultKeyboardConfig(); void parseInputConfig(const std::string game_id); @@ -270,6 +276,7 @@ class WindowSDL { void updateButton(KBMConfig::KeyBinding& binding, u32 button, bool isPressed); static Uint32 keyRepeatCallback(void* param, Uint32 id, Uint32 interval); static Uint32 mousePolling(void* param, Uint32 id, Uint32 interval); + void handleDelayedActions(); private: s32 width; From 9958033d052db8145be8aa1d9dc197d863599db4 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Thu, 31 Oct 2024 21:40:15 +0100 Subject: [PATCH 36/79] General code cleanup --- src/sdl_window.cpp | 29 ++--------------------------- src/sdl_window.h | 1 - 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 084ea74ce13..1c682e82ae5 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -32,7 +32,6 @@ Uint32 getMouseWheelEvent(const SDL_Event* event) { if (event->type != SDL_EVENT_MOUSE_WHEEL) return 0; - // std::cout << "We got a wheel event! "; if (event->wheel.y > 0) { return SDL_MOUSE_WHEEL_UP; } else if (event->wheel.y < 0) { @@ -145,7 +144,6 @@ std::vector delayedActions; KeyBinding::KeyBinding(const SDL_Event* event) { modifier = getCustomModState(); key = 0; - // std::cout << "Someone called the new binding ctor!\n"; if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) { key = event->key.key; } else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || @@ -367,29 +365,9 @@ typename std::map::const_iterator FindKeyAllowingOnlyNoModifiers( return map.end(); // Return end if no match is found } -Uint32 WindowSDL::keyRepeatCallback(void* param, Uint32 id, Uint32 interval) { - auto* data = (std::pair*)param; - KeyBinding binding(data->second); - if (data->second->type == SDL_EVENT_MOUSE_WHEEL) { - // send an off signal a frame later - auto button_it = button_map.find(binding); - auto axis_it = axis_map.find(binding); - if (button_it != button_map.end()) { - data->first->updateButton(binding, button_it->second, false); - } else if (axis_it != axis_map.end()) { - data->first->controller->Axis(0, axis_it->second.axis, Input::GetAxis(-0x80, 0x80, 0)); - } - return 0; - } - data->first->updateModKeyedInputsManually(binding); - delete data->second; - delete data; - return 0; // Return 0 to stop the timer after firing once -} - void WindowSDL::handleDelayedActions() { // Uncomment at your own terminal's risk - // std::cout << "I fear the amount of spam this line will generate\n"; + // std::cout << "I fear the amount of spam this line will generate\n"; std::this_thread::sleep_for(std::chrono::milliseconds(1)); Uint32 currentTime = SDL_GetTicks(); for (auto it = delayedActions.begin(); it != delayedActions.end();) { @@ -420,7 +398,7 @@ void WindowSDL::handleDelayedActions() { Uint32 WindowSDL::mousePolling(void* param, Uint32 id, Uint32 interval) { auto* data = (WindowSDL*)param; data->updateMouse(); - return 33; // Return 0 to stop the timer after firing once + return 33; } void WindowSDL::updateMouse() { @@ -447,7 +425,6 @@ void WindowSDL::updateMouse() { float output_speed = SDL_clamp((sqrt(d_x * d_x + d_y * d_y) + mouse_speed_offset * 128) * mouse_speed, mouse_deadzone_offset * 128, 128.0); - // std::cout << "speed: " << mouse_speed << "\n"; float angle = atan2(d_y, d_x); float a_x = cos(angle) * output_speed, a_y = sin(angle) * output_speed; @@ -599,8 +576,6 @@ void WindowSDL::updateButton(KeyBinding& binding, u32 button, bool is_pressed) { case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2: axis = (button == OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2) ? Input::Axis::TriggerRight : Input::Axis::TriggerLeft; - // int axis_value = is_pressed ? 255 : 0; - // int ax = Input::GetAxis(0, 0x80, is_pressed ? 255 : 0); controller->Axis(0, axis, Input::GetAxis(0, 0x80, is_pressed ? 255 : 0)); break; case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD: diff --git a/src/sdl_window.h b/src/sdl_window.h index 60c748c3599..4f4e9b8ebaa 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -274,7 +274,6 @@ class WindowSDL { void updateModKeyedInputsManually(KBMConfig::KeyBinding& binding); void updateButton(KBMConfig::KeyBinding& binding, u32 button, bool isPressed); - static Uint32 keyRepeatCallback(void* param, Uint32 id, Uint32 interval); static Uint32 mousePolling(void* param, Uint32 id, Uint32 interval); void handleDelayedActions(); From 7a95c27b2c3eba230c71d3cad2a4877a508d5b9f Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Tue, 12 Nov 2024 19:44:23 +0100 Subject: [PATCH 37/79] Start working on new backend --- src/input/input_handler.cpp | 7 +++++++ src/input/input_handler.h | 9 +++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/input/input_handler.cpp create mode 100644 src/input/input_handler.h diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp new file mode 100644 index 00000000000..c769752ea1d --- /dev/null +++ b/src/input/input_handler.cpp @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +namespace InputHandler { + + +} \ No newline at end of file diff --git a/src/input/input_handler.h b/src/input/input_handler.h new file mode 100644 index 00000000000..a97922004e4 --- /dev/null +++ b/src/input/input_handler.h @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace InputHandler { + + +} \ No newline at end of file From 1884b39eb8683156a4c38440d51258c973fafe3a Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Wed, 13 Nov 2024 09:39:19 +0100 Subject: [PATCH 38/79] Mouse polling, CMakeLists, and basic framework --- CMakeLists.txt | 2 + src/input/input_handler.cpp | 378 +++++++++++++++++++++++++++++++++++- src/input/input_handler.h | 279 +++++++++++++++++++++++++- src/sdl_window.cpp | 20 +- src/sdl_window.h | 2 +- 5 files changed, 676 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0e877a529e..f5d50c6b12b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -724,6 +724,8 @@ set(IMGUI src/imgui/imgui_config.h set(INPUT src/input/controller.cpp src/input/controller.h + src/input/input_handler.cpp + src/input/input_handler.h ) set(EMULATOR src/emulator.cpp diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index c769752ea1d..62be8f590a0 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -1,7 +1,383 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -namespace InputHandler { +#include "input_handler.h" +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "common/config.h" +#include "common/io_file.h" +#include "common/path_util.h" +#include "common/version.h" +#include "common/elf_info.h" +#include "input/controller.h" + +namespace Input { +/* +Project structure: +n to m connection between inputs and outputs +Keyup and keydown events update a dynamic list* of u32 'flags' (what is currently in the list is 'pressed') +On every event, after flag updates, we check for every input binding -> controller output pair if all their flags are 'on' +If not, disable; if so, enable them. +For axes, we gather their data into a struct cumulatively from all inputs, + then after we checked all of those, we update them all at once. +Wheel inputs generate a timer that doesn't turn off their outputs automatically, but push a userevent to do so. + +What structs are needed? +InputBinding(key1, key2, key3) +ControllerOutput(button, axis) - we only need a const array of these, and one of the attr-s is always 0 +BindingConnection(inputBinding (member), controllerOutput (ref to the array element)) +*/ + +// Flags and values for varying purposes +// todo: can we change these? +int mouse_joystick_binding = 0; +float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.1250; +Uint32 mouse_polling_id = 0; +bool mouse_enabled = false, leftjoystick_halfmode = false, rightjoystick_halfmode = false; + +std::string_view getDefaultKeyboardConfig() { + static std::string_view default_config = + R"(## SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +## SPDX-License-Identifier: GPL-2.0-or-later + +#This is the default keybinding config +#To change per-game configs, modify the CUSAXXXXX.ini files +#To change the default config that applies to new games without already existing configs, modify default.ini +#If you don't like certain mappings, delete, change or comment them out. +#You can add any amount of KBM keybinds to a single controller input, +#but you can use each KBM keybind for one controller input. + +#Keybinds used by the emulator (these are unchangeable): +#F11 : fullscreen +#F10 : FPS counter +#F9 : toggle mouse-to-joystick input +# (it overwrites everything else to that joystick, so this is required) +#F8 : reparse keyboard input(this) + +#This is a mapping for Bloodborne, inspired by other Souls titles on PC. + +#Specifies which joystick the mouse movement controls. +mouse_to_joystick = right; + +#Use healing item, change status in inventory +triangle = f; +#Dodge, back in inventory +circle = space; +#Interact, select item in inventory +cross = e; +#Use quick item, remove item in inventory +square = r; + +#Emergency extra bullets +up = w, lalt; +up = mousewheelup; +#Change quick item +down = s, lalt; +down = mousewheeldown; +#Change weapon in left hand +left = a, lalt; +left = mousewheelleft; +#Change weapon in right hand +right = d, lalt; +right = mousewheelright; +#Change into 'inventory mode', so you don't have to hold lalt every time you go into menus +modkey_toggle = i, lalt; + +#Menu +options = escape; +#Gestures +touchpad = g; + +#Transform +l1 = rightbutton, lshift; +#Shoot +r1 = leftbutton; +#Light attack +l2 = rightbutton; +#Heavy attack +r2 = leftbutton, lshift; +#Does nothing +l3 = x; +#Center cam, lock on +r3 = q; +r3 = middlebutton; + +#Axis mappings +#Move +axis_left_x_minus = a; +axis_left_x_plus = d; +axis_left_y_minus = w; +axis_left_y_plus = s; +#Change to 'walk mode' by holding the following key: +leftjoystick_halfmode = lctrl; +)"; + return default_config; +} + +void parseInputConfig(const std::string game_id = "") { + // Read configuration file of the game, and if it doesn't exist, generate it from default + // If that doesn't exist either, generate that from getDefaultConfig() and try again + // If even the folder is missing, we start with that. + + // maybe extract this? + const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "kbmConfig"; + const auto config_file = config_dir / (game_id + ".ini"); + const auto default_config_file = config_dir / "default.ini"; + + // Ensure the config directory exists + if (!std::filesystem::exists(config_dir)) { + std::filesystem::create_directories(config_dir); + } + + // Try loading the game-specific config file + if (!std::filesystem::exists(config_file)) { + // If game-specific config doesn't exist, check for the default config + if (!std::filesystem::exists(default_config_file)) { + // If the default config is also missing, create it from getDefaultConfig() + const auto default_config = getDefaultKeyboardConfig(); + std::ofstream default_config_stream(default_config_file); + if (default_config_stream) { + default_config_stream << default_config; + } + } + + // If default config now exists, copy it to the game-specific config file + if (std::filesystem::exists(default_config_file) && !game_id.empty()) { + std::filesystem::copy(default_config_file, config_file); + } + } + // if we just called the function to generate the directory and the default .ini + if (game_id.empty()) { + return; + } + + // we reset these here so in case the user fucks up or doesn't include this we can fall back to + // default + mouse_deadzone_offset = 0.5; + mouse_speed = 1; + mouse_speed_offset = 0.125; + //old_button_map.clear(); + //old_axis_map.clear(); + //old_key_to_modkey_toggle_map.clear(); + int lineCount = 0; + + std::ifstream file(config_file); + std::string line = ""; + while (std::getline(file, line)) { + lineCount++; + // strip the ; and whitespace + line.erase(std::remove(line.begin(), line.end(), ' '), line.end()); + if (line[line.length() - 1] == ';') { + line = line.substr(0, line.length() - 1); + } + // Ignore comment lines + if (line.empty() || line[0] == '#') { + continue; + } + // Split the line by '=' + std::size_t equal_pos = line.find('='); + if (equal_pos == std::string::npos) { + std::cerr << "Invalid line format at line: " << lineCount << " data: " << line + << std::endl; + continue; + } + + std::string before_equals = line.substr(0, equal_pos); + std::string after_equals = line.substr(equal_pos + 1); + std::size_t comma_pos = after_equals.find(','); + + // new data type construcor here + // todo + + // special check for mouse to joystick input + if (before_equals == "mouse_to_joystick") { + if (after_equals == "left") { + mouse_joystick_binding = 1; + } else if (after_equals == "right") { + mouse_joystick_binding = 2; + } else { + mouse_joystick_binding = 0; // default to 'none' or invalid + } + continue; + } + // mod key toggle + if (before_equals == "modkey_toggle") { + if (comma_pos != std::string::npos) { + // handle key-to-key toggling (separate list?) + // todo + } + std::cerr << "Invalid line format at line: " << lineCount << " data: " << line + << std::endl; + continue; + } + // todo + /* og parsing + // first we parse the binding, and if its wrong, we skip to the next line + if (comma_pos != std::string::npos) { + // Handle key + modifier + std::string key = after_equals.substr(0, comma_pos); + std::string mod = after_equals.substr(comma_pos + 1); + + auto key_it = string_to_keyboard_key_map.find(key); + auto mod_it = string_to_keyboard_mod_key_map.find(mod); + + if (key_it != string_to_keyboard_key_map.end() && + mod_it != string_to_keyboard_mod_key_map.end()) { + binding.key = key_it->second; + binding.modifier = mod_it->second; + } else if (before_equals == "mouse_movement_params") { + // handle mouse movement params + float p1 = 0.5, p2 = 1, p3 = 0.125; + std::size_t second_comma_pos = after_equals.find(','); + try { + p1 = std::stof(key); + p2 = std::stof(mod.substr(0, second_comma_pos)); + p3 = std::stof(mod.substr(second_comma_pos + 1)); + mouse_deadzone_offset = p1; + mouse_speed = p2; + mouse_speed_offset = p3; + } catch (...) { + // fallback to default values + mouse_deadzone_offset = 0.5; + mouse_speed = 1; + mouse_speed_offset = 0.125; + std::cerr << "Parsing error while parsing kbm inputs at line " << lineCount + << " line data: " << line << "\n"; + } + continue; + } else { + std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount + << " line data: " << line << "\n"; + continue; // skip + } + } else { + // Just a key without modifier + auto key_it = string_to_keyboard_key_map.find(after_equals); + if (key_it != string_to_keyboard_key_map.end()) { + binding.key = key_it->second; + } else { + std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount + << " line data: " << line << "\n"; + continue; // skip + } + } + + // Check for axis mapping (example: axis_left_x_plus) + auto axis_it = string_to_axis_map.find(before_equals); + auto button_it = string_to_cbutton_map.find(before_equals); + if (axis_it != string_to_axis_map.end()) { + old_axis_map[binding] = axis_it->second; + } else if (button_it != string_to_cbutton_map.end()) { + old_button_map[binding] = button_it->second; + } else { + std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount + << " line data: " << line << "\n"; + } + */ + } + file.close(); +} + +// todo: add an init for this +GameController* ControllerOutput::controller = nullptr; +void ControllerOutput::setControllerOutputController(GameController* c) { + ControllerOutput::controller = c; +} + +void ControllerOutput::update(bool pressed, int axis_direction) { + float touchpad_x = 0; + Input::Axis axis = Input::Axis::AxisMax; + if(button != 0){ + switch (button) { + case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2: + case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2: + axis = (button == OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2) ? Input::Axis::TriggerRight + : Input::Axis::TriggerLeft; + controller->Axis(0, axis, Input::GetAxis(0, 0x80, pressed ? 255 : 0)); + break; + case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD: + touchpad_x = Config::getBackButtonBehavior() == "left" ? 0.25f + : Config::getBackButtonBehavior() == "right" ? 0.75f + : 0.5f; + controller->SetTouchpadState(0, true, touchpad_x, 0.5f); + controller->CheckButton(0, button, pressed); + break; + default: // is a normal key + controller->CheckButton(0, button, pressed); + break; + } + } else if (axis != Axis::AxisMax) { + float multiplier = 1.0; + switch (axis) { + case Input::Axis::LeftX: + case Input::Axis::LeftY: + multiplier = leftjoystick_halfmode ? 0.5 : 1.0; + break; + case Input::Axis::RightX: + case Input::Axis::RightY: + multiplier = rightjoystick_halfmode ? 0.5 : 1.0; + break; + default: + break; + } + int output_value = (pressed ? axis_value : 0) * multiplier; + int ax = Input::GetAxis(-0x80, 0x80, output_value); + controller->Axis(0, axis, ax); + } else { + LOG_ERROR(Input, "Controller output with no values detected!"); + } +} + +void updateMouse(GameController* controller) { + if (!mouse_enabled) + return; + Axis axis_x, axis_y; + switch (mouse_joystick_binding) { + case 1: + axis_x = Axis::LeftX; + axis_y = Axis::LeftY; + break; + case 2: + axis_x = Axis::RightX; + axis_y = Axis::RightY; + break; + case 0: + default: + return; // no update needed + } + + float d_x = 0, d_y = 0; + SDL_GetRelativeMouseState(&d_x, &d_y); + + float output_speed = + SDL_clamp((sqrt(d_x * d_x + d_y * d_y) + mouse_speed_offset * 128) * mouse_speed, + mouse_deadzone_offset * 128, 128.0); + + float angle = atan2(d_y, d_x); + float a_x = cos(angle) * output_speed, a_y = sin(angle) * output_speed; + + if (d_x != 0 && d_y != 0) { + controller->Axis(0, axis_x, Input::GetAxis(-0x80, 0x80, a_x)); + controller->Axis(0, axis_y, Input::GetAxis(-0x80, 0x80, a_y)); + } else { + controller->Axis(0, axis_x, Input::GetAxis(-0x80, 0x80, 0)); + controller->Axis(0, axis_y, Input::GetAxis(-0x80, 0x80, 0)); + } +} + +Uint32 mousePolling(void* param, Uint32 id, Uint32 interval) { + auto* data = (GameController*)param; + updateMouse(data); + return interval; +} } \ No newline at end of file diff --git a/src/input/input_handler.h b/src/input/input_handler.h index a97922004e4..075a3996e01 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -3,7 +3,284 @@ #pragma once -namespace InputHandler { +#include "array" +#include "map" +#include "string" +#include "common/types.h" +#include "core/libraries/pad/pad.h" +#include "input/controller.h" + +#include +#include + +// +1 and +2 is taken +#define SDL_MOUSE_WHEEL_UP SDL_EVENT_MOUSE_WHEEL + 3 +#define SDL_MOUSE_WHEEL_DOWN SDL_EVENT_MOUSE_WHEEL + 4 +#define SDL_MOUSE_WHEEL_LEFT SDL_EVENT_MOUSE_WHEEL + 5 +#define SDL_MOUSE_WHEEL_RIGHT SDL_EVENT_MOUSE_WHEEL + 7 + +#define LEFTJOYSTICK_HALFMODE 0x00010000 +#define RIGHTJOYSTICK_HALFMODE 0x00020000 + +namespace Input { +using Input::Axis; +using Libraries::Pad::OrbisPadButtonDataOffset; + +struct AxisMapping { + Axis axis; + int value; // Value to set for key press (+127 or -127 for movement) +}; + +// i strongly suggest you collapse these maps +const std::map string_to_cbutton_map = { + {"triangle", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE}, + {"circle", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE}, + {"cross", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS}, + {"square", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE}, + {"l1", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1}, + {"l2", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2}, + {"r1", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1}, + {"r2", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2}, + {"l3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3}, + {"r3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3}, + {"options", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS}, + {"touchpad", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD}, + {"up", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP}, + {"down", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN}, + {"left", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT}, + {"right", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT}, + {"leftjoystick_halfmode", LEFTJOYSTICK_HALFMODE}, + {"rightjoystick_halfmode", RIGHTJOYSTICK_HALFMODE}, +}; +const std::map string_to_axis_map = { + {"axis_left_x_plus", {Input::Axis::LeftX, 127}}, + {"axis_left_x_minus", {Input::Axis::LeftX, -127}}, + {"axis_left_y_plus", {Input::Axis::LeftY, 127}}, + {"axis_left_y_minus", {Input::Axis::LeftY, -127}}, + {"axis_right_x_plus", {Input::Axis::RightX, 127}}, + {"axis_right_x_minus", {Input::Axis::RightX, -127}}, + {"axis_right_y_plus", {Input::Axis::RightY, 127}}, + {"axis_right_y_minus", {Input::Axis::RightY, -127}}, +}; +const std::map string_to_keyboard_key_map = { + {"a", SDLK_A}, + {"b", SDLK_B}, + {"c", SDLK_C}, + {"d", SDLK_D}, + {"e", SDLK_E}, + {"f", SDLK_F}, + {"g", SDLK_G}, + {"h", SDLK_H}, + {"i", SDLK_I}, + {"j", SDLK_J}, + {"k", SDLK_K}, + {"l", SDLK_L}, + {"m", SDLK_M}, + {"n", SDLK_N}, + {"o", SDLK_O}, + {"p", SDLK_P}, + {"q", SDLK_Q}, + {"r", SDLK_R}, + {"s", SDLK_S}, + {"t", SDLK_T}, + {"u", SDLK_U}, + {"v", SDLK_V}, + {"w", SDLK_W}, + {"x", SDLK_X}, + {"y", SDLK_Y}, + {"z", SDLK_Z}, + {"0", SDLK_0}, + {"1", SDLK_1}, + {"2", SDLK_2}, + {"3", SDLK_3}, + {"4", SDLK_4}, + {"5", SDLK_5}, + {"6", SDLK_6}, + {"7", SDLK_7}, + {"8", SDLK_8}, + {"9", SDLK_9}, + {"kp0", SDLK_KP_0}, + {"kp1", SDLK_KP_1}, + {"kp2", SDLK_KP_2}, + {"kp3", SDLK_KP_3}, + {"kp4", SDLK_KP_4}, + {"kp5", SDLK_KP_5}, + {"kp6", SDLK_KP_6}, + {"kp7", SDLK_KP_7}, + {"kp8", SDLK_KP_8}, + {"kp9", SDLK_KP_9}, + {"comma", SDLK_COMMA}, + {"period", SDLK_PERIOD}, + {"question", SDLK_QUESTION}, + {"semicolon", SDLK_SEMICOLON}, + {"minus", SDLK_MINUS}, + {"underscore", SDLK_UNDERSCORE}, + {"lparenthesis", SDLK_LEFTPAREN}, + {"rparenthesis", SDLK_RIGHTPAREN}, + {"lbracket", SDLK_LEFTBRACKET}, + {"rbracket", SDLK_RIGHTBRACKET}, + {"lbrace", SDLK_LEFTBRACE}, + {"rbrace", SDLK_RIGHTBRACE}, + {"backslash", SDLK_BACKSLASH}, + {"dash", SDLK_SLASH}, + {"enter", SDLK_RETURN}, + {"space", SDLK_SPACE}, + {"tab", SDLK_TAB}, + {"backspace", SDLK_BACKSPACE}, + {"escape", SDLK_ESCAPE}, + {"left", SDLK_LEFT}, + {"right", SDLK_RIGHT}, + {"up", SDLK_UP}, + {"down", SDLK_DOWN}, + {"lctrl", SDLK_LCTRL}, + {"rctrl", SDLK_RCTRL}, + {"lshift", SDLK_LSHIFT}, + {"rshift", SDLK_RSHIFT}, + {"lalt", SDLK_LALT}, + {"ralt", SDLK_RALT}, + {"lmeta", SDLK_LGUI}, + {"rmeta", SDLK_RGUI}, + {"lwin", SDLK_LGUI}, + {"rwin", SDLK_RGUI}, + {"home", SDLK_HOME}, + {"end", SDLK_END}, + {"pgup", SDLK_PAGEUP}, + {"pgdown", SDLK_PAGEDOWN}, + {"leftbutton", SDL_BUTTON_LEFT}, + {"rightbutton", SDL_BUTTON_RIGHT}, + {"middlebutton", SDL_BUTTON_MIDDLE}, + {"sidebuttonback", SDL_BUTTON_X1}, + {"sidebuttonforward", SDL_BUTTON_X2}, + {"mousewheelup", SDL_MOUSE_WHEEL_UP}, + {"mousewheeldown", SDL_MOUSE_WHEEL_DOWN}, + {"mousewheelleft", SDL_MOUSE_WHEEL_LEFT}, + {"mousewheelright", SDL_MOUSE_WHEEL_RIGHT}, + {"kpperiod", SDLK_KP_PERIOD}, + {"kpcomma", SDLK_KP_COMMA}, + {"kpdivide", SDLK_KP_DIVIDE}, + {"kpmultiply", SDLK_KP_MULTIPLY}, + {"kpminus", SDLK_KP_MINUS}, + {"kpplus", SDLK_KP_PLUS}, + {"kpenter", SDLK_KP_ENTER}, + {"kpequals", SDLK_KP_EQUALS}, + {"capslock", SDLK_CAPSLOCK}, +}; + +// i wrapped it in a function so I can collapse it +std::string_view getDefaultKeyboardConfig(); + +void parseInputConfig(const std::string game_id); + +class InputBinding { +public: + u32 key1, key2, key3; + int axis_value; + InputBinding(int v, u32 k1 = SDLK_UNKNOWN, u32 k2 = SDLK_UNKNOWN, u32 k3 = SDLK_UNKNOWN) { + // we format the keys so comaring them will be very fast, because we will only have to compare 3 sorted elements, + // where the only possible duplicate item is 0 + + // duplicate entries get changed to one original, one null + if(k1 == k2 && k1 != SDLK_UNKNOWN) { k2 = 0; } + if(k1 == k3 && k1 != SDLK_UNKNOWN) { k3 = 0; } + if(k3 == k2 && k2 != SDLK_UNKNOWN) { k2 = 0; } + // this sorts them + if (k1 <= k2 && k1 <= k3) { + key1 = k1; + if (k2 <= k3) { key2 = k2; key3 = k3; } + else { key2 = k3; key3 = k2; } + } else if (k2 <= k1 && k2 <= k3) { + key1 = k2; + if (k1 <= k3) { key2 = k1; key3 = k3; } + else { key2 = k3; key3 = k1; } + } else { + key1 = k3; + if (k1 <= k2) { key2 = k1; key3 = k2; } + else { key2 = k2; key3 = k1; } + } + } + + inline bool operator==(const InputBinding& o) { + // 0 = SDLK_UNKNOWN aka unused slot + return (key3 == o.key3 || key3 == 0 || o.key3 == 0) && + (key2 == o.key2 || key2 == 0 || o.key2 == 0) && + (key1 == o.key1 || key1 == 0 || o.key1 == 0); + // it is already very fast, + // but reverse order makes it check the actual keys first instead of possible 0-s, + // potenially skipping the later expressions of the three-way AND + } + + static u32 getInputIDFromEvent(const SDL_Event& e) { + switch(e.type) { + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: + return e.key.key; + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: + return (u32)e.button.button; + default: + // todo: add the rest (wheel) + return 0; + } + } + +}; +class ControllerOutput { + static GameController* controller; +public: + static void setControllerOutputController(GameController* c); + + std::string name; + u32 button; + Input::Axis axis; + int axis_value; + bool active; + ControllerOutput(const std::string& n, u32 b, Axis a = Axis::AxisMax, int v = 0, bool ac = false) { + name = n; + button = b; + axis = a; + axis_value = v; + active = ac; + } + ControllerOutput(const ControllerOutput& o); + void update(bool pressed, int axis_direction = 0); +}; +class InputData { + InputBinding binding; + int axis_value; + bool flag; + InputData(InputBinding b, int v = 0) : binding(b), axis_value(v), flag(false) {} + +}; + +// todo +// don't forget to change the number too +const std::array input_state = { +// buttons and axes rolled into one +ControllerOutput("up", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP), +ControllerOutput("down", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN), +// etc. +ControllerOutput("axis_left_x_plus", 0, Axis::LeftX, 127), +ControllerOutput("axis_left_x_minus", 0, Axis::LeftX, -127), +// etc. +}; + + +extern std::map new_binding_map; +extern u32 pressed_keys[]; + +// Check if the 3 key input is currently active. +bool checkForInputDown(InputBinding i); + +// Add/remove the input that generated the event to/from the held keys container. +void updatePressedKeys(u32 button, bool is_pressed); + + +void updateMouse(GameController* controller); + +// Polls the mouse for changes, and simulates joystick movement from it. +Uint32 mousePolling(void* param, Uint32 id, Uint32 interval); + + } \ No newline at end of file diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index ad7d1b4a6b4..c81a495fe22 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -12,6 +12,7 @@ #include "core/libraries/pad/pad.h" #include "imgui/renderer/imgui_core.h" #include "input/controller.h" +#include "input/input_handler.h" #include "sdl_window.h" #include "video_core/renderdoc.h" @@ -76,6 +77,8 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_ window_info.type = WindowSystemType::Metal; window_info.render_surface = SDL_Metal_GetLayer(SDL_Metal_CreateView(window)); #endif + // input handler init-s + Input::ControllerOutput::setControllerOutputController(controller); } WindowSDL::~WindowSDL() = default; @@ -103,9 +106,10 @@ void WindowSDL::waitEvent() { is_shown = event.type == SDL_EVENT_WINDOW_EXPOSED; onResize(); break; + case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: - onKeyPress(&event); + onKeyboardMouseInput(&event); break; case SDL_EVENT_GAMEPAD_BUTTON_DOWN: case SDL_EVENT_GAMEPAD_BUTTON_UP: @@ -127,6 +131,8 @@ void WindowSDL::waitEvent() { void WindowSDL::initTimers() { SDL_AddTimer(100, &PollController, controller); + // todo: add back mouse polling here + SDL_AddTimer(33, Input::mousePolling, (void*)controller); } void WindowSDL::onResize() { @@ -134,9 +140,18 @@ void WindowSDL::onResize() { ImGui::Core::OnResize(); } -void WindowSDL::onKeyPress(const SDL_Event* event) { +void WindowSDL::onKeyboardMouseInput(const SDL_Event* event) { using Libraries::Pad::OrbisPadButtonDataOffset; + // get the event's id, if it's keyup or keydown + + // add/remove it from the list + + // update bindings and buttons + + // update axes + +/* og function #ifdef __APPLE__ // Use keys that are more friendly for keyboards without a keypad. // Once there are key binding options this won't be necessary. @@ -323,6 +338,7 @@ void WindowSDL::onKeyPress(const SDL_Event* event) { if (axis != Input::Axis::AxisMax) { controller->Axis(0, axis, ax); } +*/ } void WindowSDL::onGamepadEvent(const SDL_Event* event) { diff --git a/src/sdl_window.h b/src/sdl_window.h index ec8de354b80..ad27ba4a55a 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -72,7 +72,7 @@ class WindowSDL { private: void onResize(); - void onKeyPress(const SDL_Event* event); + void onKeyboardMouseInput(const SDL_Event* event); void onGamepadEvent(const SDL_Event* event); int sdlGamepadToOrbisButton(u8 button); From d92a83ccb5f77877e533fe08b9fb87035b87821b Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Wed, 13 Nov 2024 11:17:07 +0100 Subject: [PATCH 39/79] Output update handling, and reworked file creating, reading and parsing --- src/common/config.cpp | 111 +++++++++++++++++++++++++ src/common/config.h | 3 + src/input/input_handler.cpp | 158 ++++++++---------------------------- src/input/input_handler.h | 50 ++++++------ 4 files changed, 173 insertions(+), 149 deletions(-) diff --git a/src/common/config.cpp b/src/common/config.cpp index 1dde7223c40..3a926bc9745 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -701,4 +701,115 @@ void setDefaultValues() { gpuId = -1; } +std::string_view getDefaultKeyboardConfig() { + static std::string_view default_config = + R"(#This is the default keybinding config +#To change per-game configs, modify the CUSAXXXXX.ini files +#To change the default config that applies to new games without already existing configs, modify default.ini +#If you don't like certain mappings, delete, change or comment them out. +#You can add any amount of KBM keybinds to a single controller input, +#but you can use each KBM keybind for one controller input. + +#Keybinds used by the emulator (these are unchangeable): +#F11 : fullscreen +#F10 : FPS counter +#F9 : toggle mouse-to-joystick input +# (it overwrites everything else to that joystick, so this is required) +#F8 : reparse keyboard input(this) + +#This is a mapping for Bloodborne, inspired by other Souls titles on PC. + +#Specifies which joystick the mouse movement controls. +mouse_to_joystick = right; + +#Use healing item, change status in inventory +triangle = f; +#Dodge, back in inventory +circle = space; +#Interact, select item in inventory +cross = e; +#Use quick item, remove item in inventory +square = r; + +#Emergency extra bullets +up = w, lalt; +up = mousewheelup; +#Change quick item +down = s, lalt; +down = mousewheeldown; +#Change weapon in left hand +left = a, lalt; +left = mousewheelleft; +#Change weapon in right hand +right = d, lalt; +right = mousewheelright; +#Change into 'inventory mode', so you don't have to hold lalt every time you go into menus +modkey_toggle = i, lalt; + +#Menu +options = escape; +#Gestures +touchpad = g; + +#Transform +l1 = rightbutton, lshift; +#Shoot +r1 = leftbutton; +#Light attack +l2 = rightbutton; +#Heavy attack +r2 = leftbutton, lshift; +#Does nothing +l3 = x; +#Center cam, lock on +r3 = q; +r3 = middlebutton; + +#Axis mappings +#Move +axis_left_x_minus = a; +axis_left_x_plus = d; +axis_left_y_minus = w; +axis_left_y_plus = s; +#Change to 'walk mode' by holding the following key: +leftjoystick_halfmode = lctrl; +)"; + return default_config; +} +std::filesystem::path getFoolproofKbmConfigFile(const std::string& game_id) { + // Read configuration file of the game, and if it doesn't exist, generate it from default + // If that doesn't exist either, generate that from getDefaultConfig() and try again + // If even the folder is missing, we start with that. + + const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "kbmConfig"; + const auto config_file = config_dir / (game_id + ".ini"); + const auto default_config_file = config_dir / "default.ini"; + + // Ensure the config directory exists + if (!std::filesystem::exists(config_dir)) { + std::filesystem::create_directories(config_dir); + } + + // Check if the default config exists + if (!std::filesystem::exists(default_config_file)) { + // If the default config is also missing, create it from getDefaultConfig() + const auto default_config = getDefaultKeyboardConfig(); + std::ofstream default_config_stream(default_config_file); + if (default_config_stream) { + default_config_stream << default_config; + } + } + + // if empty, we only need to execute the function up until this point + if(game_id.empty()) { + return default_config_file; + } + + // If game-specific config doesn't exist, create it from the default config + if (!std::filesystem::exists(config_file)) { + std::filesystem::copy(default_config_file, config_file); + } + return config_file; +} + } // namespace Config diff --git a/src/common/config.h b/src/common/config.h index 9c71c96a8e6..3dfafade7b3 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -123,6 +123,9 @@ std::string getEmulatorLanguage(); void setDefaultValues(); +// todo: name and function location pending +std::filesystem::path getFoolproofKbmConfigFile(const std::string& game_id = ""); + // settings u32 GetLanguage(); }; // namespace Config diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 62be8f590a0..72e872550b3 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -44,122 +44,16 @@ float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.1250; Uint32 mouse_polling_id = 0; bool mouse_enabled = false, leftjoystick_halfmode = false, rightjoystick_halfmode = false; -std::string_view getDefaultKeyboardConfig() { - static std::string_view default_config = - R"(## SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project -## SPDX-License-Identifier: GPL-2.0-or-later - -#This is the default keybinding config -#To change per-game configs, modify the CUSAXXXXX.ini files -#To change the default config that applies to new games without already existing configs, modify default.ini -#If you don't like certain mappings, delete, change or comment them out. -#You can add any amount of KBM keybinds to a single controller input, -#but you can use each KBM keybind for one controller input. - -#Keybinds used by the emulator (these are unchangeable): -#F11 : fullscreen -#F10 : FPS counter -#F9 : toggle mouse-to-joystick input -# (it overwrites everything else to that joystick, so this is required) -#F8 : reparse keyboard input(this) - -#This is a mapping for Bloodborne, inspired by other Souls titles on PC. - -#Specifies which joystick the mouse movement controls. -mouse_to_joystick = right; - -#Use healing item, change status in inventory -triangle = f; -#Dodge, back in inventory -circle = space; -#Interact, select item in inventory -cross = e; -#Use quick item, remove item in inventory -square = r; - -#Emergency extra bullets -up = w, lalt; -up = mousewheelup; -#Change quick item -down = s, lalt; -down = mousewheeldown; -#Change weapon in left hand -left = a, lalt; -left = mousewheelleft; -#Change weapon in right hand -right = d, lalt; -right = mousewheelright; -#Change into 'inventory mode', so you don't have to hold lalt every time you go into menus -modkey_toggle = i, lalt; - -#Menu -options = escape; -#Gestures -touchpad = g; - -#Transform -l1 = rightbutton, lshift; -#Shoot -r1 = leftbutton; -#Light attack -l2 = rightbutton; -#Heavy attack -r2 = leftbutton, lshift; -#Does nothing -l3 = x; -#Center cam, lock on -r3 = q; -r3 = middlebutton; - -#Axis mappings -#Move -axis_left_x_minus = a; -axis_left_x_plus = d; -axis_left_y_minus = w; -axis_left_y_plus = s; -#Change to 'walk mode' by holding the following key: -leftjoystick_halfmode = lctrl; -)"; - return default_config; -} - void parseInputConfig(const std::string game_id = "") { - // Read configuration file of the game, and if it doesn't exist, generate it from default - // If that doesn't exist either, generate that from getDefaultConfig() and try again - // If even the folder is missing, we start with that. - - // maybe extract this? - const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "kbmConfig"; - const auto config_file = config_dir / (game_id + ".ini"); - const auto default_config_file = config_dir / "default.ini"; + + const auto config_file = Config::getFoolproofKbmConfigFile(game_id); - // Ensure the config directory exists - if (!std::filesystem::exists(config_dir)) { - std::filesystem::create_directories(config_dir); - } - - // Try loading the game-specific config file - if (!std::filesystem::exists(config_file)) { - // If game-specific config doesn't exist, check for the default config - if (!std::filesystem::exists(default_config_file)) { - // If the default config is also missing, create it from getDefaultConfig() - const auto default_config = getDefaultKeyboardConfig(); - std::ofstream default_config_stream(default_config_file); - if (default_config_stream) { - default_config_stream << default_config; - } - } - - // If default config now exists, copy it to the game-specific config file - if (std::filesystem::exists(default_config_file) && !game_id.empty()) { - std::filesystem::copy(default_config_file, config_file); - } - } - // if we just called the function to generate the directory and the default .ini - if (game_id.empty()) { + // todo: change usages of this to getFoolproofKbmConfigFile (gui) + if(game_id == "") { return; } + // todo // we reset these here so in case the user fucks up or doesn't include this we can fall back to // default mouse_deadzone_offset = 0.5; @@ -293,17 +187,18 @@ void ControllerOutput::setControllerOutputController(GameController* c) { ControllerOutput::controller = c; } -void ControllerOutput::update(bool pressed, int axis_direction) { +void ControllerOutput::update(bool pressed, int axis_value) { float touchpad_x = 0; - Input::Axis axis = Input::Axis::AxisMax; if(button != 0){ switch (button) { + /* todo case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2: case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2: - axis = (button == OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2) ? Input::Axis::TriggerRight - : Input::Axis::TriggerLeft; - controller->Axis(0, axis, Input::GetAxis(0, 0x80, pressed ? 255 : 0)); + axis = (button == OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2) ? Axis::TriggerRight + : Axis::TriggerLeft; + controller->Axis(0, axis, GetAxis(0, 0x80, pressed ? 128 : 0)); break; + */ case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD: touchpad_x = Config::getBackButtonBehavior() == "left" ? 0.25f : Config::getBackButtonBehavior() == "right" ? 0.75f @@ -311,26 +206,37 @@ void ControllerOutput::update(bool pressed, int axis_direction) { controller->SetTouchpadState(0, true, touchpad_x, 0.5f); controller->CheckButton(0, button, pressed); break; - default: // is a normal key + case LEFTJOYSTICK_HALFMODE: + leftjoystick_halfmode ^= pressed; // toggle if pressed, don't change otherwise + break; + case RIGHTJOYSTICK_HALFMODE: + rightjoystick_halfmode ^= pressed; + break; + default: // is a normal key (hopefully) controller->CheckButton(0, button, pressed); break; } } else if (axis != Axis::AxisMax) { float multiplier = 1.0; switch (axis) { - case Input::Axis::LeftX: - case Input::Axis::LeftY: + case Axis::LeftX: + case Axis::LeftY: multiplier = leftjoystick_halfmode ? 0.5 : 1.0; break; - case Input::Axis::RightX: - case Input::Axis::RightY: + case Axis::RightX: + case Axis::RightY: multiplier = rightjoystick_halfmode ? 0.5 : 1.0; break; + case Axis::TriggerLeft: + case Axis::TriggerRight: + // todo: verify this works + controller->Axis(0, axis, GetAxis(0, 0x80, pressed ? 128 : 0)); + break; default: break; } int output_value = (pressed ? axis_value : 0) * multiplier; - int ax = Input::GetAxis(-0x80, 0x80, output_value); + int ax = GetAxis(-0x80, 0x80, output_value); controller->Axis(0, axis, ax); } else { LOG_ERROR(Input, "Controller output with no values detected!"); @@ -366,11 +272,11 @@ void updateMouse(GameController* controller) { float a_x = cos(angle) * output_speed, a_y = sin(angle) * output_speed; if (d_x != 0 && d_y != 0) { - controller->Axis(0, axis_x, Input::GetAxis(-0x80, 0x80, a_x)); - controller->Axis(0, axis_y, Input::GetAxis(-0x80, 0x80, a_y)); + controller->Axis(0, axis_x, GetAxis(-0x80, 0x80, a_x)); + controller->Axis(0, axis_y, GetAxis(-0x80, 0x80, a_y)); } else { - controller->Axis(0, axis_x, Input::GetAxis(-0x80, 0x80, 0)); - controller->Axis(0, axis_y, Input::GetAxis(-0x80, 0x80, 0)); + controller->Axis(0, axis_x, GetAxis(-0x80, 0x80, 0)); + controller->Axis(0, axis_y, GetAxis(-0x80, 0x80, 0)); } } diff --git a/src/input/input_handler.h b/src/input/input_handler.h index 075a3996e01..7dc3453ea26 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -7,6 +7,7 @@ #include "map" #include "string" #include "common/types.h" +#include "common/logging/log.h" #include "core/libraries/pad/pad.h" #include "input/controller.h" @@ -174,9 +175,8 @@ void parseInputConfig(const std::string game_id); class InputBinding { public: u32 key1, key2, key3; - int axis_value; - InputBinding(int v, u32 k1 = SDLK_UNKNOWN, u32 k2 = SDLK_UNKNOWN, u32 k3 = SDLK_UNKNOWN) { - // we format the keys so comaring them will be very fast, because we will only have to compare 3 sorted elements, + InputBinding(u32 k1 = SDLK_UNKNOWN, u32 k2 = SDLK_UNKNOWN, u32 k3 = SDLK_UNKNOWN) { + // we format the keys so comparing them will be very fast, because we will only have to compare 3 sorted elements, // where the only possible duplicate item is 0 // duplicate entries get changed to one original, one null @@ -198,6 +198,8 @@ class InputBinding { else { key2 = k2; key3 = k1; } } } + // copy ctor + InputBinding(const InputBinding& o) : key1(o.key1), key2(o.key2), key3(o.key3) {} inline bool operator==(const InputBinding& o) { // 0 = SDLK_UNKNOWN aka unused slot @@ -209,6 +211,7 @@ class InputBinding { // potenially skipping the later expressions of the three-way AND } + // returns a u32 based on the event type (keyboard, mouse buttons, or wheel) static u32 getInputIDFromEvent(const SDL_Event& e) { switch(e.type) { case SDL_EVENT_KEY_DOWN: @@ -229,43 +232,44 @@ class ControllerOutput { public: static void setControllerOutputController(GameController* c); - std::string name; u32 button; - Input::Axis axis; - int axis_value; - bool active; - ControllerOutput(const std::string& n, u32 b, Axis a = Axis::AxisMax, int v = 0, bool ac = false) { - name = n; + Axis axis; + + ControllerOutput(u32 b, Axis a = Axis::AxisMax) { button = b; axis = a; - axis_value = v; - active = ac; } - ControllerOutput(const ControllerOutput& o); + ControllerOutput(const ControllerOutput& o) : button(o.button), axis(o.axis) {} void update(bool pressed, int axis_direction = 0); }; -class InputData { +class BindingConnection { +public: InputBinding binding; + ControllerOutput* output; int axis_value; - bool flag; - InputData(InputBinding b, int v = 0) : binding(b), axis_value(v), flag(false) {} + BindingConnection(InputBinding b, ControllerOutput* out, int a_v = 0) { + binding = b; + axis_value = 0; + + // todo: check if out is in the allowed array + output = out; + } }; // todo // don't forget to change the number too -const std::array input_state = { -// buttons and axes rolled into one -ControllerOutput("up", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP), -ControllerOutput("down", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN), -// etc. -ControllerOutput("axis_left_x_plus", 0, Axis::LeftX, 127), -ControllerOutput("axis_left_x_minus", 0, Axis::LeftX, -127), +const std::array output_array = { +ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP), +ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN), + +ControllerOutput(0, Axis::TriggerLeft), +ControllerOutput(0, Axis::LeftY), // etc. }; -extern std::map new_binding_map; +extern std::map new_binding_map; extern u32 pressed_keys[]; // Check if the 3 key input is currently active. From 86c87013235339c85001f3bf6a6b9cc97f043183 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Wed, 13 Nov 2024 17:09:00 +0100 Subject: [PATCH 40/79] Parsing works now --- src/input/input_handler.cpp | 112 ++++++++++++++++++++++++++++++------ src/input/input_handler.h | 30 +++++----- src/sdl_window.cpp | 14 +++-- src/sdl_window.h | 2 +- 4 files changed, 120 insertions(+), 38 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 72e872550b3..8883d109963 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -3,15 +3,16 @@ #include "input_handler.h" -#include -#include -#include -#include -#include -#include +#include "fstream" +#include "iostream" +#include "map" +#include "list" +#include "sstream" +#include "string" +#include "vector" -#include -#include +#include "SDL3/SDL_events.h" +#include "SDL3/SDL_timer.h" #include "common/config.h" #include "common/io_file.h" @@ -44,11 +45,66 @@ float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.1250; Uint32 mouse_polling_id = 0; bool mouse_enabled = false, leftjoystick_halfmode = false, rightjoystick_halfmode = false; +// todo +ControllerOutput output_array[] = { + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN), + + ControllerOutput(0, Axis::TriggerLeft), + ControllerOutput(0, Axis::LeftY), + // etc. + + // signifies the end of the array + ControllerOutput(0, Axis::AxisMax), +}; +std::list connections = std::list(); + +// parsing related functions + +// syntax: 'name, name,name' or 'name,name' or 'name' +InputBinding getBindingFromString(std::string& line) { + u32 key1 = 0, key2 = 0, key3 = 0; + + // Split the string by commas + std::vector tokens; + std::stringstream ss(line); + std::string token; + + while (std::getline(ss, token, ',')) { + tokens.push_back(token); + } + + // Check for invalid tokens and map valid ones to keys + for (const auto& t : tokens) { + if (string_to_keyboard_key_map.find(t) == string_to_keyboard_key_map.end()) { + return InputBinding(0, 0, 0); // Skip by setting all keys to 0 + } + } + + // Assign values to keys if all tokens were valid + if (tokens.size() > 0) key1 = string_to_keyboard_key_map.at(tokens[0]); + if (tokens.size() > 1) key2 = string_to_keyboard_key_map.at(tokens[1]); + if (tokens.size() > 2) key3 = string_to_keyboard_key_map.at(tokens[2]); + + return InputBinding(key1, key2, key3); +} + +// function that takes a controlleroutput, and returns the array's corresponding element's pointer +ControllerOutput* getOutputPointer(const ControllerOutput& parsed) { + // i wonder how long until someone notices this or I get rid of it + for (int i = 0; i[output_array] != ControllerOutput(0, Axis::AxisMax); i++) { + if(i[output_array] == parsed) { + return &output_array[i]; + } + } + return nullptr; +} + void parseInputConfig(const std::string game_id = "") { const auto config_file = Config::getFoolproofKbmConfigFile(game_id); - // todo: change usages of this to getFoolproofKbmConfigFile (gui) + // todo: change usages of this to getFoolproofKbmConfigFile (in the gui) if(game_id == "") { return; } @@ -80,8 +136,7 @@ void parseInputConfig(const std::string game_id = "") { // Split the line by '=' std::size_t equal_pos = line.find('='); if (equal_pos == std::string::npos) { - std::cerr << "Invalid line format at line: " << lineCount << " data: " << line - << std::endl; + LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); continue; } @@ -89,8 +144,6 @@ void parseInputConfig(const std::string game_id = "") { std::string after_equals = line.substr(equal_pos + 1); std::size_t comma_pos = after_equals.find(','); - // new data type construcor here - // todo // special check for mouse to joystick input if (before_equals == "mouse_to_joystick") { @@ -108,12 +161,34 @@ void parseInputConfig(const std::string game_id = "") { if (comma_pos != std::string::npos) { // handle key-to-key toggling (separate list?) // todo + LOG_ERROR(Input, "todo"); + continue; } - std::cerr << "Invalid line format at line: " << lineCount << " data: " << line - << std::endl; + LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); continue; } - // todo + + // normal cases + InputBinding binding = getBindingFromString(after_equals); + BindingConnection connection(0, nullptr); + auto button_it = string_to_cbutton_map.find(before_equals); + auto axis_it = string_to_axis_map.find(before_equals); + + if(binding.isEmpty()) { + LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); + continue; + } + if (button_it != string_to_cbutton_map.end()) { + connection = BindingConnection(binding, getOutputPointer(ControllerOutput(button_it->second))); + connections.push_back(connection); + } else if (axis_it != string_to_axis_map.end()) { + connection = BindingConnection(binding, getOutputPointer(ControllerOutput(0, axis_it->second.axis)), axis_it->second.value); + connections.push_back(connection); + } else { + LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); + continue; + } + LOG_INFO(Input, "Succesfully parsed line {}", lineCount); /* og parsing // first we parse the binding, and if its wrong, we skip to the next line if (comma_pos != std::string::npos) { @@ -243,6 +318,11 @@ void ControllerOutput::update(bool pressed, int axis_value) { } } +void activateOutputsFromInputs() { + // iterates over the connections, and updates them depending on whether the corresponding input trio is found + +} + void updateMouse(GameController* controller) { if (!mouse_enabled) return; diff --git a/src/input/input_handler.h b/src/input/input_handler.h index 7dc3453ea26..2857d1c149f 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -5,14 +5,15 @@ #include "array" #include "map" +#include "unordered_set" #include "string" #include "common/types.h" #include "common/logging/log.h" #include "core/libraries/pad/pad.h" #include "input/controller.h" -#include -#include +#include "SDL3/SDL_events.h" +#include "SDL3/SDL_timer.h" // +1 and +2 is taken #define SDL_MOUSE_WHEEL_UP SDL_EVENT_MOUSE_WHEEL + 3 @@ -210,6 +211,9 @@ class InputBinding { // but reverse order makes it check the actual keys first instead of possible 0-s, // potenially skipping the later expressions of the three-way AND } + inline bool isEmpty() { + return key1 == 0 && key2 == 0 && key3 == 0; + } // returns a u32 based on the event type (keyboard, mouse buttons, or wheel) static u32 getInputIDFromEvent(const SDL_Event& e) { @@ -235,11 +239,17 @@ class ControllerOutput { u32 button; Axis axis; - ControllerOutput(u32 b, Axis a = Axis::AxisMax) { + ControllerOutput(const u32 b, Axis a = Axis::AxisMax) { button = b; axis = a; } ControllerOutput(const ControllerOutput& o) : button(o.button), axis(o.axis) {} + inline bool operator==(const ControllerOutput& o) const { // fucking consts everywhere + return button == o.button && axis == o.axis; + } + inline bool operator!=(const ControllerOutput& o) const { + return button != o.button || axis != o.axis; + } void update(bool pressed, int axis_direction = 0); }; class BindingConnection { @@ -258,18 +268,8 @@ class BindingConnection { }; // todo -// don't forget to change the number too -const std::array output_array = { -ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP), -ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN), - -ControllerOutput(0, Axis::TriggerLeft), -ControllerOutput(0, Axis::LeftY), -// etc. -}; - - -extern std::map new_binding_map; +//extern ControllerOutput output_array[]; +//extern std::map new_binding_map; extern u32 pressed_keys[]; // Check if the 3 key input is currently active. diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index c81a495fe22..cfa0e3eb309 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -1,14 +1,15 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include -#include -#include -#include -#include +#include "SDL3/SDL_events.h" +#include "SDL3/SDL_init.h" +#include "SDL3/SDL_properties.h" +#include "SDL3/SDL_timer.h" +#include "SDL3/SDL_video.h" #include "common/assert.h" #include "common/config.h" #include "common/version.h" +#include "common/elf_info.h" #include "core/libraries/pad/pad.h" #include "imgui/renderer/imgui_core.h" #include "input/controller.h" @@ -17,7 +18,7 @@ #include "video_core/renderdoc.h" #ifdef __APPLE__ -#include +#include "SDL3/SDL_metal.h" #endif namespace Frontend { @@ -79,6 +80,7 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_ #endif // input handler init-s Input::ControllerOutput::setControllerOutputController(controller); + Input::parseInputConfig(std::string(Common::ElfInfo::Instance().GameSerial())); } WindowSDL::~WindowSDL() = default; diff --git a/src/sdl_window.h b/src/sdl_window.h index ad27ba4a55a..1c298682f59 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -3,7 +3,7 @@ #pragma once -#include +#include "string" #include "common/types.h" struct SDL_Window; From 5c2d09dd3e338a62ef7762344b3ce110e795f6d7 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Wed, 13 Nov 2024 19:03:42 +0100 Subject: [PATCH 41/79] Single key button inputs work now --- src/input/input_handler.cpp | 188 +++++++++++++++++------------- src/input/input_handler.h | 10 +- src/sdl_window.cpp | 220 +++++------------------------------- 3 files changed, 146 insertions(+), 272 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 8883d109963..c72689c07d6 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -6,6 +6,7 @@ #include "fstream" #include "iostream" #include "map" +#include "unordered_map" #include "list" #include "sstream" #include "string" @@ -45,19 +46,45 @@ float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.1250; Uint32 mouse_polling_id = 0; bool mouse_enabled = false, leftjoystick_halfmode = false, rightjoystick_halfmode = false; -// todo +std::list pressed_keys = std::list(); +std::list connections = std::list(); + +void toggleMouseEnabled() { + mouse_enabled ^= true; +} ControllerOutput output_array[] = { + // Button mappings + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD), ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP), ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN), - - ControllerOutput(0, Axis::TriggerLeft), - ControllerOutput(0, Axis::LeftY), - // etc. - - // signifies the end of the array - ControllerOutput(0, Axis::AxisMax), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT), + + // Axis mappings + ControllerOutput(0, Input::Axis::LeftX), + ControllerOutput(0, Input::Axis::LeftY), + ControllerOutput(0, Input::Axis::RightX), + ControllerOutput(0, Input::Axis::RightY), + ControllerOutput(0, Input::Axis::TriggerLeft), + ControllerOutput(0, Input::Axis::TriggerRight), + + ControllerOutput(LEFTJOYSTICK_HALFMODE), + ControllerOutput(RIGHTJOYSTICK_HALFMODE), + + // End marker to signify the end of the array + ControllerOutput(0, Input::Axis::AxisMax) }; -std::list connections = std::list(); // parsing related functions @@ -167,6 +194,10 @@ void parseInputConfig(const std::string game_id = "") { LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); continue; } + if (before_equals == "mouse_movement_params") { + LOG_ERROR(Input, "todo"); + continue; + } // normal cases InputBinding binding = getBindingFromString(after_equals); @@ -180,78 +211,15 @@ void parseInputConfig(const std::string game_id = "") { } if (button_it != string_to_cbutton_map.end()) { connection = BindingConnection(binding, getOutputPointer(ControllerOutput(button_it->second))); - connections.push_back(connection); + connections.insert(connections.end(), connection); } else if (axis_it != string_to_axis_map.end()) { connection = BindingConnection(binding, getOutputPointer(ControllerOutput(0, axis_it->second.axis)), axis_it->second.value); - connections.push_back(connection); + connections.insert(connections.end(), connection); } else { LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); continue; } - LOG_INFO(Input, "Succesfully parsed line {}", lineCount); - /* og parsing - // first we parse the binding, and if its wrong, we skip to the next line - if (comma_pos != std::string::npos) { - // Handle key + modifier - std::string key = after_equals.substr(0, comma_pos); - std::string mod = after_equals.substr(comma_pos + 1); - - auto key_it = string_to_keyboard_key_map.find(key); - auto mod_it = string_to_keyboard_mod_key_map.find(mod); - - if (key_it != string_to_keyboard_key_map.end() && - mod_it != string_to_keyboard_mod_key_map.end()) { - binding.key = key_it->second; - binding.modifier = mod_it->second; - } else if (before_equals == "mouse_movement_params") { - // handle mouse movement params - float p1 = 0.5, p2 = 1, p3 = 0.125; - std::size_t second_comma_pos = after_equals.find(','); - try { - p1 = std::stof(key); - p2 = std::stof(mod.substr(0, second_comma_pos)); - p3 = std::stof(mod.substr(second_comma_pos + 1)); - mouse_deadzone_offset = p1; - mouse_speed = p2; - mouse_speed_offset = p3; - } catch (...) { - // fallback to default values - mouse_deadzone_offset = 0.5; - mouse_speed = 1; - mouse_speed_offset = 0.125; - std::cerr << "Parsing error while parsing kbm inputs at line " << lineCount - << " line data: " << line << "\n"; - } - continue; - } else { - std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount - << " line data: " << line << "\n"; - continue; // skip - } - } else { - // Just a key without modifier - auto key_it = string_to_keyboard_key_map.find(after_equals); - if (key_it != string_to_keyboard_key_map.end()) { - binding.key = key_it->second; - } else { - std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount - << " line data: " << line << "\n"; - continue; // skip - } - } - - // Check for axis mapping (example: axis_left_x_plus) - auto axis_it = string_to_axis_map.find(before_equals); - auto button_it = string_to_cbutton_map.find(before_equals); - if (axis_it != string_to_axis_map.end()) { - old_axis_map[binding] = axis_it->second; - } else if (button_it != string_to_cbutton_map.end()) { - old_button_map[binding] = button_it->second; - } else { - std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount - << " line data: " << line << "\n"; - } - */ + //LOG_INFO(Input, "Succesfully parsed line {}", lineCount); } file.close(); } @@ -262,18 +230,23 @@ void ControllerOutput::setControllerOutputController(GameController* c) { ControllerOutput::controller = c; } + + void ControllerOutput::update(bool pressed, int axis_value) { + if(controller == nullptr) { + LOG_ERROR(Input, "No controller found!"); + return; + } float touchpad_x = 0; if(button != 0){ switch (button) { - /* todo + // todo: check if l2 and r2 can be moved to the axis section case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2: case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2: axis = (button == OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2) ? Axis::TriggerRight : Axis::TriggerLeft; controller->Axis(0, axis, GetAxis(0, 0x80, pressed ? 128 : 0)); break; - */ case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD: touchpad_x = Config::getBackButtonBehavior() == "left" ? 0.25f : Config::getBackButtonBehavior() == "right" ? 0.75f @@ -318,9 +291,68 @@ void ControllerOutput::update(bool pressed, int axis_value) { } } +void updatePressedKeys(u32 value, bool is_pressed) { + if (is_pressed) { + // Find the correct position for insertion to maintain order + auto it = std::lower_bound(pressed_keys.begin(), pressed_keys.end(), value); + + // Insert only if 'value' is not already in the list + if (it == pressed_keys.end() || *it != value) { + pressed_keys.insert(it, value); + } + } else { + // Remove 'value' from the list if it's not pressed + pressed_keys.remove(value); + } +} + +// Check if a given binding's all keys are currently active. +bool isInputActive(const InputBinding& i) { + /* how to check if a binding is currently held down: + iterate until connection.InputBinding.key3 is found or we reach the end + iterate from that point until connection.InputBinding.key2 is found or we reach the end + iterate from that point until connection.InputBinding.key1 is found or we reach the end + if we ever reach the end, return false + if the next key to find would be 0, return true + if all three are found return true + */ + auto it = pressed_keys.begin(); + + // Check for key1 if it's set + if (i.key1 != 0) { + it = std::find(it, pressed_keys.end(), i.key1); + if (it == pressed_keys.end()) return false; + ++it; // Move to the next element for subsequent checks + } + + // Check for key2 if it's set + if (i.key2 != 0) { + it = std::find(it, pressed_keys.end(), i.key2); + if (it == pressed_keys.end()) return false; + ++it; + } + + // Check for key3 if it's set + if (i.key3 != 0) { + it = std::find(it, pressed_keys.end(), i.key3); + if (it == pressed_keys.end()) return false; + } + + // All required keys were found in order + LOG_INFO(Input, "A valid held input is found!"); + return true; +} + void activateOutputsFromInputs() { // iterates over the connections, and updates them depending on whether the corresponding input trio is found - + for(auto it = connections.begin(); it != connections.end(); it++) { + if (it->output) { // Check if output is not nullptr + it->output->update(isInputActive(it->binding), it->axis_value); + LOG_INFO(Input, "Updating an output"); + } else { + LOG_ERROR(Input, "Null output in BindingConnection at position {}", std::distance(connections.begin(), it)); + } + } } void updateMouse(GameController* controller) { diff --git a/src/input/input_handler.h b/src/input/input_handler.h index 2857d1c149f..73ad461cb50 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -168,6 +168,9 @@ const std::map string_to_keyboard_key_map = { {"capslock", SDLK_CAPSLOCK}, }; +// literally the only flag that needs external access +void toggleMouseEnabled(); + // i wrapped it in a function so I can collapse it std::string_view getDefaultKeyboardConfig(); @@ -267,17 +270,14 @@ class BindingConnection { }; -// todo -//extern ControllerOutput output_array[]; -//extern std::map new_binding_map; -extern u32 pressed_keys[]; - // Check if the 3 key input is currently active. bool checkForInputDown(InputBinding i); // Add/remove the input that generated the event to/from the held keys container. void updatePressedKeys(u32 button, bool is_pressed); +void activateOutputsFromInputs(); + void updateMouse(GameController* controller); diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index cfa0e3eb309..e7dfbae0709 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -108,7 +108,9 @@ void WindowSDL::waitEvent() { is_shown = event.type == SDL_EVENT_WINDOW_EXPOSED; onResize(); break; - + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: + case SDL_EVENT_MOUSE_WHEEL: case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: onKeyboardMouseInput(&event); @@ -146,201 +148,41 @@ void WindowSDL::onKeyboardMouseInput(const SDL_Event* event) { using Libraries::Pad::OrbisPadButtonDataOffset; // get the event's id, if it's keyup or keydown + bool input_down = event->type == SDL_EVENT_KEY_DOWN || + event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || + event->type == SDL_EVENT_MOUSE_WHEEL; + u32 input_id = Input::InputBinding::getInputIDFromEvent(*event); - // add/remove it from the list - - // update bindings and buttons - - // update axes - -/* og function -#ifdef __APPLE__ - // Use keys that are more friendly for keyboards without a keypad. - // Once there are key binding options this won't be necessary. - constexpr SDL_Keycode CrossKey = SDLK_N; - constexpr SDL_Keycode CircleKey = SDLK_B; - constexpr SDL_Keycode SquareKey = SDLK_V; - constexpr SDL_Keycode TriangleKey = SDLK_C; -#else - constexpr SDL_Keycode CrossKey = SDLK_KP_2; - constexpr SDL_Keycode CircleKey = SDLK_KP_6; - constexpr SDL_Keycode SquareKey = SDLK_KP_4; - constexpr SDL_Keycode TriangleKey = SDLK_KP_8; -#endif - - u32 button = 0; - Input::Axis axis = Input::Axis::AxisMax; - int axisvalue = 0; - int ax = 0; - std::string backButtonBehavior = Config::getBackButtonBehavior(); - switch (event->key.key) { - case SDLK_UP: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP; - break; - case SDLK_DOWN: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN; - break; - case SDLK_LEFT: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT; - break; - case SDLK_RIGHT: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT; - break; - case TriangleKey: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE; - break; - case CircleKey: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE; - break; - case CrossKey: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS; - break; - case SquareKey: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE; - break; - case SDLK_RETURN: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS; - break; - case SDLK_A: - axis = Input::Axis::LeftX; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += -127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_D: - axis = Input::Axis::LeftX; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += 127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_W: - axis = Input::Axis::LeftY; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += -127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_S: - axis = Input::Axis::LeftY; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += 127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_J: - axis = Input::Axis::RightX; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += -127; - } else { - axisvalue = 0; + // Handle window controls outside of the input maps + if (event->type == SDL_EVENT_KEY_DOWN) { + // Reparse kbm inputs + if (input_id == SDLK_F8) { + Input::parseInputConfig(std::string(Common::ElfInfo::Instance().GameSerial())); } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_L: - axis = Input::Axis::RightX; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += 127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_I: - axis = Input::Axis::RightY; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += -127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_K: - axis = Input::Axis::RightY; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += 127; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(-0x80, 0x80, axisvalue); - break; - case SDLK_X: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3; - break; - case SDLK_M: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3; - break; - case SDLK_Q: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1; - break; - case SDLK_U: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1; - break; - case SDLK_E: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2; - axis = Input::Axis::TriggerLeft; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += 255; - } else { - axisvalue = 0; + // Toggle mouse capture and movement input + else if (input_id == SDLK_F7) { + Input::toggleMouseEnabled(); + SDL_SetWindowRelativeMouseMode(this->GetSdlWindow(), + !SDL_GetWindowRelativeMouseMode(this->GetSdlWindow())); } - ax = Input::GetAxis(0, 0x80, axisvalue); - break; - case SDLK_O: - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2; - axis = Input::Axis::TriggerRight; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += 255; - } else { - axisvalue = 0; - } - ax = Input::GetAxis(0, 0x80, axisvalue); - break; - case SDLK_SPACE: - if (backButtonBehavior != "none") { - float x = backButtonBehavior == "left" ? 0.25f - : (backButtonBehavior == "right" ? 0.75f : 0.5f); - // trigger a touchpad event so that the touchpad emulation for back button works - controller->SetTouchpadState(0, true, x, 0.5f); - button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD; - } else { - button = 0; + // Toggle fullscreen + else if (input_id == SDLK_F11) { + SDL_WindowFlags flag = SDL_GetWindowFlags(window); + bool is_fullscreen = flag & SDL_WINDOW_FULLSCREEN; + SDL_SetWindowFullscreen(window, !is_fullscreen); } - break; - case SDLK_F11: - if (event->type == SDL_EVENT_KEY_DOWN) { - { - SDL_WindowFlags flag = SDL_GetWindowFlags(window); - bool is_fullscreen = flag & SDL_WINDOW_FULLSCREEN; - SDL_SetWindowFullscreen(window, !is_fullscreen); - } - } - break; - case SDLK_F12: - if (event->type == SDL_EVENT_KEY_DOWN) { - // Trigger rdoc capture + // Trigger rdoc capture + else if (input_id == SDLK_F12) { VideoCore::TriggerCapture(); } - break; - default: - break; } - if (button != 0) { - controller->CheckButton(0, button, event->type == SDL_EVENT_KEY_DOWN); - } - if (axis != Input::Axis::AxisMax) { - controller->Axis(0, axis, ax); - } -*/ + + // add/remove it from the list + Input::updatePressedKeys(input_id, input_down); + + // update bindings + Input::activateOutputsFromInputs(); + } void WindowSDL::onGamepadEvent(const SDL_Event* event) { From df738c6dc13d44cce0743535b3bd5650d4a9a96c Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Wed, 13 Nov 2024 21:20:46 +0100 Subject: [PATCH 42/79] Axis outputs work now --- src/input/input_handler.cpp | 127 ++++++++++++++++++++++++++++++------ src/input/input_handler.h | 23 +++---- src/sdl_window.cpp | 15 +++++ 3 files changed, 131 insertions(+), 34 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index c72689c07d6..2655c110e61 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -139,12 +139,10 @@ void parseInputConfig(const std::string game_id = "") { // todo // we reset these here so in case the user fucks up or doesn't include this we can fall back to // default + connections.clear(); mouse_deadzone_offset = 0.5; mouse_speed = 1; mouse_speed_offset = 0.125; - //old_button_map.clear(); - //old_axis_map.clear(); - //old_key_to_modkey_toggle_map.clear(); int lineCount = 0; std::ifstream file(config_file); @@ -187,7 +185,6 @@ void parseInputConfig(const std::string game_id = "") { if (before_equals == "modkey_toggle") { if (comma_pos != std::string::npos) { // handle key-to-key toggling (separate list?) - // todo LOG_ERROR(Input, "todo"); continue; } @@ -211,10 +208,10 @@ void parseInputConfig(const std::string game_id = "") { } if (button_it != string_to_cbutton_map.end()) { connection = BindingConnection(binding, getOutputPointer(ControllerOutput(button_it->second))); - connections.insert(connections.end(), connection); + connections.insert(connections.end(), connection); } else if (axis_it != string_to_axis_map.end()) { connection = BindingConnection(binding, getOutputPointer(ControllerOutput(0, axis_it->second.axis)), axis_it->second.value); - connections.insert(connections.end(), connection); + connections.insert(connections.end(), connection); } else { LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); continue; @@ -224,19 +221,43 @@ void parseInputConfig(const std::string game_id = "") { file.close(); } -// todo: add an init for this +Uint32 getMouseWheelEvent(const SDL_Event& event) { + if (event.type != SDL_EVENT_MOUSE_WHEEL || event.type != SDL_EVENT_MOUSE_WHEEL_OFF) + return 0; + if (event.wheel.y > 0) { + return SDL_MOUSE_WHEEL_UP; + } else if (event.wheel.y < 0) { + return SDL_MOUSE_WHEEL_DOWN; + } else if (event.wheel.x > 0) { + return SDL_MOUSE_WHEEL_RIGHT; + } else if (event.wheel.x < 0) { + return SDL_MOUSE_WHEEL_LEFT; + } + return 0; +} + +u32 InputBinding::getInputIDFromEvent(const SDL_Event& e) { + switch(e.type) { + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: + return e.key.key; + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: + return (u32)e.button.button; + case SDL_EVENT_MOUSE_WHEEL: + case SDL_EVENT_MOUSE_WHEEL_OFF: + return getMouseWheelEvent(e); + default: + return (u32)-1; + } +} + GameController* ControllerOutput::controller = nullptr; void ControllerOutput::setControllerOutputController(GameController* c) { ControllerOutput::controller = c; } - - -void ControllerOutput::update(bool pressed, int axis_value) { - if(controller == nullptr) { - LOG_ERROR(Input, "No controller found!"); - return; - } +void ControllerOutput::update(bool pressed, int a_value) { float touchpad_x = 0; if(button != 0){ switch (button) { @@ -278,14 +299,73 @@ void ControllerOutput::update(bool pressed, int axis_value) { case Axis::TriggerLeft: case Axis::TriggerRight: // todo: verify this works + //controller->Axis(0, axis, GetAxis(0, 0x80, pressed ? 128 : 0)); + break; + default: + break; + } + axis_value = SDL_clamp((pressed ? a_value : 0) * multiplier, -127, 127); + int ax = GetAxis(-0x80, 0x80, axis_value); + controller->Axis(0, axis, ax); + } else { + LOG_ERROR(Input, "Controller output with no values detected!"); + } +} +void ControllerOutput::addUpdate(bool pressed, int a_value) { + + float touchpad_x = 0; + if(button != 0){ + if(!pressed) { + return; + } + switch (button) { + // todo: check if l2 and r2 can be moved to the axis section + case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2: + case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2: + axis = (button == OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2) ? Axis::TriggerRight + : Axis::TriggerLeft; controller->Axis(0, axis, GetAxis(0, 0x80, pressed ? 128 : 0)); break; + case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD: + touchpad_x = Config::getBackButtonBehavior() == "left" ? 0.25f + : Config::getBackButtonBehavior() == "right" ? 0.75f + : 0.5f; + controller->SetTouchpadState(0, true, touchpad_x, 0.5f); + controller->CheckButton(0, button, pressed); + break; + case LEFTJOYSTICK_HALFMODE: + leftjoystick_halfmode ^= pressed; // toggle if pressed, don't change otherwise + break; + case RIGHTJOYSTICK_HALFMODE: + rightjoystick_halfmode ^= pressed; + break; + default: // is a normal key (hopefully) + controller->CheckButton(0, button, pressed); + break; + } + } else if (axis != Axis::AxisMax) { + float multiplier = 1.0; + switch (axis) { + case Axis::LeftX: + case Axis::LeftY: + multiplier = leftjoystick_halfmode ? 0.5 : 1.0; + break; + case Axis::RightX: + case Axis::RightY: + multiplier = rightjoystick_halfmode ? 0.5 : 1.0; + break; + case Axis::TriggerLeft: + case Axis::TriggerRight: + // todo: verify this works + //controller->Axis(0, axis, GetAxis(0, 0x80, pressed ? 128 : 0)); + break; default: break; } - int output_value = (pressed ? axis_value : 0) * multiplier; - int ax = GetAxis(-0x80, 0x80, output_value); + axis_value = SDL_clamp((pressed ? a_value : 0) * multiplier + axis_value, -127, 127); + int ax = GetAxis(-0x80, 0x80, axis_value); controller->Axis(0, axis, ax); + LOG_INFO(Input, "Axis value delta: {} final value: {}", a_value, axis_value); } else { LOG_ERROR(Input, "Controller output with no values detected!"); } @@ -344,15 +424,22 @@ bool isInputActive(const InputBinding& i) { } void activateOutputsFromInputs() { - // iterates over the connections, and updates them depending on whether the corresponding input trio is found + // reset everything for(auto it = connections.begin(); it != connections.end(); it++) { - if (it->output) { // Check if output is not nullptr - it->output->update(isInputActive(it->binding), it->axis_value); - LOG_INFO(Input, "Updating an output"); + if (it->output) { + it->output->update(false, 0); } else { LOG_ERROR(Input, "Null output in BindingConnection at position {}", std::distance(connections.begin(), it)); } } + // iterates over the connections, and updates them depending on whether the corresponding input trio is found + for(auto it = connections.begin(); it != connections.end(); it++) { + if (it->output) { + it->output->addUpdate(isInputActive(it->binding), it->axis_value); + } else { + //LOG_ERROR(Input, "Null output in BindingConnection at position {}", std::distance(connections.begin(), it)); + } + } } void updateMouse(GameController* controller) { diff --git a/src/input/input_handler.h b/src/input/input_handler.h index 73ad461cb50..0f3291b9638 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -21,6 +21,9 @@ #define SDL_MOUSE_WHEEL_LEFT SDL_EVENT_MOUSE_WHEEL + 5 #define SDL_MOUSE_WHEEL_RIGHT SDL_EVENT_MOUSE_WHEEL + 7 +// idk who already used what where so I just chose a big number +#define SDL_EVENT_MOUSE_WHEEL_OFF SDL_EVENT_USER + 10 + #define LEFTJOYSTICK_HALFMODE 0x00010000 #define RIGHTJOYSTICK_HALFMODE 0x00020000 @@ -219,19 +222,7 @@ class InputBinding { } // returns a u32 based on the event type (keyboard, mouse buttons, or wheel) - static u32 getInputIDFromEvent(const SDL_Event& e) { - switch(e.type) { - case SDL_EVENT_KEY_DOWN: - case SDL_EVENT_KEY_UP: - return e.key.key; - case SDL_EVENT_MOUSE_BUTTON_DOWN: - case SDL_EVENT_MOUSE_BUTTON_UP: - return (u32)e.button.button; - default: - // todo: add the rest (wheel) - return 0; - } - } + static u32 getInputIDFromEvent(const SDL_Event& e); }; class ControllerOutput { @@ -241,10 +232,12 @@ class ControllerOutput { u32 button; Axis axis; + int axis_value; ControllerOutput(const u32 b, Axis a = Axis::AxisMax) { button = b; axis = a; + axis_value = 0; } ControllerOutput(const ControllerOutput& o) : button(o.button), axis(o.axis) {} inline bool operator==(const ControllerOutput& o) const { // fucking consts everywhere @@ -254,6 +247,8 @@ class ControllerOutput { return button != o.button || axis != o.axis; } void update(bool pressed, int axis_direction = 0); + // Off events are not counted + void addUpdate(bool pressed, int axis_direction = 0); }; class BindingConnection { public: @@ -262,7 +257,7 @@ class BindingConnection { int axis_value; BindingConnection(InputBinding b, ControllerOutput* out, int a_v = 0) { binding = b; - axis_value = 0; + axis_value = a_v; // bruh this accidentally set to be 0 no wonder it didn't do anything // todo: check if out is in the allowed array output = out; diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index e7dfbae0709..8ff2f14f184 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -111,6 +111,7 @@ void WindowSDL::waitEvent() { case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: case SDL_EVENT_MOUSE_WHEEL: + case SDL_EVENT_MOUSE_WHEEL_OFF: case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: onKeyboardMouseInput(&event); @@ -144,6 +145,14 @@ void WindowSDL::onResize() { ImGui::Core::OnResize(); } +Uint32 wheelOffCallback(void* og_event, Uint32 timer_id, Uint32 interval) { + SDL_Event off_event = *(SDL_Event*)og_event; + off_event.type = SDL_EVENT_MOUSE_WHEEL_OFF; + SDL_PushEvent(&off_event); + delete (SDL_Event*)og_event; + return 0; +} + void WindowSDL::onKeyboardMouseInput(const SDL_Event* event) { using Libraries::Pad::OrbisPadButtonDataOffset; @@ -176,6 +185,12 @@ void WindowSDL::onKeyboardMouseInput(const SDL_Event* event) { VideoCore::TriggerCapture(); } } + + // if it's a wheel event, make a timer that turns it off after a set time + if(event->type == SDL_EVENT_MOUSE_WHEEL) { + const SDL_Event* copy = new SDL_Event(*event); + SDL_AddTimer(33, wheelOffCallback, (void*)copy); + } // add/remove it from the list Input::updatePressedKeys(input_id, input_down); From 0d87d0d7304543ee9e557fbed1a1b0f51d8acba3 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Thu, 14 Nov 2024 11:03:03 +0100 Subject: [PATCH 43/79] Wheel works now (for me), l2/r2 handling improvements, and misc bugfixes --- src/input/input_handler.cpp | 56 ++++++++++++++++--------------------- src/input/input_handler.h | 11 ++++++-- src/sdl_window.cpp | 4 +++ 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 2655c110e61..50b924cccde 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -185,14 +185,14 @@ void parseInputConfig(const std::string game_id = "") { if (before_equals == "modkey_toggle") { if (comma_pos != std::string::npos) { // handle key-to-key toggling (separate list?) - LOG_ERROR(Input, "todo"); + LOG_ERROR(Input, "todo: {}", line); continue; } LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); continue; } if (before_equals == "mouse_movement_params") { - LOG_ERROR(Input, "todo"); + LOG_ERROR(Input, "todo: {}", line); continue; } @@ -209,6 +209,7 @@ void parseInputConfig(const std::string game_id = "") { if (button_it != string_to_cbutton_map.end()) { connection = BindingConnection(binding, getOutputPointer(ControllerOutput(button_it->second))); connections.insert(connections.end(), connection); + } else if (axis_it != string_to_axis_map.end()) { connection = BindingConnection(binding, getOutputPointer(ControllerOutput(0, axis_it->second.axis)), axis_it->second.value); connections.insert(connections.end(), connection); @@ -219,11 +220,14 @@ void parseInputConfig(const std::string game_id = "") { //LOG_INFO(Input, "Succesfully parsed line {}", lineCount); } file.close(); + LOG_INFO(Input, "Done parsing the input config!"); } -Uint32 getMouseWheelEvent(const SDL_Event& event) { - if (event.type != SDL_EVENT_MOUSE_WHEEL || event.type != SDL_EVENT_MOUSE_WHEEL_OFF) +u32 getMouseWheelEvent(const SDL_Event& event) { + if (event.type != SDL_EVENT_MOUSE_WHEEL && event.type != SDL_EVENT_MOUSE_WHEEL_OFF) { + LOG_ERROR(Input, "Something went wrong with wheel input parsing!"); return 0; + } if (event.wheel.y > 0) { return SDL_MOUSE_WHEEL_UP; } else if (event.wheel.y < 0) { @@ -233,7 +237,7 @@ Uint32 getMouseWheelEvent(const SDL_Event& event) { } else if (event.wheel.x < 0) { return SDL_MOUSE_WHEEL_LEFT; } - return 0; + return (u32)-1; } u32 InputBinding::getInputIDFromEvent(const SDL_Event& e) { @@ -261,13 +265,6 @@ void ControllerOutput::update(bool pressed, int a_value) { float touchpad_x = 0; if(button != 0){ switch (button) { - // todo: check if l2 and r2 can be moved to the axis section - case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2: - case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2: - axis = (button == OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2) ? Axis::TriggerRight - : Axis::TriggerLeft; - controller->Axis(0, axis, GetAxis(0, 0x80, pressed ? 128 : 0)); - break; case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD: touchpad_x = Config::getBackButtonBehavior() == "left" ? 0.25f : Config::getBackButtonBehavior() == "right" ? 0.75f @@ -298,9 +295,11 @@ void ControllerOutput::update(bool pressed, int a_value) { break; case Axis::TriggerLeft: case Axis::TriggerRight: - // todo: verify this works - //controller->Axis(0, axis, GetAxis(0, 0x80, pressed ? 128 : 0)); - break; + // todo: verify this works (This probably works from testing, + // but needs extra info (multiple input to the same trigger?)) + axis_value = SDL_clamp((pressed ? a_value : 0) * multiplier, 0, 127); + controller->Axis(0, axis, GetAxis(0, 0x80, axis_value)); + return; default: break; } @@ -319,13 +318,6 @@ void ControllerOutput::addUpdate(bool pressed, int a_value) { return; } switch (button) { - // todo: check if l2 and r2 can be moved to the axis section - case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2: - case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2: - axis = (button == OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2) ? Axis::TriggerRight - : Axis::TriggerLeft; - controller->Axis(0, axis, GetAxis(0, 0x80, pressed ? 128 : 0)); - break; case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD: touchpad_x = Config::getBackButtonBehavior() == "left" ? 0.25f : Config::getBackButtonBehavior() == "right" ? 0.75f @@ -334,10 +326,10 @@ void ControllerOutput::addUpdate(bool pressed, int a_value) { controller->CheckButton(0, button, pressed); break; case LEFTJOYSTICK_HALFMODE: - leftjoystick_halfmode ^= pressed; // toggle if pressed, don't change otherwise + leftjoystick_halfmode = pressed; break; case RIGHTJOYSTICK_HALFMODE: - rightjoystick_halfmode ^= pressed; + rightjoystick_halfmode = pressed; break; default: // is a normal key (hopefully) controller->CheckButton(0, button, pressed); @@ -357,15 +349,15 @@ void ControllerOutput::addUpdate(bool pressed, int a_value) { case Axis::TriggerLeft: case Axis::TriggerRight: // todo: verify this works - //controller->Axis(0, axis, GetAxis(0, 0x80, pressed ? 128 : 0)); - break; + axis_value = SDL_clamp((pressed ? a_value : 0) * multiplier + axis_value, 0, 127); + controller->Axis(0, axis, GetAxis(0, 0x80, axis_value)); + return; default: break; } axis_value = SDL_clamp((pressed ? a_value : 0) * multiplier + axis_value, -127, 127); - int ax = GetAxis(-0x80, 0x80, axis_value); - controller->Axis(0, axis, ax); - LOG_INFO(Input, "Axis value delta: {} final value: {}", a_value, axis_value); + controller->Axis(0, axis, GetAxis(-0x80, 0x80, axis_value)); + //LOG_INFO(Input, "Axis value delta: {} final value: {}", (pressed ? a_value : 0), axis_value); } else { LOG_ERROR(Input, "Controller output with no values detected!"); } @@ -398,21 +390,18 @@ bool isInputActive(const InputBinding& i) { */ auto it = pressed_keys.begin(); - // Check for key1 if it's set if (i.key1 != 0) { it = std::find(it, pressed_keys.end(), i.key1); if (it == pressed_keys.end()) return false; ++it; // Move to the next element for subsequent checks } - // Check for key2 if it's set if (i.key2 != 0) { it = std::find(it, pressed_keys.end(), i.key2); if (it == pressed_keys.end()) return false; ++it; } - // Check for key3 if it's set if (i.key3 != 0) { it = std::find(it, pressed_keys.end(), i.key3); if (it == pressed_keys.end()) return false; @@ -429,6 +418,9 @@ void activateOutputsFromInputs() { if (it->output) { it->output->update(false, 0); } else { + // LOG_ERROR(Input, "Null output in BindingConnection at position {}\n data: {}: {}", + // std::distance(connections.begin(), it), + // it->binding.toString(), it->output->toString()); LOG_ERROR(Input, "Null output in BindingConnection at position {}", std::distance(connections.begin(), it)); } } diff --git a/src/input/input_handler.h b/src/input/input_handler.h index 0f3291b9638..175d2b23f12 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -10,6 +10,7 @@ #include "common/types.h" #include "common/logging/log.h" #include "core/libraries/pad/pad.h" +#include "fmt/format.h" #include "input/controller.h" #include "SDL3/SDL_events.h" @@ -43,9 +44,7 @@ const std::map string_to_cbutton_map = { {"cross", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS}, {"square", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE}, {"l1", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1}, - {"l2", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2}, {"r1", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1}, - {"r2", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2}, {"l3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3}, {"r3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3}, {"options", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS}, @@ -66,6 +65,8 @@ const std::map string_to_axis_map = { {"axis_right_x_minus", {Input::Axis::RightX, -127}}, {"axis_right_y_plus", {Input::Axis::RightY, 127}}, {"axis_right_y_minus", {Input::Axis::RightY, -127}}, + {"l2", {Axis::TriggerLeft, 127}}, + {"r2", {Axis::TriggerRight, 127}}, }; const std::map string_to_keyboard_key_map = { {"a", SDLK_A}, @@ -220,6 +221,9 @@ class InputBinding { inline bool isEmpty() { return key1 == 0 && key2 == 0 && key3 == 0; } + std::string toString() { + return fmt::format("({}, {}, {})", key1, key2, key3); + } // returns a u32 based on the event type (keyboard, mouse buttons, or wheel) static u32 getInputIDFromEvent(const SDL_Event& e); @@ -246,6 +250,9 @@ class ControllerOutput { inline bool operator!=(const ControllerOutput& o) const { return button != o.button || axis != o.axis; } + std::string toString() const { + return fmt::format("({}, {}, {})", button, (int)axis, axis_value); + } void update(bool pressed, int axis_direction = 0); // Off events are not counted void addUpdate(bool pressed, int axis_direction = 0); diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 8ff2f14f184..21f2669314f 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -167,22 +167,26 @@ void WindowSDL::onKeyboardMouseInput(const SDL_Event* event) { // Reparse kbm inputs if (input_id == SDLK_F8) { Input::parseInputConfig(std::string(Common::ElfInfo::Instance().GameSerial())); + return; } // Toggle mouse capture and movement input else if (input_id == SDLK_F7) { Input::toggleMouseEnabled(); SDL_SetWindowRelativeMouseMode(this->GetSdlWindow(), !SDL_GetWindowRelativeMouseMode(this->GetSdlWindow())); + return; } // Toggle fullscreen else if (input_id == SDLK_F11) { SDL_WindowFlags flag = SDL_GetWindowFlags(window); bool is_fullscreen = flag & SDL_WINDOW_FULLSCREEN; SDL_SetWindowFullscreen(window, !is_fullscreen); + return; } // Trigger rdoc capture else if (input_id == SDLK_F12) { VideoCore::TriggerCapture(); + return; } } From 6ad6079c56681f6796b74e40f969ea051c85e932 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:15:14 +0100 Subject: [PATCH 44/79] Downgraded prints to log_debug, and implemented input hierarchy --- src/input/input_handler.cpp | 109 +++++++++++++++++++++--------------- src/input/input_handler.h | 13 ++++- src/sdl_window.cpp | 1 - 3 files changed, 74 insertions(+), 49 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 50b924cccde..de3239b849b 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -46,7 +46,7 @@ float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.1250; Uint32 mouse_polling_id = 0; bool mouse_enabled = false, leftjoystick_halfmode = false, rightjoystick_halfmode = false; -std::list pressed_keys = std::list(); +std::list> pressed_keys; std::list connections = std::list(); void toggleMouseEnabled() { @@ -161,7 +161,7 @@ void parseInputConfig(const std::string game_id = "") { // Split the line by '=' std::size_t equal_pos = line.find('='); if (equal_pos == std::string::npos) { - LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); + LOG_DEBUG(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); continue; } @@ -185,14 +185,14 @@ void parseInputConfig(const std::string game_id = "") { if (before_equals == "modkey_toggle") { if (comma_pos != std::string::npos) { // handle key-to-key toggling (separate list?) - LOG_ERROR(Input, "todo: {}", line); + LOG_DEBUG(Input, "todo: {}", line); continue; } - LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); + LOG_DEBUG(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); continue; } if (before_equals == "mouse_movement_params") { - LOG_ERROR(Input, "todo: {}", line); + LOG_DEBUG(Input, "todo: {}", line); continue; } @@ -203,7 +203,7 @@ void parseInputConfig(const std::string game_id = "") { auto axis_it = string_to_axis_map.find(before_equals); if(binding.isEmpty()) { - LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); + LOG_DEBUG(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); continue; } if (button_it != string_to_cbutton_map.end()) { @@ -214,18 +214,19 @@ void parseInputConfig(const std::string game_id = "") { connection = BindingConnection(binding, getOutputPointer(ControllerOutput(0, axis_it->second.axis)), axis_it->second.value); connections.insert(connections.end(), connection); } else { - LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); + LOG_DEBUG(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); continue; } //LOG_INFO(Input, "Succesfully parsed line {}", lineCount); } file.close(); - LOG_INFO(Input, "Done parsing the input config!"); + connections.sort(); + LOG_DEBUG(Input, "Done parsing the input config!"); } u32 getMouseWheelEvent(const SDL_Event& event) { if (event.type != SDL_EVENT_MOUSE_WHEEL && event.type != SDL_EVENT_MOUSE_WHEEL_OFF) { - LOG_ERROR(Input, "Something went wrong with wheel input parsing!"); + LOG_DEBUG(Input, "Something went wrong with wheel input parsing!"); return 0; } if (event.wheel.y > 0) { @@ -273,10 +274,10 @@ void ControllerOutput::update(bool pressed, int a_value) { controller->CheckButton(0, button, pressed); break; case LEFTJOYSTICK_HALFMODE: - leftjoystick_halfmode ^= pressed; // toggle if pressed, don't change otherwise + leftjoystick_halfmode = pressed; break; case RIGHTJOYSTICK_HALFMODE: - rightjoystick_halfmode ^= pressed; + rightjoystick_halfmode = pressed; break; default: // is a normal key (hopefully) controller->CheckButton(0, button, pressed); @@ -307,7 +308,7 @@ void ControllerOutput::update(bool pressed, int a_value) { int ax = GetAxis(-0x80, 0x80, axis_value); controller->Axis(0, axis, ax); } else { - LOG_ERROR(Input, "Controller output with no values detected!"); + LOG_DEBUG(Input, "Controller output with no values detected!"); } } void ControllerOutput::addUpdate(bool pressed, int a_value) { @@ -359,77 +360,93 @@ void ControllerOutput::addUpdate(bool pressed, int a_value) { controller->Axis(0, axis, GetAxis(-0x80, 0x80, axis_value)); //LOG_INFO(Input, "Axis value delta: {} final value: {}", (pressed ? a_value : 0), axis_value); } else { - LOG_ERROR(Input, "Controller output with no values detected!"); + LOG_DEBUG(Input, "Controller output with no values detected!"); } } void updatePressedKeys(u32 value, bool is_pressed) { if (is_pressed) { // Find the correct position for insertion to maintain order - auto it = std::lower_bound(pressed_keys.begin(), pressed_keys.end(), value); - + auto it = std::lower_bound(pressed_keys.begin(), pressed_keys.end(), value, + [](const std::pair& pk, u32 v) { return pk.first < v; }); + // Insert only if 'value' is not already in the list - if (it == pressed_keys.end() || *it != value) { - pressed_keys.insert(it, value); + if (it == pressed_keys.end() || it->first != value) { + pressed_keys.insert(it, {value, false}); } } else { // Remove 'value' from the list if it's not pressed - pressed_keys.remove(value); + auto it = std::find_if(pressed_keys.begin(), pressed_keys.end(), + [value](const std::pair& pk) { return pk.first == value; }); + if (it != pressed_keys.end()) { + pressed_keys.erase(it); // Remove the key entirely from the list + } } } // Check if a given binding's all keys are currently active. bool isInputActive(const InputBinding& i) { - /* how to check if a binding is currently held down: - iterate until connection.InputBinding.key3 is found or we reach the end - iterate from that point until connection.InputBinding.key2 is found or we reach the end - iterate from that point until connection.InputBinding.key1 is found or we reach the end - if we ever reach the end, return false - if the next key to find would be 0, return true - if all three are found return true - */ - auto it = pressed_keys.begin(); - - if (i.key1 != 0) { - it = std::find(it, pressed_keys.end(), i.key1); - if (it == pressed_keys.end()) return false; - ++it; // Move to the next element for subsequent checks + bool* flag1 = nullptr; + bool* flag2 = nullptr; + bool* flag3 = nullptr; + + // First pass: locate each key and save pointers to their flags if found + for (auto& entry : pressed_keys) { + u32 key = entry.first; + bool& is_active = entry.second; + + if (i.key1 != 0 && key == i.key1 && !flag1) { + flag1 = &is_active; + } else if (i.key2 != 0 && key == i.key2 && !flag2) { + flag2 = &is_active; + } else if (i.key3 != 0 && key == i.key3 && !flag3) { + flag3 = &is_active; + break; + } else { + return false; // an all 0 input never gets activated + } } - if (i.key2 != 0) { - it = std::find(it, pressed_keys.end(), i.key2); - if (it == pressed_keys.end()) return false; - ++it; + // If any required key was not found, return false without updating flags + if ((i.key1 != 0 && !flag1) || (i.key2 != 0 && !flag2) || (i.key3 != 0 && !flag3)) { + return false; } - if (i.key3 != 0) { - it = std::find(it, pressed_keys.end(), i.key3); - if (it == pressed_keys.end()) return false; + // Check if all flags are already true, which indicates this input is overridden (only if the key is not 0) + if ((i.key1 == 0 || (flag1 && *flag1)) && + (i.key2 == 0 || (flag2 && *flag2)) && + (i.key3 == 0 || (flag3 && *flag3))) { + return false; // This input is overridden by another input } - // All required keys were found in order - LOG_INFO(Input, "A valid held input is found!"); + // Set flags to true only after confirming all keys are present and not overridden + if (flag1) *flag1 = true; + if (flag2) *flag2 = true; + if (flag3) *flag3 = true; + + LOG_DEBUG(Input, "A valid held input is found: {}, flag ptrs: {} {} {}", i.toString(), fmt::ptr(flag1), fmt::ptr(flag2), fmt::ptr(flag3)); return true; } void activateOutputsFromInputs() { + LOG_DEBUG(Input, "Starting input scan..."); // reset everything for(auto it = connections.begin(); it != connections.end(); it++) { if (it->output) { it->output->update(false, 0); } else { - // LOG_ERROR(Input, "Null output in BindingConnection at position {}\n data: {}: {}", - // std::distance(connections.begin(), it), - // it->binding.toString(), it->output->toString()); - LOG_ERROR(Input, "Null output in BindingConnection at position {}", std::distance(connections.begin(), it)); + LOG_DEBUG(Input, "Null output in BindingConnection at position {}", std::distance(connections.begin(), it)); } } + for (auto it : pressed_keys) { + it.second = false; + } // iterates over the connections, and updates them depending on whether the corresponding input trio is found for(auto it = connections.begin(); it != connections.end(); it++) { if (it->output) { it->output->addUpdate(isInputActive(it->binding), it->axis_value); } else { - //LOG_ERROR(Input, "Null output in BindingConnection at position {}", std::distance(connections.begin(), it)); + //LOG_DEBUG(Input, "Null output in BindingConnection at position {}", std::distance(connections.begin(), it)); } } } diff --git a/src/input/input_handler.h b/src/input/input_handler.h index 175d2b23f12..7001b715251 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -218,10 +218,17 @@ class InputBinding { // but reverse order makes it check the actual keys first instead of possible 0-s, // potenially skipping the later expressions of the three-way AND } + inline int keyCount() const { + return (key1 ? 1 : 0) + (key2 ? 1 : 0) + (key3 ? 1 : 0); + } + // Sorts by the amount of non zero keys - left side is 'bigger' here + bool operator<(const InputBinding& other) const { + return keyCount() > other.keyCount(); + } inline bool isEmpty() { return key1 == 0 && key2 == 0 && key3 == 0; } - std::string toString() { + std::string toString() const { return fmt::format("({}, {}, {})", key1, key2, key3); } @@ -269,7 +276,9 @@ class BindingConnection { // todo: check if out is in the allowed array output = out; } - + bool operator<(const BindingConnection& other) { + return binding < other.binding; + } }; // Check if the 3 key input is currently active. diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 21f2669314f..62c2029343d 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -136,7 +136,6 @@ void WindowSDL::waitEvent() { void WindowSDL::initTimers() { SDL_AddTimer(100, &PollController, controller); - // todo: add back mouse polling here SDL_AddTimer(33, Input::mousePolling, (void*)controller); } From 09b945ce8bbcd3d98b2aa5cfe23f0b2e0f13f9a7 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Thu, 14 Nov 2024 14:21:05 +0100 Subject: [PATCH 45/79] Implemented key toggle --- src/input/input_handler.cpp | 99 +++++++++++++++++++++++++------------ src/input/input_handler.h | 12 +++-- 2 files changed, 75 insertions(+), 36 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index de3239b849b..6a54d233cd7 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -47,11 +47,10 @@ Uint32 mouse_polling_id = 0; bool mouse_enabled = false, leftjoystick_halfmode = false, rightjoystick_halfmode = false; std::list> pressed_keys; +std::list toggled_keys; std::list connections = std::list(); -void toggleMouseEnabled() { - mouse_enabled ^= true; -} + ControllerOutput output_array[] = { // Button mappings ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE), @@ -81,11 +80,16 @@ ControllerOutput output_array[] = { ControllerOutput(LEFTJOYSTICK_HALFMODE), ControllerOutput(RIGHTJOYSTICK_HALFMODE), + ControllerOutput(KEY_TOGGLE), // End marker to signify the end of the array ControllerOutput(0, Input::Axis::AxisMax) }; +// We had to go through 3 files of indirection just to update a flag +void toggleMouseEnabled() { + mouse_enabled ^= true; +} // parsing related functions // syntax: 'name, name,name' or 'name,name' or 'name' @@ -161,46 +165,54 @@ void parseInputConfig(const std::string game_id = "") { // Split the line by '=' std::size_t equal_pos = line.find('='); if (equal_pos == std::string::npos) { - LOG_DEBUG(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); + LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); continue; } - std::string before_equals = line.substr(0, equal_pos); - std::string after_equals = line.substr(equal_pos + 1); - std::size_t comma_pos = after_equals.find(','); + std::string output_string = line.substr(0, equal_pos); + std::string input_string = line.substr(equal_pos + 1); + std::size_t comma_pos = input_string.find(','); // special check for mouse to joystick input - if (before_equals == "mouse_to_joystick") { - if (after_equals == "left") { + if (output_string == "mouse_to_joystick") { + if (input_string == "left") { mouse_joystick_binding = 1; - } else if (after_equals == "right") { + } else if (input_string == "right") { mouse_joystick_binding = 2; } else { mouse_joystick_binding = 0; // default to 'none' or invalid } continue; } - // mod key toggle - if (before_equals == "modkey_toggle") { + // key toggle + if (output_string == "key_toggle") { if (comma_pos != std::string::npos) { // handle key-to-key toggling (separate list?) - LOG_DEBUG(Input, "todo: {}", line); + InputBinding toggle_keys = getBindingFromString(input_string); + if(toggle_keys.keyCount() != 2) { + LOG_ERROR(Input, "Syntax error: Please provide exactly 2 keys: " + "first is the toggler, the second is the key to toggle: {}", line); + continue; + } + ControllerOutput* toggle_out = getOutputPointer(ControllerOutput(KEY_TOGGLE)); + BindingConnection toggle_connection = BindingConnection(InputBinding(toggle_keys.key2), toggle_out, toggle_keys.key3); + connections.insert(connections.end(), toggle_connection); continue; } - LOG_DEBUG(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); + LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); continue; } - if (before_equals == "mouse_movement_params") { + if (output_string == "mouse_movement_params") { LOG_DEBUG(Input, "todo: {}", line); continue; } // normal cases - InputBinding binding = getBindingFromString(after_equals); + InputBinding binding = getBindingFromString(input_string); BindingConnection connection(0, nullptr); - auto button_it = string_to_cbutton_map.find(before_equals); - auto axis_it = string_to_axis_map.find(before_equals); + auto button_it = string_to_cbutton_map.find(output_string); + auto axis_it = string_to_axis_map.find(output_string); if(binding.isEmpty()) { LOG_DEBUG(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); @@ -262,7 +274,18 @@ void ControllerOutput::setControllerOutputController(GameController* c) { ControllerOutput::controller = c; } -void ControllerOutput::update(bool pressed, int a_value) { +void toggleKeyInList(u32 key) { + auto it = std::find(toggled_keys.begin(), toggled_keys.end(), key); + if(it == toggled_keys.end()) { + toggled_keys.insert(toggled_keys.end(), key); + LOG_DEBUG(Input, "Added {} to toggled keys", key); + } else { + toggled_keys.erase(it); + LOG_DEBUG(Input, "Removed {} from toggled keys", key); + } +} + +void ControllerOutput::update(bool pressed, u32 param) { float touchpad_x = 0; if(button != 0){ switch (button) { @@ -279,6 +302,11 @@ void ControllerOutput::update(bool pressed, int a_value) { case RIGHTJOYSTICK_HALFMODE: rightjoystick_halfmode = pressed; break; + case KEY_TOGGLE: + if(pressed) { + toggleKeyInList(param); + } + break; default: // is a normal key (hopefully) controller->CheckButton(0, button, pressed); break; @@ -298,20 +326,20 @@ void ControllerOutput::update(bool pressed, int a_value) { case Axis::TriggerRight: // todo: verify this works (This probably works from testing, // but needs extra info (multiple input to the same trigger?)) - axis_value = SDL_clamp((pressed ? a_value : 0) * multiplier, 0, 127); + axis_value = SDL_clamp((pressed ? (int)param : 0) * multiplier, 0, 127); controller->Axis(0, axis, GetAxis(0, 0x80, axis_value)); return; default: break; } - axis_value = SDL_clamp((pressed ? a_value : 0) * multiplier, -127, 127); + axis_value = SDL_clamp((pressed ? (int)param : 0) * multiplier, -127, 127); int ax = GetAxis(-0x80, 0x80, axis_value); controller->Axis(0, axis, ax); } else { LOG_DEBUG(Input, "Controller output with no values detected!"); } } -void ControllerOutput::addUpdate(bool pressed, int a_value) { +void ControllerOutput::addUpdate(bool pressed, u32 param) { float touchpad_x = 0; if(button != 0){ @@ -332,6 +360,11 @@ void ControllerOutput::addUpdate(bool pressed, int a_value) { case RIGHTJOYSTICK_HALFMODE: rightjoystick_halfmode = pressed; break; + case KEY_TOGGLE: + if(pressed) { + toggleKeyInList(param); + } + break; default: // is a normal key (hopefully) controller->CheckButton(0, button, pressed); break; @@ -350,13 +383,13 @@ void ControllerOutput::addUpdate(bool pressed, int a_value) { case Axis::TriggerLeft: case Axis::TriggerRight: // todo: verify this works - axis_value = SDL_clamp((pressed ? a_value : 0) * multiplier + axis_value, 0, 127); + axis_value = SDL_clamp((pressed ? (int)param : 0) * multiplier + axis_value, 0, 127); controller->Axis(0, axis, GetAxis(0, 0x80, axis_value)); return; default: break; } - axis_value = SDL_clamp((pressed ? a_value : 0) * multiplier + axis_value, -127, 127); + axis_value = SDL_clamp((pressed ? (int)param : 0) * multiplier + axis_value, -127, 127); controller->Axis(0, axis, GetAxis(-0x80, 0x80, axis_value)); //LOG_INFO(Input, "Axis value delta: {} final value: {}", (pressed ? a_value : 0), axis_value); } else { @@ -390,16 +423,20 @@ bool isInputActive(const InputBinding& i) { bool* flag2 = nullptr; bool* flag3 = nullptr; + bool key1_pressed = std::find(toggled_keys.begin(), toggled_keys.end(), i.key1) != toggled_keys.end(); + bool key2_pressed = std::find(toggled_keys.begin(), toggled_keys.end(), i.key2) != toggled_keys.end(); + bool key3_pressed = std::find(toggled_keys.begin(), toggled_keys.end(), i.key3) != toggled_keys.end(); + // First pass: locate each key and save pointers to their flags if found for (auto& entry : pressed_keys) { u32 key = entry.first; bool& is_active = entry.second; - if (i.key1 != 0 && key == i.key1 && !flag1) { + if (key1_pressed || (i.key1 != 0 && key == i.key1 && !flag1)) { flag1 = &is_active; - } else if (i.key2 != 0 && key == i.key2 && !flag2) { + } else if (key2_pressed || (i.key2 != 0 && key == i.key2 && !flag2)) { flag2 = &is_active; - } else if (i.key3 != 0 && key == i.key3 && !flag3) { + } else if (key3_pressed || (i.key3 != 0 && key == i.key3 && !flag3)) { flag3 = &is_active; break; } else { @@ -420,9 +457,9 @@ bool isInputActive(const InputBinding& i) { } // Set flags to true only after confirming all keys are present and not overridden - if (flag1) *flag1 = true; - if (flag2) *flag2 = true; - if (flag3) *flag3 = true; + if (flag1 && !key1_pressed) *flag1 = true; + if (flag2 && !key2_pressed) *flag2 = true; + if (flag3 && !key3_pressed) *flag3 = true; LOG_DEBUG(Input, "A valid held input is found: {}, flag ptrs: {} {} {}", i.toString(), fmt::ptr(flag1), fmt::ptr(flag2), fmt::ptr(flag3)); return true; @@ -444,7 +481,7 @@ void activateOutputsFromInputs() { // iterates over the connections, and updates them depending on whether the corresponding input trio is found for(auto it = connections.begin(); it != connections.end(); it++) { if (it->output) { - it->output->addUpdate(isInputActive(it->binding), it->axis_value); + it->output->addUpdate(isInputActive(it->binding), it->parameter); } else { //LOG_DEBUG(Input, "Null output in BindingConnection at position {}", std::distance(connections.begin(), it)); } diff --git a/src/input/input_handler.h b/src/input/input_handler.h index 7001b715251..09929d3580b 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -28,6 +28,8 @@ #define LEFTJOYSTICK_HALFMODE 0x00010000 #define RIGHTJOYSTICK_HALFMODE 0x00020000 +#define KEY_TOGGLE 0x00200000 + namespace Input { using Input::Axis; using Libraries::Pad::OrbisPadButtonDataOffset; @@ -260,18 +262,18 @@ class ControllerOutput { std::string toString() const { return fmt::format("({}, {}, {})", button, (int)axis, axis_value); } - void update(bool pressed, int axis_direction = 0); + void update(bool pressed, u32 param = 0); // Off events are not counted - void addUpdate(bool pressed, int axis_direction = 0); + void addUpdate(bool pressed, u32 param = 0); }; class BindingConnection { public: InputBinding binding; ControllerOutput* output; - int axis_value; - BindingConnection(InputBinding b, ControllerOutput* out, int a_v = 0) { + u32 parameter; + BindingConnection(InputBinding b, ControllerOutput* out, u32 param = 0) { binding = b; - axis_value = a_v; // bruh this accidentally set to be 0 no wonder it didn't do anything + parameter = param; // bruh this accidentally set to be 0 no wonder it didn't do anything // todo: check if out is in the allowed array output = out; From 1a8f177526a12607d8933150ddb6b29d5e2912fc Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Thu, 14 Nov 2024 14:42:52 +0100 Subject: [PATCH 46/79] Added mouse parameter parsing --- src/input/input_handler.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 6a54d233cd7..77bd1c34cdd 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -204,7 +204,19 @@ void parseInputConfig(const std::string game_id = "") { continue; } if (output_string == "mouse_movement_params") { - LOG_DEBUG(Input, "todo: {}", line); + std::stringstream ss(input_string); + char comma; // To hold the comma separators between the floats + ss >> mouse_deadzone_offset >> comma + >> mouse_speed >> comma + >> mouse_speed_offset; + + // Check for invalid input (in case there's an unexpected format) + if (ss.fail()) { + LOG_ERROR(Input, "Failed to parse mouse movement parameters from line: {}", line); + } else { + //LOG_DEBUG(Input, "Mouse movement parameters parsed: {} {} {}", mouse_deadzone_offset, mouse_speed, mouse_speed_offset); + } + continue; } From 9c81f8e2f28305178782ab5b4b5aa892e2bfebb1 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Thu, 14 Nov 2024 14:44:34 +0100 Subject: [PATCH 47/79] clang-format --- src/input/input_handler.cpp | 188 ++++++++++++++++++++---------------- src/input/input_handler.h | 65 ++++++++----- src/sdl_window.cpp | 7 +- src/sdl_window.h | 2 +- 4 files changed, 148 insertions(+), 114 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 77bd1c34cdd..556ce3e97cb 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -5,38 +5,38 @@ #include "fstream" #include "iostream" -#include "map" -#include "unordered_map" #include "list" +#include "map" #include "sstream" #include "string" +#include "unordered_map" #include "vector" #include "SDL3/SDL_events.h" #include "SDL3/SDL_timer.h" #include "common/config.h" +#include "common/elf_info.h" #include "common/io_file.h" #include "common/path_util.h" #include "common/version.h" -#include "common/elf_info.h" #include "input/controller.h" namespace Input { /* Project structure: n to m connection between inputs and outputs -Keyup and keydown events update a dynamic list* of u32 'flags' (what is currently in the list is 'pressed') -On every event, after flag updates, we check for every input binding -> controller output pair if all their flags are 'on' -If not, disable; if so, enable them. -For axes, we gather their data into a struct cumulatively from all inputs, - then after we checked all of those, we update them all at once. -Wheel inputs generate a timer that doesn't turn off their outputs automatically, but push a userevent to do so. +Keyup and keydown events update a dynamic list* of u32 'flags' (what is currently in the list is +'pressed') On every event, after flag updates, we check for every input binding -> controller output +pair if all their flags are 'on' If not, disable; if so, enable them. For axes, we gather their data +into a struct cumulatively from all inputs, then after we checked all of those, we update them all +at once. Wheel inputs generate a timer that doesn't turn off their outputs automatically, but push a +userevent to do so. What structs are needed? InputBinding(key1, key2, key3) -ControllerOutput(button, axis) - we only need a const array of these, and one of the attr-s is always 0 -BindingConnection(inputBinding (member), controllerOutput (ref to the array element)) +ControllerOutput(button, axis) - we only need a const array of these, and one of the attr-s is +always 0 BindingConnection(inputBinding (member), controllerOutput (ref to the array element)) */ // Flags and values for varying purposes @@ -50,7 +50,6 @@ std::list> pressed_keys; std::list toggled_keys; std::list connections = std::list(); - ControllerOutput output_array[] = { // Button mappings ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE), @@ -71,20 +70,15 @@ ControllerOutput output_array[] = { ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT), // Axis mappings - ControllerOutput(0, Input::Axis::LeftX), - ControllerOutput(0, Input::Axis::LeftY), - ControllerOutput(0, Input::Axis::RightX), - ControllerOutput(0, Input::Axis::RightY), - ControllerOutput(0, Input::Axis::TriggerLeft), - ControllerOutput(0, Input::Axis::TriggerRight), - - ControllerOutput(LEFTJOYSTICK_HALFMODE), - ControllerOutput(RIGHTJOYSTICK_HALFMODE), + ControllerOutput(0, Input::Axis::LeftX), ControllerOutput(0, Input::Axis::LeftY), + ControllerOutput(0, Input::Axis::RightX), ControllerOutput(0, Input::Axis::RightY), + ControllerOutput(0, Input::Axis::TriggerLeft), ControllerOutput(0, Input::Axis::TriggerRight), + + ControllerOutput(LEFTJOYSTICK_HALFMODE), ControllerOutput(RIGHTJOYSTICK_HALFMODE), ControllerOutput(KEY_TOGGLE), // End marker to signify the end of the array - ControllerOutput(0, Input::Axis::AxisMax) -}; + ControllerOutput(0, Input::Axis::AxisMax)}; // We had to go through 3 files of indirection just to update a flag void toggleMouseEnabled() { @@ -113,9 +107,12 @@ InputBinding getBindingFromString(std::string& line) { } // Assign values to keys if all tokens were valid - if (tokens.size() > 0) key1 = string_to_keyboard_key_map.at(tokens[0]); - if (tokens.size() > 1) key2 = string_to_keyboard_key_map.at(tokens[1]); - if (tokens.size() > 2) key3 = string_to_keyboard_key_map.at(tokens[2]); + if (tokens.size() > 0) + key1 = string_to_keyboard_key_map.at(tokens[0]); + if (tokens.size() > 1) + key2 = string_to_keyboard_key_map.at(tokens[1]); + if (tokens.size() > 2) + key3 = string_to_keyboard_key_map.at(tokens[2]); return InputBinding(key1, key2, key3); } @@ -124,7 +121,7 @@ InputBinding getBindingFromString(std::string& line) { ControllerOutput* getOutputPointer(const ControllerOutput& parsed) { // i wonder how long until someone notices this or I get rid of it for (int i = 0; i[output_array] != ControllerOutput(0, Axis::AxisMax); i++) { - if(i[output_array] == parsed) { + if (i[output_array] == parsed) { return &output_array[i]; } } @@ -132,11 +129,11 @@ ControllerOutput* getOutputPointer(const ControllerOutput& parsed) { } void parseInputConfig(const std::string game_id = "") { - + const auto config_file = Config::getFoolproofKbmConfigFile(game_id); // todo: change usages of this to getFoolproofKbmConfigFile (in the gui) - if(game_id == "") { + if (game_id == "") { return; } @@ -165,14 +162,14 @@ void parseInputConfig(const std::string game_id = "") { // Split the line by '=' std::size_t equal_pos = line.find('='); if (equal_pos == std::string::npos) { - LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); + LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, + line); continue; } std::string output_string = line.substr(0, equal_pos); std::string input_string = line.substr(equal_pos + 1); std::size_t comma_pos = input_string.find(','); - // special check for mouse to joystick input if (output_string == "mouse_to_joystick") { @@ -190,31 +187,34 @@ void parseInputConfig(const std::string game_id = "") { if (comma_pos != std::string::npos) { // handle key-to-key toggling (separate list?) InputBinding toggle_keys = getBindingFromString(input_string); - if(toggle_keys.keyCount() != 2) { - LOG_ERROR(Input, "Syntax error: Please provide exactly 2 keys: " - "first is the toggler, the second is the key to toggle: {}", line); + if (toggle_keys.keyCount() != 2) { + LOG_ERROR(Input, + "Syntax error: Please provide exactly 2 keys: " + "first is the toggler, the second is the key to toggle: {}", + line); continue; } ControllerOutput* toggle_out = getOutputPointer(ControllerOutput(KEY_TOGGLE)); - BindingConnection toggle_connection = BindingConnection(InputBinding(toggle_keys.key2), toggle_out, toggle_keys.key3); + BindingConnection toggle_connection = + BindingConnection(InputBinding(toggle_keys.key2), toggle_out, toggle_keys.key3); connections.insert(connections.end(), toggle_connection); continue; } - LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); + LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, + line); continue; } if (output_string == "mouse_movement_params") { std::stringstream ss(input_string); - char comma; // To hold the comma separators between the floats - ss >> mouse_deadzone_offset >> comma - >> mouse_speed >> comma - >> mouse_speed_offset; + char comma; // To hold the comma separators between the floats + ss >> mouse_deadzone_offset >> comma >> mouse_speed >> comma >> mouse_speed_offset; // Check for invalid input (in case there's an unexpected format) if (ss.fail()) { LOG_ERROR(Input, "Failed to parse mouse movement parameters from line: {}", line); } else { - //LOG_DEBUG(Input, "Mouse movement parameters parsed: {} {} {}", mouse_deadzone_offset, mouse_speed, mouse_speed_offset); + // LOG_DEBUG(Input, "Mouse movement parameters parsed: {} {} {}", + // mouse_deadzone_offset, mouse_speed, mouse_speed_offset); } continue; @@ -226,22 +226,27 @@ void parseInputConfig(const std::string game_id = "") { auto button_it = string_to_cbutton_map.find(output_string); auto axis_it = string_to_axis_map.find(output_string); - if(binding.isEmpty()) { - LOG_DEBUG(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); + if (binding.isEmpty()) { + LOG_DEBUG(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, + line); continue; } if (button_it != string_to_cbutton_map.end()) { - connection = BindingConnection(binding, getOutputPointer(ControllerOutput(button_it->second))); + connection = + BindingConnection(binding, getOutputPointer(ControllerOutput(button_it->second))); connections.insert(connections.end(), connection); } else if (axis_it != string_to_axis_map.end()) { - connection = BindingConnection(binding, getOutputPointer(ControllerOutput(0, axis_it->second.axis)), axis_it->second.value); + connection = BindingConnection( + binding, getOutputPointer(ControllerOutput(0, axis_it->second.axis)), + axis_it->second.value); connections.insert(connections.end(), connection); } else { - LOG_DEBUG(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); + LOG_DEBUG(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, + line); continue; } - //LOG_INFO(Input, "Succesfully parsed line {}", lineCount); + // LOG_INFO(Input, "Succesfully parsed line {}", lineCount); } file.close(); connections.sort(); @@ -266,7 +271,7 @@ u32 getMouseWheelEvent(const SDL_Event& event) { } u32 InputBinding::getInputIDFromEvent(const SDL_Event& e) { - switch(e.type) { + switch (e.type) { case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: return e.key.key; @@ -288,7 +293,7 @@ void ControllerOutput::setControllerOutputController(GameController* c) { void toggleKeyInList(u32 key) { auto it = std::find(toggled_keys.begin(), toggled_keys.end(), key); - if(it == toggled_keys.end()) { + if (it == toggled_keys.end()) { toggled_keys.insert(toggled_keys.end(), key); LOG_DEBUG(Input, "Added {} to toggled keys", key); } else { @@ -299,12 +304,12 @@ void toggleKeyInList(u32 key) { void ControllerOutput::update(bool pressed, u32 param) { float touchpad_x = 0; - if(button != 0){ + if (button != 0) { switch (button) { case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD: touchpad_x = Config::getBackButtonBehavior() == "left" ? 0.25f - : Config::getBackButtonBehavior() == "right" ? 0.75f - : 0.5f; + : Config::getBackButtonBehavior() == "right" ? 0.75f + : 0.5f; controller->SetTouchpadState(0, true, touchpad_x, 0.5f); controller->CheckButton(0, button, pressed); break; @@ -315,7 +320,7 @@ void ControllerOutput::update(bool pressed, u32 param) { rightjoystick_halfmode = pressed; break; case KEY_TOGGLE: - if(pressed) { + if (pressed) { toggleKeyInList(param); } break; @@ -336,7 +341,7 @@ void ControllerOutput::update(bool pressed, u32 param) { break; case Axis::TriggerLeft: case Axis::TriggerRight: - // todo: verify this works (This probably works from testing, + // todo: verify this works (This probably works from testing, // but needs extra info (multiple input to the same trigger?)) axis_value = SDL_clamp((pressed ? (int)param : 0) * multiplier, 0, 127); controller->Axis(0, axis, GetAxis(0, 0x80, axis_value)); @@ -352,17 +357,17 @@ void ControllerOutput::update(bool pressed, u32 param) { } } void ControllerOutput::addUpdate(bool pressed, u32 param) { - + float touchpad_x = 0; - if(button != 0){ - if(!pressed) { + if (button != 0) { + if (!pressed) { return; } switch (button) { case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD: touchpad_x = Config::getBackButtonBehavior() == "left" ? 0.25f - : Config::getBackButtonBehavior() == "right" ? 0.75f - : 0.5f; + : Config::getBackButtonBehavior() == "right" ? 0.75f + : 0.5f; controller->SetTouchpadState(0, true, touchpad_x, 0.5f); controller->CheckButton(0, button, pressed); break; @@ -373,7 +378,7 @@ void ControllerOutput::addUpdate(bool pressed, u32 param) { rightjoystick_halfmode = pressed; break; case KEY_TOGGLE: - if(pressed) { + if (pressed) { toggleKeyInList(param); } break; @@ -403,7 +408,8 @@ void ControllerOutput::addUpdate(bool pressed, u32 param) { } axis_value = SDL_clamp((pressed ? (int)param : 0) * multiplier + axis_value, -127, 127); controller->Axis(0, axis, GetAxis(-0x80, 0x80, axis_value)); - //LOG_INFO(Input, "Axis value delta: {} final value: {}", (pressed ? a_value : 0), axis_value); + // LOG_INFO(Input, "Axis value delta: {} final value: {}", (pressed ? a_value : 0), + // axis_value); } else { LOG_DEBUG(Input, "Controller output with no values detected!"); } @@ -412,19 +418,21 @@ void ControllerOutput::addUpdate(bool pressed, u32 param) { void updatePressedKeys(u32 value, bool is_pressed) { if (is_pressed) { // Find the correct position for insertion to maintain order - auto it = std::lower_bound(pressed_keys.begin(), pressed_keys.end(), value, - [](const std::pair& pk, u32 v) { return pk.first < v; }); + auto it = + std::lower_bound(pressed_keys.begin(), pressed_keys.end(), value, + [](const std::pair& pk, u32 v) { return pk.first < v; }); // Insert only if 'value' is not already in the list if (it == pressed_keys.end() || it->first != value) { - pressed_keys.insert(it, {value, false}); + pressed_keys.insert(it, {value, false}); } } else { // Remove 'value' from the list if it's not pressed - auto it = std::find_if(pressed_keys.begin(), pressed_keys.end(), - [value](const std::pair& pk) { return pk.first == value; }); + auto it = + std::find_if(pressed_keys.begin(), pressed_keys.end(), + [value](const std::pair& pk) { return pk.first == value; }); if (it != pressed_keys.end()) { - pressed_keys.erase(it); // Remove the key entirely from the list + pressed_keys.erase(it); // Remove the key entirely from the list } } } @@ -435,9 +443,12 @@ bool isInputActive(const InputBinding& i) { bool* flag2 = nullptr; bool* flag3 = nullptr; - bool key1_pressed = std::find(toggled_keys.begin(), toggled_keys.end(), i.key1) != toggled_keys.end(); - bool key2_pressed = std::find(toggled_keys.begin(), toggled_keys.end(), i.key2) != toggled_keys.end(); - bool key3_pressed = std::find(toggled_keys.begin(), toggled_keys.end(), i.key3) != toggled_keys.end(); + bool key1_pressed = + std::find(toggled_keys.begin(), toggled_keys.end(), i.key1) != toggled_keys.end(); + bool key2_pressed = + std::find(toggled_keys.begin(), toggled_keys.end(), i.key2) != toggled_keys.end(); + bool key3_pressed = + std::find(toggled_keys.begin(), toggled_keys.end(), i.key3) != toggled_keys.end(); // First pass: locate each key and save pointers to their flags if found for (auto& entry : pressed_keys) { @@ -461,41 +472,48 @@ bool isInputActive(const InputBinding& i) { return false; } - // Check if all flags are already true, which indicates this input is overridden (only if the key is not 0) - if ((i.key1 == 0 || (flag1 && *flag1)) && - (i.key2 == 0 || (flag2 && *flag2)) && + // Check if all flags are already true, which indicates this input is overridden (only if the + // key is not 0) + if ((i.key1 == 0 || (flag1 && *flag1)) && (i.key2 == 0 || (flag2 && *flag2)) && (i.key3 == 0 || (flag3 && *flag3))) { - return false; // This input is overridden by another input + return false; // This input is overridden by another input } // Set flags to true only after confirming all keys are present and not overridden - if (flag1 && !key1_pressed) *flag1 = true; - if (flag2 && !key2_pressed) *flag2 = true; - if (flag3 && !key3_pressed) *flag3 = true; - - LOG_DEBUG(Input, "A valid held input is found: {}, flag ptrs: {} {} {}", i.toString(), fmt::ptr(flag1), fmt::ptr(flag2), fmt::ptr(flag3)); + if (flag1 && !key1_pressed) + *flag1 = true; + if (flag2 && !key2_pressed) + *flag2 = true; + if (flag3 && !key3_pressed) + *flag3 = true; + + LOG_DEBUG(Input, "A valid held input is found: {}, flag ptrs: {} {} {}", i.toString(), + fmt::ptr(flag1), fmt::ptr(flag2), fmt::ptr(flag3)); return true; } void activateOutputsFromInputs() { LOG_DEBUG(Input, "Starting input scan..."); // reset everything - for(auto it = connections.begin(); it != connections.end(); it++) { + for (auto it = connections.begin(); it != connections.end(); it++) { if (it->output) { it->output->update(false, 0); } else { - LOG_DEBUG(Input, "Null output in BindingConnection at position {}", std::distance(connections.begin(), it)); + LOG_DEBUG(Input, "Null output in BindingConnection at position {}", + std::distance(connections.begin(), it)); } } for (auto it : pressed_keys) { it.second = false; } - // iterates over the connections, and updates them depending on whether the corresponding input trio is found - for(auto it = connections.begin(); it != connections.end(); it++) { + // iterates over the connections, and updates them depending on whether the corresponding input + // trio is found + for (auto it = connections.begin(); it != connections.end(); it++) { if (it->output) { it->output->addUpdate(isInputActive(it->binding), it->parameter); } else { - //LOG_DEBUG(Input, "Null output in BindingConnection at position {}", std::distance(connections.begin(), it)); + // LOG_DEBUG(Input, "Null output in BindingConnection at position {}", + // std::distance(connections.begin(), it)); } } } @@ -543,4 +561,4 @@ Uint32 mousePolling(void* param, Uint32 id, Uint32 interval) { return interval; } -} \ No newline at end of file +} // namespace Input \ No newline at end of file diff --git a/src/input/input_handler.h b/src/input/input_handler.h index 09929d3580b..cd752e9675e 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -4,14 +4,14 @@ #pragma once #include "array" -#include "map" -#include "unordered_set" -#include "string" -#include "common/types.h" #include "common/logging/log.h" +#include "common/types.h" #include "core/libraries/pad/pad.h" #include "fmt/format.h" #include "input/controller.h" +#include "map" +#include "string" +#include "unordered_set" #include "SDL3/SDL_events.h" #include "SDL3/SDL_timer.h" @@ -23,7 +23,7 @@ #define SDL_MOUSE_WHEEL_RIGHT SDL_EVENT_MOUSE_WHEEL + 7 // idk who already used what where so I just chose a big number -#define SDL_EVENT_MOUSE_WHEEL_OFF SDL_EVENT_USER + 10 +#define SDL_EVENT_MOUSE_WHEEL_OFF SDL_EVENT_USER + 10 #define LEFTJOYSTICK_HALFMODE 0x00010000 #define RIGHTJOYSTICK_HALFMODE 0x00020000 @@ -186,37 +186,58 @@ class InputBinding { public: u32 key1, key2, key3; InputBinding(u32 k1 = SDLK_UNKNOWN, u32 k2 = SDLK_UNKNOWN, u32 k3 = SDLK_UNKNOWN) { - // we format the keys so comparing them will be very fast, because we will only have to compare 3 sorted elements, - // where the only possible duplicate item is 0 + // we format the keys so comparing them will be very fast, because we will only have to + // compare 3 sorted elements, where the only possible duplicate item is 0 // duplicate entries get changed to one original, one null - if(k1 == k2 && k1 != SDLK_UNKNOWN) { k2 = 0; } - if(k1 == k3 && k1 != SDLK_UNKNOWN) { k3 = 0; } - if(k3 == k2 && k2 != SDLK_UNKNOWN) { k2 = 0; } + if (k1 == k2 && k1 != SDLK_UNKNOWN) { + k2 = 0; + } + if (k1 == k3 && k1 != SDLK_UNKNOWN) { + k3 = 0; + } + if (k3 == k2 && k2 != SDLK_UNKNOWN) { + k2 = 0; + } // this sorts them if (k1 <= k2 && k1 <= k3) { key1 = k1; - if (k2 <= k3) { key2 = k2; key3 = k3; } - else { key2 = k3; key3 = k2; } + if (k2 <= k3) { + key2 = k2; + key3 = k3; + } else { + key2 = k3; + key3 = k2; + } } else if (k2 <= k1 && k2 <= k3) { key1 = k2; - if (k1 <= k3) { key2 = k1; key3 = k3; } - else { key2 = k3; key3 = k1; } + if (k1 <= k3) { + key2 = k1; + key3 = k3; + } else { + key2 = k3; + key3 = k1; + } } else { key1 = k3; - if (k1 <= k2) { key2 = k1; key3 = k2; } - else { key2 = k2; key3 = k1; } + if (k1 <= k2) { + key2 = k1; + key3 = k2; + } else { + key2 = k2; + key3 = k1; + } } } // copy ctor InputBinding(const InputBinding& o) : key1(o.key1), key2(o.key2), key3(o.key3) {} - + inline bool operator==(const InputBinding& o) { // 0 = SDLK_UNKNOWN aka unused slot return (key3 == o.key3 || key3 == 0 || o.key3 == 0) && (key2 == o.key2 || key2 == 0 || o.key2 == 0) && (key1 == o.key1 || key1 == 0 || o.key1 == 0); - // it is already very fast, + // it is already very fast, // but reverse order makes it check the actual keys first instead of possible 0-s, // potenially skipping the later expressions of the three-way AND } @@ -236,10 +257,10 @@ class InputBinding { // returns a u32 based on the event type (keyboard, mouse buttons, or wheel) static u32 getInputIDFromEvent(const SDL_Event& e); - }; class ControllerOutput { static GameController* controller; + public: static void setControllerOutputController(GameController* c); @@ -291,13 +312,9 @@ void updatePressedKeys(u32 button, bool is_pressed); void activateOutputsFromInputs(); - void updateMouse(GameController* controller); // Polls the mouse for changes, and simulates joystick movement from it. Uint32 mousePolling(void* param, Uint32 id, Uint32 interval); - - - -} \ No newline at end of file +} // namespace Input \ No newline at end of file diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 62c2029343d..acd34bc2d10 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -8,8 +8,8 @@ #include "SDL3/SDL_video.h" #include "common/assert.h" #include "common/config.h" -#include "common/version.h" #include "common/elf_info.h" +#include "common/version.h" #include "core/libraries/pad/pad.h" #include "imgui/renderer/imgui_core.h" #include "input/controller.h" @@ -188,9 +188,9 @@ void WindowSDL::onKeyboardMouseInput(const SDL_Event* event) { return; } } - + // if it's a wheel event, make a timer that turns it off after a set time - if(event->type == SDL_EVENT_MOUSE_WHEEL) { + if (event->type == SDL_EVENT_MOUSE_WHEEL) { const SDL_Event* copy = new SDL_Event(*event); SDL_AddTimer(33, wheelOffCallback, (void*)copy); } @@ -200,7 +200,6 @@ void WindowSDL::onKeyboardMouseInput(const SDL_Event* event) { // update bindings Input::activateOutputsFromInputs(); - } void WindowSDL::onGamepadEvent(const SDL_Event* event) { diff --git a/src/sdl_window.h b/src/sdl_window.h index 1c298682f59..4266165c175 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -3,8 +3,8 @@ #pragma once -#include "string" #include "common/types.h" +#include "string" struct SDL_Window; struct SDL_Gamepad; From 3e512bcd514b163e67a4a50649d8cd06068646e6 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Thu, 14 Nov 2024 15:28:10 +0100 Subject: [PATCH 48/79] Fixed clang and added a const keyword for mac --- src/common/config.cpp | 4 ++-- src/input/input_handler.cpp | 8 ++++---- src/input/input_handler.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/common/config.cpp b/src/common/config.cpp index 8764bed39cf..d3bdc7895ce 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -801,10 +801,10 @@ std::filesystem::path getFoolproofKbmConfigFile(const std::string& game_id) { } // if empty, we only need to execute the function up until this point - if(game_id.empty()) { + if (game_id.empty()) { return default_config_file; } - + // If game-specific config doesn't exist, create it from the default config if (!std::filesystem::exists(config_file)) { std::filesystem::copy(default_config_file, config_file); diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 556ce3e97cb..0e6e36f6263 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -343,13 +343,13 @@ void ControllerOutput::update(bool pressed, u32 param) { case Axis::TriggerRight: // todo: verify this works (This probably works from testing, // but needs extra info (multiple input to the same trigger?)) - axis_value = SDL_clamp((pressed ? (int)param : 0) * multiplier, 0, 127); + axis_value = SDL_clamp((pressed ? (s32)param : 0) * multiplier, 0, 127); controller->Axis(0, axis, GetAxis(0, 0x80, axis_value)); return; default: break; } - axis_value = SDL_clamp((pressed ? (int)param : 0) * multiplier, -127, 127); + axis_value = SDL_clamp((pressed ? (s32)param : 0) * multiplier, -127, 127); int ax = GetAxis(-0x80, 0x80, axis_value); controller->Axis(0, axis, ax); } else { @@ -400,13 +400,13 @@ void ControllerOutput::addUpdate(bool pressed, u32 param) { case Axis::TriggerLeft: case Axis::TriggerRight: // todo: verify this works - axis_value = SDL_clamp((pressed ? (int)param : 0) * multiplier + axis_value, 0, 127); + axis_value = SDL_clamp((pressed ? (s32)param : 0) * multiplier + axis_value, 0, 127); controller->Axis(0, axis, GetAxis(0, 0x80, axis_value)); return; default: break; } - axis_value = SDL_clamp((pressed ? (int)param : 0) * multiplier + axis_value, -127, 127); + axis_value = SDL_clamp((pressed ? (s32)param : 0) * multiplier + axis_value, -127, 127); controller->Axis(0, axis, GetAxis(-0x80, 0x80, axis_value)); // LOG_INFO(Input, "Axis value delta: {} final value: {}", (pressed ? a_value : 0), // axis_value); diff --git a/src/input/input_handler.h b/src/input/input_handler.h index cd752e9675e..f22c7e28ef9 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -299,7 +299,7 @@ class BindingConnection { // todo: check if out is in the allowed array output = out; } - bool operator<(const BindingConnection& other) { + bool operator<(const BindingConnection& other) const { return binding < other.binding; } }; From 1efd2475840a813281db12d7d8641dd653de7c2f Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Thu, 14 Nov 2024 22:29:56 +0100 Subject: [PATCH 49/79] Fix input hierarchy --- src/input/input_handler.cpp | 97 ++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 55 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 0e6e36f6263..325afa2840a 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -439,62 +439,54 @@ void updatePressedKeys(u32 value, bool is_pressed) { // Check if a given binding's all keys are currently active. bool isInputActive(const InputBinding& i) { - bool* flag1 = nullptr; - bool* flag2 = nullptr; - bool* flag3 = nullptr; - - bool key1_pressed = - std::find(toggled_keys.begin(), toggled_keys.end(), i.key1) != toggled_keys.end(); - bool key2_pressed = - std::find(toggled_keys.begin(), toggled_keys.end(), i.key2) != toggled_keys.end(); - bool key3_pressed = - std::find(toggled_keys.begin(), toggled_keys.end(), i.key3) != toggled_keys.end(); - - // First pass: locate each key and save pointers to their flags if found - for (auto& entry : pressed_keys) { - u32 key = entry.first; - bool& is_active = entry.second; - - if (key1_pressed || (i.key1 != 0 && key == i.key1 && !flag1)) { - flag1 = &is_active; - } else if (key2_pressed || (i.key2 != 0 && key == i.key2 && !flag2)) { - flag2 = &is_active; - } else if (key3_pressed || (i.key3 != 0 && key == i.key3 && !flag3)) { - flag3 = &is_active; - break; - } else { - return false; // an all 0 input never gets activated + // Extract keys from InputBinding and ignore unused (0) keys + std::list input_keys = { i.key1, i.key2, i.key3 }; + input_keys.remove(0); + + // Iterator for pressed_keys, starting from the beginning + auto pressed_it = pressed_keys.begin(); + auto pressed_end = pressed_keys.end(); + + // Store pointers to flags in pressed_keys that need to be set if all keys are active + std::list flags_to_set; + + // Check if all keys in input_keys are active + for (uint32_t key : input_keys) { + bool key_found = false; + + // Search for the current key in pressed_keys starting from the last checked position + while (pressed_it != pressed_end && pressed_it->first <= key) { + if (pressed_it->first == key) { + if (!pressed_it->second) { + flags_to_set.push_back(&pressed_it->second); // Collect pointer if flag is not already set + } + key_found = true; + ++pressed_it; // Move to the next key in pressed_keys + break; + } + ++pressed_it; } - } - // If any required key was not found, return false without updating flags - if ((i.key1 != 0 && !flag1) || (i.key2 != 0 && !flag2) || (i.key3 != 0 && !flag3)) { - return false; + // If not found in pressed_keys, check in toggled_keys + if (!key_found && std::find(toggled_keys.begin(), toggled_keys.end(), key) == toggled_keys.end()) { + return false; // Key not found in either list + } } - // Check if all flags are already true, which indicates this input is overridden (only if the - // key is not 0) - if ((i.key1 == 0 || (flag1 && *flag1)) && (i.key2 == 0 || (flag2 && *flag2)) && - (i.key3 == 0 || (flag3 && *flag3))) { - return false; // This input is overridden by another input + // Set all flags now that we've verified all keys are active + for (bool* flag : flags_to_set) { + *flag = true; } - // Set flags to true only after confirming all keys are present and not overridden - if (flag1 && !key1_pressed) - *flag1 = true; - if (flag2 && !key2_pressed) - *flag2 = true; - if (flag3 && !key3_pressed) - *flag3 = true; - - LOG_DEBUG(Input, "A valid held input is found: {}, flag ptrs: {} {} {}", i.toString(), - fmt::ptr(flag1), fmt::ptr(flag2), fmt::ptr(flag3)); - return true; + return true; // All keys are active } void activateOutputsFromInputs() { - LOG_DEBUG(Input, "Starting input scan..."); + //LOG_DEBUG(Input, "Starting input scan... {} inputs active", std::distance(pressed_keys.begin(), pressed_keys.end())); // reset everything + for (auto& it : pressed_keys) { + it.second = false; + } for (auto it = connections.begin(); it != connections.end(); it++) { if (it->output) { it->output->update(false, 0); @@ -503,17 +495,12 @@ void activateOutputsFromInputs() { std::distance(connections.begin(), it)); } } - for (auto it : pressed_keys) { - it.second = false; - } // iterates over the connections, and updates them depending on whether the corresponding input // trio is found - for (auto it = connections.begin(); it != connections.end(); it++) { - if (it->output) { - it->output->addUpdate(isInputActive(it->binding), it->parameter); - } else { - // LOG_DEBUG(Input, "Null output in BindingConnection at position {}", - // std::distance(connections.begin(), it)); + for (auto& it : connections) { + if (it.output) { + bool active = isInputActive(it.binding); + it.output->addUpdate(active, it.parameter); } } } From e43d60edaa704e6803e0d85e65121c2dccacd9ab Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Fri, 15 Nov 2024 09:04:43 +0100 Subject: [PATCH 50/79] Fixed joysick halfmodes, and possibly the last update on input hierarchy --- src/input/input_handler.cpp | 23 ++++++++++++++--------- src/input/input_handler.h | 13 ++++++++++++- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 325afa2840a..2031939f722 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -334,23 +334,25 @@ void ControllerOutput::update(bool pressed, u32 param) { case Axis::LeftX: case Axis::LeftY: multiplier = leftjoystick_halfmode ? 0.5 : 1.0; + //LOG_DEBUG(Input, "Joystick multiplier set to {}", multiplier); break; case Axis::RightX: case Axis::RightY: multiplier = rightjoystick_halfmode ? 0.5 : 1.0; + //LOG_DEBUG(Input, "Joystick multiplier set to {}", multiplier); break; case Axis::TriggerLeft: case Axis::TriggerRight: // todo: verify this works (This probably works from testing, // but needs extra info (multiple input to the same trigger?)) - axis_value = SDL_clamp((pressed ? (s32)param : 0) * multiplier, 0, 127); + axis_value = SDL_clamp((pressed ? (s32)param : 0), 0, 127); controller->Axis(0, axis, GetAxis(0, 0x80, axis_value)); return; default: break; } - axis_value = SDL_clamp((pressed ? (s32)param : 0) * multiplier, -127, 127); - int ax = GetAxis(-0x80, 0x80, axis_value); + axis_value = SDL_clamp((pressed ? (s32)param : 0), -127, 127); + int ax = GetAxis(-0x80, 0x80, axis_value * multiplier); controller->Axis(0, axis, ax); } else { LOG_DEBUG(Input, "Controller output with no values detected!"); @@ -372,10 +374,10 @@ void ControllerOutput::addUpdate(bool pressed, u32 param) { controller->CheckButton(0, button, pressed); break; case LEFTJOYSTICK_HALFMODE: - leftjoystick_halfmode = pressed; + leftjoystick_halfmode |= pressed; break; case RIGHTJOYSTICK_HALFMODE: - rightjoystick_halfmode = pressed; + rightjoystick_halfmode |= pressed; break; case KEY_TOGGLE: if (pressed) { @@ -392,22 +394,24 @@ void ControllerOutput::addUpdate(bool pressed, u32 param) { case Axis::LeftX: case Axis::LeftY: multiplier = leftjoystick_halfmode ? 0.5 : 1.0; + LOG_DEBUG(Input, "Left joystick multiplier set to {}", multiplier); break; case Axis::RightX: case Axis::RightY: multiplier = rightjoystick_halfmode ? 0.5 : 1.0; + LOG_DEBUG(Input, " Right joystick multiplier set to {}", multiplier); break; case Axis::TriggerLeft: case Axis::TriggerRight: // todo: verify this works - axis_value = SDL_clamp((pressed ? (s32)param : 0) * multiplier + axis_value, 0, 127); + axis_value = SDL_clamp((pressed ? (s32)param : 0) + axis_value, 0, 127); controller->Axis(0, axis, GetAxis(0, 0x80, axis_value)); return; default: break; } - axis_value = SDL_clamp((pressed ? (s32)param : 0) * multiplier + axis_value, -127, 127); - controller->Axis(0, axis, GetAxis(-0x80, 0x80, axis_value)); + axis_value = SDL_clamp(((pressed ? (s32)param : 0)+ axis_value) , -127, 127); + controller->Axis(0, axis, GetAxis(-0x80, 0x80, axis_value * multiplier)); // LOG_INFO(Input, "Axis value delta: {} final value: {}", (pressed ? a_value : 0), // axis_value); } else { @@ -458,9 +462,9 @@ bool isInputActive(const InputBinding& i) { while (pressed_it != pressed_end && pressed_it->first <= key) { if (pressed_it->first == key) { if (!pressed_it->second) { + key_found = true; flags_to_set.push_back(&pressed_it->second); // Collect pointer if flag is not already set } - key_found = true; ++pressed_it; // Move to the next key in pressed_keys break; } @@ -478,6 +482,7 @@ bool isInputActive(const InputBinding& i) { *flag = true; } + LOG_DEBUG(Input, "Input found: {}", i.toString()); return true; // All keys are active } diff --git a/src/input/input_handler.h b/src/input/input_handler.h index f22c7e28ef9..a5b46bb2302 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -283,6 +283,12 @@ class ControllerOutput { std::string toString() const { return fmt::format("({}, {}, {})", button, (int)axis, axis_value); } + inline bool isButton() const { + return axis == Axis::AxisMax && button != 0; + } + inline bool isAxis() const { + return axis != Axis::AxisMax && button == 0; + } void update(bool pressed, u32 param = 0); // Off events are not counted void addUpdate(bool pressed, u32 param = 0); @@ -300,7 +306,12 @@ class BindingConnection { output = out; } bool operator<(const BindingConnection& other) const { - return binding < other.binding; + if (binding < other.binding) { + return true; + } + // false, except if the first is a button and second is an axis, + // in which case the button is higher priority + return output->isButton() && other.output->isAxis(); } }; From 900b57898808a48bab6fcb8edd8c0927f34160df Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Fri, 15 Nov 2024 09:06:52 +0100 Subject: [PATCH 51/79] clang-format --- src/input/input_handler.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 2031939f722..b2e599e9b5b 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -334,12 +334,12 @@ void ControllerOutput::update(bool pressed, u32 param) { case Axis::LeftX: case Axis::LeftY: multiplier = leftjoystick_halfmode ? 0.5 : 1.0; - //LOG_DEBUG(Input, "Joystick multiplier set to {}", multiplier); + // LOG_DEBUG(Input, "Joystick multiplier set to {}", multiplier); break; case Axis::RightX: case Axis::RightY: multiplier = rightjoystick_halfmode ? 0.5 : 1.0; - //LOG_DEBUG(Input, "Joystick multiplier set to {}", multiplier); + // LOG_DEBUG(Input, "Joystick multiplier set to {}", multiplier); break; case Axis::TriggerLeft: case Axis::TriggerRight: @@ -410,7 +410,7 @@ void ControllerOutput::addUpdate(bool pressed, u32 param) { default: break; } - axis_value = SDL_clamp(((pressed ? (s32)param : 0)+ axis_value) , -127, 127); + axis_value = SDL_clamp(((pressed ? (s32)param : 0) + axis_value), -127, 127); controller->Axis(0, axis, GetAxis(-0x80, 0x80, axis_value * multiplier)); // LOG_INFO(Input, "Axis value delta: {} final value: {}", (pressed ? a_value : 0), // axis_value); @@ -444,7 +444,7 @@ void updatePressedKeys(u32 value, bool is_pressed) { // Check if a given binding's all keys are currently active. bool isInputActive(const InputBinding& i) { // Extract keys from InputBinding and ignore unused (0) keys - std::list input_keys = { i.key1, i.key2, i.key3 }; + std::list input_keys = {i.key1, i.key2, i.key3}; input_keys.remove(0); // Iterator for pressed_keys, starting from the beginning @@ -463,17 +463,19 @@ bool isInputActive(const InputBinding& i) { if (pressed_it->first == key) { if (!pressed_it->second) { key_found = true; - flags_to_set.push_back(&pressed_it->second); // Collect pointer if flag is not already set + flags_to_set.push_back( + &pressed_it->second); // Collect pointer if flag is not already set } - ++pressed_it; // Move to the next key in pressed_keys + ++pressed_it; // Move to the next key in pressed_keys break; } ++pressed_it; } // If not found in pressed_keys, check in toggled_keys - if (!key_found && std::find(toggled_keys.begin(), toggled_keys.end(), key) == toggled_keys.end()) { - return false; // Key not found in either list + if (!key_found && + std::find(toggled_keys.begin(), toggled_keys.end(), key) == toggled_keys.end()) { + return false; // Key not found in either list } } @@ -483,12 +485,13 @@ bool isInputActive(const InputBinding& i) { } LOG_DEBUG(Input, "Input found: {}", i.toString()); - return true; // All keys are active + return true; // All keys are active } void activateOutputsFromInputs() { - //LOG_DEBUG(Input, "Starting input scan... {} inputs active", std::distance(pressed_keys.begin(), pressed_keys.end())); - // reset everything + // LOG_DEBUG(Input, "Starting input scan... {} inputs active", + // std::distance(pressed_keys.begin(), pressed_keys.end())); + // reset everything for (auto& it : pressed_keys) { it.second = false; } From 94c6a9fad90e55ddee79cb476863fa62044fe422 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Fri, 15 Nov 2024 09:44:25 +0100 Subject: [PATCH 52/79] Rewrote the default config to reflect new changes --- src/common/config.cpp | 28 ++++++++++++++++------------ src/input/input_handler.h | 10 +++++++--- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/common/config.cpp b/src/common/config.cpp index d3bdc7895ce..021f1f255ad 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -701,21 +701,24 @@ void setDefaultValues() { gpuId = -1; } -std::string_view getDefaultKeyboardConfig() { - static std::string_view default_config = - R"(#This is the default keybinding config +constexpr std::string_view getDefaultKeyboardConfig() { + return R"(#This is the default keybinding config #To change per-game configs, modify the CUSAXXXXX.ini files -#To change the default config that applies to new games without already existing configs, modify default.ini +#To change the default config that applies to new games without modifying already existing configs, modify default.ini #If you don't like certain mappings, delete, change or comment them out. #You can add any amount of KBM keybinds to a single controller input, #but you can use each KBM keybind for one controller input. +#Every input consists of up to 3 different keys. #Keybinds used by the emulator (these are unchangeable): -#F11 : fullscreen +#F12 : Trigger Renderdoc capture +#F11 : Fullscreen #F10 : FPS counter -#F9 : toggle mouse-to-joystick input -# (it overwrites everything else to that joystick, so this is required) +#Ctrl + F10 : Debug overlay +#F9 : Pause emulator, but only if the debug overlay is active #F8 : reparse keyboard input(this) +#F7 : toggle mouse-to-joystick input +# (it overwrites everything else to that joystick, so this is required) #This is a mapping for Bloodborne, inspired by other Souls titles on PC. @@ -743,8 +746,8 @@ left = mousewheelleft; #Change weapon in right hand right = d, lalt; right = mousewheelright; -#Change into 'inventory mode', so you don't have to hold lalt every time you go into menus -modkey_toggle = i, lalt; +#Change into 'inventory mode', so you don't have to hold the secondary key every time you go into menus +key_toggle = i, lalt; #Menu options = escape; @@ -767,14 +770,15 @@ r3 = middlebutton; #Axis mappings #Move +#Change to 'walk mode' by holding the following key: +#(halves the distance the inputs push the virtual joystick to a given direction) +leftjoystick_halfmode = lctrl; axis_left_x_minus = a; axis_left_x_plus = d; axis_left_y_minus = w; axis_left_y_plus = s; -#Change to 'walk mode' by holding the following key: -leftjoystick_halfmode = lctrl; + )"; - return default_config; } std::filesystem::path getFoolproofKbmConfigFile(const std::string& game_id) { // Read configuration file of the game, and if it doesn't exist, generate it from default diff --git a/src/input/input_handler.h b/src/input/input_handler.h index a5b46bb2302..7c179810712 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -306,12 +306,16 @@ class BindingConnection { output = out; } bool operator<(const BindingConnection& other) const { + // a button is a higher priority than an axis, as buttons can influence axes + // (e.g. joystick_halfmode) + if( output->isButton() && other.output->isAxis()) { + return true; + } if (binding < other.binding) { return true; } - // false, except if the first is a button and second is an axis, - // in which case the button is higher priority - return output->isButton() && other.output->isAxis(); + return false; + } }; From 9d6dd79486537dc10588bfc0af8165e6fd1d1bea Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Fri, 15 Nov 2024 09:45:32 +0100 Subject: [PATCH 53/79] clang --- src/input/input_handler.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/input/input_handler.h b/src/input/input_handler.h index 7c179810712..a4184bf2d11 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -308,14 +308,13 @@ class BindingConnection { bool operator<(const BindingConnection& other) const { // a button is a higher priority than an axis, as buttons can influence axes // (e.g. joystick_halfmode) - if( output->isButton() && other.output->isAxis()) { + if (output->isButton() && other.output->isAxis()) { return true; } if (binding < other.binding) { return true; } return false; - } }; From 91e30ac62ba014f07fb1f23130dc9012b8086fc8 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Fri, 15 Nov 2024 10:33:56 +0100 Subject: [PATCH 54/79] Update code style --- src/common/config.cpp | 6 ++-- src/common/config.h | 2 +- src/input/input_handler.cpp | 64 ++++++++++++++++++------------------- src/input/input_handler.h | 41 +++++++++++------------- src/sdl_window.cpp | 30 ++++++++--------- src/sdl_window.h | 6 ++-- 6 files changed, 73 insertions(+), 76 deletions(-) diff --git a/src/common/config.cpp b/src/common/config.cpp index 021f1f255ad..045fa398cdb 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -701,7 +701,7 @@ void setDefaultValues() { gpuId = -1; } -constexpr std::string_view getDefaultKeyboardConfig() { +constexpr std::string_view GetDefaultKeyboardConfig() { return R"(#This is the default keybinding config #To change per-game configs, modify the CUSAXXXXX.ini files #To change the default config that applies to new games without modifying already existing configs, modify default.ini @@ -780,7 +780,7 @@ axis_left_y_plus = s; )"; } -std::filesystem::path getFoolproofKbmConfigFile(const std::string& game_id) { +std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id) { // Read configuration file of the game, and if it doesn't exist, generate it from default // If that doesn't exist either, generate that from getDefaultConfig() and try again // If even the folder is missing, we start with that. @@ -797,7 +797,7 @@ std::filesystem::path getFoolproofKbmConfigFile(const std::string& game_id) { // Check if the default config exists if (!std::filesystem::exists(default_config_file)) { // If the default config is also missing, create it from getDefaultConfig() - const auto default_config = getDefaultKeyboardConfig(); + const auto default_config = GetDefaultKeyboardConfig(); std::ofstream default_config_stream(default_config_file); if (default_config_stream) { default_config_stream << default_config; diff --git a/src/common/config.h b/src/common/config.h index 3dfafade7b3..d5a28218dad 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -124,7 +124,7 @@ std::string getEmulatorLanguage(); void setDefaultValues(); // todo: name and function location pending -std::filesystem::path getFoolproofKbmConfigFile(const std::string& game_id = ""); +std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id = ""); // settings u32 GetLanguage(); diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index b2e599e9b5b..af2a3be4c3a 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -81,13 +81,13 @@ ControllerOutput output_array[] = { ControllerOutput(0, Input::Axis::AxisMax)}; // We had to go through 3 files of indirection just to update a flag -void toggleMouseEnabled() { +void ToggleMouseEnabled() { mouse_enabled ^= true; } // parsing related functions // syntax: 'name, name,name' or 'name,name' or 'name' -InputBinding getBindingFromString(std::string& line) { +InputBinding GetBindingFromString(std::string& line) { u32 key1 = 0, key2 = 0, key3 = 0; // Split the string by commas @@ -118,7 +118,7 @@ InputBinding getBindingFromString(std::string& line) { } // function that takes a controlleroutput, and returns the array's corresponding element's pointer -ControllerOutput* getOutputPointer(const ControllerOutput& parsed) { +ControllerOutput* GetOutputPointer(const ControllerOutput& parsed) { // i wonder how long until someone notices this or I get rid of it for (int i = 0; i[output_array] != ControllerOutput(0, Axis::AxisMax); i++) { if (i[output_array] == parsed) { @@ -128,11 +128,11 @@ ControllerOutput* getOutputPointer(const ControllerOutput& parsed) { return nullptr; } -void parseInputConfig(const std::string game_id = "") { +void ParseInputConfig(const std::string game_id = "") { - const auto config_file = Config::getFoolproofKbmConfigFile(game_id); + const auto config_file = Config::GetFoolproofKbmConfigFile(game_id); - // todo: change usages of this to getFoolproofKbmConfigFile (in the gui) + // todo: change usages of this to GetFoolproofKbmConfigFile (in the gui) if (game_id == "") { return; } @@ -186,15 +186,15 @@ void parseInputConfig(const std::string game_id = "") { if (output_string == "key_toggle") { if (comma_pos != std::string::npos) { // handle key-to-key toggling (separate list?) - InputBinding toggle_keys = getBindingFromString(input_string); - if (toggle_keys.keyCount() != 2) { + InputBinding toggle_keys = GetBindingFromString(input_string); + if (toggle_keys.KeyCount() != 2) { LOG_ERROR(Input, "Syntax error: Please provide exactly 2 keys: " "first is the toggler, the second is the key to toggle: {}", line); continue; } - ControllerOutput* toggle_out = getOutputPointer(ControllerOutput(KEY_TOGGLE)); + ControllerOutput* toggle_out = GetOutputPointer(ControllerOutput(KEY_TOGGLE)); BindingConnection toggle_connection = BindingConnection(InputBinding(toggle_keys.key2), toggle_out, toggle_keys.key3); connections.insert(connections.end(), toggle_connection); @@ -221,24 +221,24 @@ void parseInputConfig(const std::string game_id = "") { } // normal cases - InputBinding binding = getBindingFromString(input_string); + InputBinding binding = GetBindingFromString(input_string); BindingConnection connection(0, nullptr); auto button_it = string_to_cbutton_map.find(output_string); auto axis_it = string_to_axis_map.find(output_string); - if (binding.isEmpty()) { + if (binding.IsEmpty()) { LOG_DEBUG(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount, line); continue; } if (button_it != string_to_cbutton_map.end()) { connection = - BindingConnection(binding, getOutputPointer(ControllerOutput(button_it->second))); + BindingConnection(binding, GetOutputPointer(ControllerOutput(button_it->second))); connections.insert(connections.end(), connection); } else if (axis_it != string_to_axis_map.end()) { connection = BindingConnection( - binding, getOutputPointer(ControllerOutput(0, axis_it->second.axis)), + binding, GetOutputPointer(ControllerOutput(0, axis_it->second.axis)), axis_it->second.value); connections.insert(connections.end(), connection); } else { @@ -253,7 +253,7 @@ void parseInputConfig(const std::string game_id = "") { LOG_DEBUG(Input, "Done parsing the input config!"); } -u32 getMouseWheelEvent(const SDL_Event& event) { +u32 GetMouseWheelEvent(const SDL_Event& event) { if (event.type != SDL_EVENT_MOUSE_WHEEL && event.type != SDL_EVENT_MOUSE_WHEEL_OFF) { LOG_DEBUG(Input, "Something went wrong with wheel input parsing!"); return 0; @@ -270,7 +270,7 @@ u32 getMouseWheelEvent(const SDL_Event& event) { return (u32)-1; } -u32 InputBinding::getInputIDFromEvent(const SDL_Event& e) { +u32 InputBinding::GetInputIDFromEvent(const SDL_Event& e) { switch (e.type) { case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: @@ -280,18 +280,18 @@ u32 InputBinding::getInputIDFromEvent(const SDL_Event& e) { return (u32)e.button.button; case SDL_EVENT_MOUSE_WHEEL: case SDL_EVENT_MOUSE_WHEEL_OFF: - return getMouseWheelEvent(e); + return GetMouseWheelEvent(e); default: return (u32)-1; } } GameController* ControllerOutput::controller = nullptr; -void ControllerOutput::setControllerOutputController(GameController* c) { +void ControllerOutput::GetControllerOutputController(GameController* c) { ControllerOutput::controller = c; } -void toggleKeyInList(u32 key) { +void ToggleKeyInList(u32 key) { auto it = std::find(toggled_keys.begin(), toggled_keys.end(), key); if (it == toggled_keys.end()) { toggled_keys.insert(toggled_keys.end(), key); @@ -302,7 +302,7 @@ void toggleKeyInList(u32 key) { } } -void ControllerOutput::update(bool pressed, u32 param) { +void ControllerOutput::Update(bool pressed, u32 param) { float touchpad_x = 0; if (button != 0) { switch (button) { @@ -321,7 +321,7 @@ void ControllerOutput::update(bool pressed, u32 param) { break; case KEY_TOGGLE: if (pressed) { - toggleKeyInList(param); + ToggleKeyInList(param); } break; default: // is a normal key (hopefully) @@ -358,7 +358,7 @@ void ControllerOutput::update(bool pressed, u32 param) { LOG_DEBUG(Input, "Controller output with no values detected!"); } } -void ControllerOutput::addUpdate(bool pressed, u32 param) { +void ControllerOutput::AddUpdate(bool pressed, u32 param) { float touchpad_x = 0; if (button != 0) { @@ -381,7 +381,7 @@ void ControllerOutput::addUpdate(bool pressed, u32 param) { break; case KEY_TOGGLE: if (pressed) { - toggleKeyInList(param); + ToggleKeyInList(param); } break; default: // is a normal key (hopefully) @@ -419,7 +419,7 @@ void ControllerOutput::addUpdate(bool pressed, u32 param) { } } -void updatePressedKeys(u32 value, bool is_pressed) { +void UpdatePressedKeys(u32 value, bool is_pressed) { if (is_pressed) { // Find the correct position for insertion to maintain order auto it = @@ -442,7 +442,7 @@ void updatePressedKeys(u32 value, bool is_pressed) { } // Check if a given binding's all keys are currently active. -bool isInputActive(const InputBinding& i) { +bool IsInputActive(const InputBinding& i) { // Extract keys from InputBinding and ignore unused (0) keys std::list input_keys = {i.key1, i.key2, i.key3}; input_keys.remove(0); @@ -484,11 +484,11 @@ bool isInputActive(const InputBinding& i) { *flag = true; } - LOG_DEBUG(Input, "Input found: {}", i.toString()); + LOG_DEBUG(Input, "Input found: {}", i.ToString()); return true; // All keys are active } -void activateOutputsFromInputs() { +void ActivateOutputsFromInputs() { // LOG_DEBUG(Input, "Starting input scan... {} inputs active", // std::distance(pressed_keys.begin(), pressed_keys.end())); // reset everything @@ -497,7 +497,7 @@ void activateOutputsFromInputs() { } for (auto it = connections.begin(); it != connections.end(); it++) { if (it->output) { - it->output->update(false, 0); + it->output->Update(false, 0); } else { LOG_DEBUG(Input, "Null output in BindingConnection at position {}", std::distance(connections.begin(), it)); @@ -507,13 +507,13 @@ void activateOutputsFromInputs() { // trio is found for (auto& it : connections) { if (it.output) { - bool active = isInputActive(it.binding); - it.output->addUpdate(active, it.parameter); + bool active = IsInputActive(it.binding); + it.output->AddUpdate(active, it.parameter); } } } -void updateMouse(GameController* controller) { +void UpdateMouse(GameController* controller) { if (!mouse_enabled) return; Axis axis_x, axis_y; @@ -550,9 +550,9 @@ void updateMouse(GameController* controller) { } } -Uint32 mousePolling(void* param, Uint32 id, Uint32 interval) { +Uint32 MousePolling(void* param, Uint32 id, Uint32 interval) { auto* data = (GameController*)param; - updateMouse(data); + UpdateMouse(data); return interval; } diff --git a/src/input/input_handler.h b/src/input/input_handler.h index a4184bf2d11..8a76beae2c5 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -175,12 +175,9 @@ const std::map string_to_keyboard_key_map = { }; // literally the only flag that needs external access -void toggleMouseEnabled(); +void ToggleMouseEnabled(); -// i wrapped it in a function so I can collapse it -std::string_view getDefaultKeyboardConfig(); - -void parseInputConfig(const std::string game_id); +void ParseInputConfig(const std::string game_id); class InputBinding { public: @@ -241,28 +238,28 @@ class InputBinding { // but reverse order makes it check the actual keys first instead of possible 0-s, // potenially skipping the later expressions of the three-way AND } - inline int keyCount() const { + inline int KeyCount() const { return (key1 ? 1 : 0) + (key2 ? 1 : 0) + (key3 ? 1 : 0); } // Sorts by the amount of non zero keys - left side is 'bigger' here bool operator<(const InputBinding& other) const { - return keyCount() > other.keyCount(); + return KeyCount() > other.KeyCount(); } - inline bool isEmpty() { + inline bool IsEmpty() { return key1 == 0 && key2 == 0 && key3 == 0; } - std::string toString() const { + std::string ToString() const { return fmt::format("({}, {}, {})", key1, key2, key3); } // returns a u32 based on the event type (keyboard, mouse buttons, or wheel) - static u32 getInputIDFromEvent(const SDL_Event& e); + static u32 GetInputIDFromEvent(const SDL_Event& e); }; class ControllerOutput { static GameController* controller; public: - static void setControllerOutputController(GameController* c); + static void GetControllerOutputController(GameController* c); u32 button; Axis axis; @@ -280,18 +277,18 @@ class ControllerOutput { inline bool operator!=(const ControllerOutput& o) const { return button != o.button || axis != o.axis; } - std::string toString() const { + std::string ToString() const { return fmt::format("({}, {}, {})", button, (int)axis, axis_value); } - inline bool isButton() const { + inline bool IsButton() const { return axis == Axis::AxisMax && button != 0; } - inline bool isAxis() const { + inline bool IsAxis() const { return axis != Axis::AxisMax && button == 0; } - void update(bool pressed, u32 param = 0); + void Update(bool pressed, u32 param = 0); // Off events are not counted - void addUpdate(bool pressed, u32 param = 0); + void AddUpdate(bool pressed, u32 param = 0); }; class BindingConnection { public: @@ -308,7 +305,7 @@ class BindingConnection { bool operator<(const BindingConnection& other) const { // a button is a higher priority than an axis, as buttons can influence axes // (e.g. joystick_halfmode) - if (output->isButton() && other.output->isAxis()) { + if (output->IsButton() && other.output->IsAxis()) { return true; } if (binding < other.binding) { @@ -319,16 +316,16 @@ class BindingConnection { }; // Check if the 3 key input is currently active. -bool checkForInputDown(InputBinding i); +bool IsInputActive(const InputBinding& i); // Add/remove the input that generated the event to/from the held keys container. -void updatePressedKeys(u32 button, bool is_pressed); +void UpdatePressedKeys(u32 button, bool is_pressed); -void activateOutputsFromInputs(); +void ActivateOutputsFromInputs(); -void updateMouse(GameController* controller); +void UpdateMouse(GameController* controller); // Polls the mouse for changes, and simulates joystick movement from it. -Uint32 mousePolling(void* param, Uint32 id, Uint32 interval); +Uint32 MousePolling(void* param, Uint32 id, Uint32 interval); } // namespace Input \ No newline at end of file diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index acd34bc2d10..2567a85dc0a 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -79,8 +79,8 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_ window_info.render_surface = SDL_Metal_GetLayer(SDL_Metal_CreateView(window)); #endif // input handler init-s - Input::ControllerOutput::setControllerOutputController(controller); - Input::parseInputConfig(std::string(Common::ElfInfo::Instance().GameSerial())); + Input::ControllerOutput::GetControllerOutputController(controller); + Input::ParseInputConfig(std::string(Common::ElfInfo::Instance().GameSerial())); } WindowSDL::~WindowSDL() = default; @@ -101,12 +101,12 @@ void WindowSDL::waitEvent() { case SDL_EVENT_WINDOW_RESIZED: case SDL_EVENT_WINDOW_MAXIMIZED: case SDL_EVENT_WINDOW_RESTORED: - onResize(); + OnResize(); break; case SDL_EVENT_WINDOW_MINIMIZED: case SDL_EVENT_WINDOW_EXPOSED: is_shown = event.type == SDL_EVENT_WINDOW_EXPOSED; - onResize(); + OnResize(); break; case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: @@ -114,7 +114,7 @@ void WindowSDL::waitEvent() { case SDL_EVENT_MOUSE_WHEEL_OFF: case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: - onKeyboardMouseInput(&event); + OnKeyboardMouseInput(&event); break; case SDL_EVENT_GAMEPAD_BUTTON_DOWN: case SDL_EVENT_GAMEPAD_BUTTON_UP: @@ -124,7 +124,7 @@ void WindowSDL::waitEvent() { case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: - onGamepadEvent(&event); + OnGamepadEvent(&event); break; case SDL_EVENT_QUIT: is_open = false; @@ -136,10 +136,10 @@ void WindowSDL::waitEvent() { void WindowSDL::initTimers() { SDL_AddTimer(100, &PollController, controller); - SDL_AddTimer(33, Input::mousePolling, (void*)controller); + SDL_AddTimer(33, Input::MousePolling, (void*)controller); } -void WindowSDL::onResize() { +void WindowSDL::OnResize() { SDL_GetWindowSizeInPixels(window, &width, &height); ImGui::Core::OnResize(); } @@ -152,25 +152,25 @@ Uint32 wheelOffCallback(void* og_event, Uint32 timer_id, Uint32 interval) { return 0; } -void WindowSDL::onKeyboardMouseInput(const SDL_Event* event) { +void WindowSDL::OnKeyboardMouseInput(const SDL_Event* event) { using Libraries::Pad::OrbisPadButtonDataOffset; // get the event's id, if it's keyup or keydown bool input_down = event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || event->type == SDL_EVENT_MOUSE_WHEEL; - u32 input_id = Input::InputBinding::getInputIDFromEvent(*event); + u32 input_id = Input::InputBinding::GetInputIDFromEvent(*event); // Handle window controls outside of the input maps if (event->type == SDL_EVENT_KEY_DOWN) { // Reparse kbm inputs if (input_id == SDLK_F8) { - Input::parseInputConfig(std::string(Common::ElfInfo::Instance().GameSerial())); + Input::ParseInputConfig(std::string(Common::ElfInfo::Instance().GameSerial())); return; } // Toggle mouse capture and movement input else if (input_id == SDLK_F7) { - Input::toggleMouseEnabled(); + Input::ToggleMouseEnabled(); SDL_SetWindowRelativeMouseMode(this->GetSdlWindow(), !SDL_GetWindowRelativeMouseMode(this->GetSdlWindow())); return; @@ -196,13 +196,13 @@ void WindowSDL::onKeyboardMouseInput(const SDL_Event* event) { } // add/remove it from the list - Input::updatePressedKeys(input_id, input_down); + Input::UpdatePressedKeys(input_id, input_down); // update bindings - Input::activateOutputsFromInputs(); + Input::ActivateOutputsFromInputs(); } -void WindowSDL::onGamepadEvent(const SDL_Event* event) { +void WindowSDL::OnGamepadEvent(const SDL_Event* event) { using Libraries::Pad::OrbisPadButtonDataOffset; u32 button = 0; diff --git a/src/sdl_window.h b/src/sdl_window.h index 4266165c175..bafe377d08a 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -71,9 +71,9 @@ class WindowSDL { void initTimers(); private: - void onResize(); - void onKeyboardMouseInput(const SDL_Event* event); - void onGamepadEvent(const SDL_Event* event); + void OnResize(); + void OnKeyboardMouseInput(const SDL_Event* event); + void OnGamepadEvent(const SDL_Event* event); int sdlGamepadToOrbisButton(u8 button); From f5f988d63e42f2f56f2fb2931b26b0b9319c2cf8 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Fri, 15 Nov 2024 11:50:58 +0100 Subject: [PATCH 55/79] Updated sorting to accomodate for that one specific edge case --- src/input/input_handler.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/input/input_handler.h b/src/input/input_handler.h index 8a76beae2c5..85a78a6e403 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -305,7 +305,9 @@ class BindingConnection { bool operator<(const BindingConnection& other) const { // a button is a higher priority than an axis, as buttons can influence axes // (e.g. joystick_halfmode) - if (output->IsButton() && other.output->IsAxis()) { + if (output->IsButton() && + (other.output->IsAxis() && (other.output->axis != Axis::TriggerLeft && + other.output->axis != Axis::TriggerRight))) { return true; } if (binding < other.binding) { From 3d4db9122530bea0a1abc1c2648577330f668a73 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Fri, 15 Nov 2024 16:57:49 +0100 Subject: [PATCH 56/79] Fix default config and the latest bug with input hiearchy --- src/common/config.cpp | 4 ++-- src/input/input_handler.cpp | 17 +++++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/common/config.cpp b/src/common/config.cpp index 045fa398cdb..ac9c5b634d0 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -756,9 +756,9 @@ touchpad = g; #Transform l1 = rightbutton, lshift; -#Shoot -r1 = leftbutton; #Light attack +r1 = leftbutton; +#Shoot l2 = rightbutton; #Heavy attack r2 = leftbutton, lshift; diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index af2a3be4c3a..c86b1533475 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -461,11 +461,10 @@ bool IsInputActive(const InputBinding& i) { // Search for the current key in pressed_keys starting from the last checked position while (pressed_it != pressed_end && pressed_it->first <= key) { if (pressed_it->first == key) { - if (!pressed_it->second) { - key_found = true; - flags_to_set.push_back( - &pressed_it->second); // Collect pointer if flag is not already set - } + + key_found = true; + flags_to_set.push_back(&pressed_it->second); + ++pressed_it; // Move to the next key in pressed_keys break; } @@ -479,7 +478,13 @@ bool IsInputActive(const InputBinding& i) { } } - // Set all flags now that we've verified all keys are active + bool is_fully_blocked = true; + for (bool* flag : flags_to_set) { + is_fully_blocked &= *flag; + } + if(is_fully_blocked) { + return false; + } for (bool* flag : flags_to_set) { *flag = true; } From 01100091ffe67899a057c00d36699c4c7945d7c2 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sat, 16 Nov 2024 10:02:37 +0100 Subject: [PATCH 57/79] Fix typo --- src/input/input_handler.cpp | 4 +--- src/input/input_handler.h | 2 +- src/sdl_window.cpp | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index c86b1533475..80a71187c58 100644 --- a/src/input/input_handler.cpp +++ b/src/input/input_handler.cpp @@ -287,7 +287,7 @@ u32 InputBinding::GetInputIDFromEvent(const SDL_Event& e) { } GameController* ControllerOutput::controller = nullptr; -void ControllerOutput::GetControllerOutputController(GameController* c) { +void ControllerOutput::SetControllerOutputController(GameController* c) { ControllerOutput::controller = c; } @@ -494,8 +494,6 @@ bool IsInputActive(const InputBinding& i) { } void ActivateOutputsFromInputs() { - // LOG_DEBUG(Input, "Starting input scan... {} inputs active", - // std::distance(pressed_keys.begin(), pressed_keys.end())); // reset everything for (auto& it : pressed_keys) { it.second = false; diff --git a/src/input/input_handler.h b/src/input/input_handler.h index 85a78a6e403..c8a3d51a859 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -259,7 +259,7 @@ class ControllerOutput { static GameController* controller; public: - static void GetControllerOutputController(GameController* c); + static void SetControllerOutputController(GameController* c); u32 button; Axis axis; diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 2567a85dc0a..d20016f5a13 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -79,7 +79,7 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_ window_info.render_surface = SDL_Metal_GetLayer(SDL_Metal_CreateView(window)); #endif // input handler init-s - Input::ControllerOutput::GetControllerOutputController(controller); + Input::ControllerOutput::SetControllerOutputController(controller); Input::ParseInputConfig(std::string(Common::ElfInfo::Instance().GameSerial())); } From 9062be0fd776c241afb268ddb4f9c5c647995d99 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Sat, 16 Nov 2024 10:06:41 +0100 Subject: [PATCH 58/79] Temporarily added my GUI --- src/qt_gui/kbm_config_dialog.cpp | 187 +++++++++++++++++++++++++++++++ src/qt_gui/kbm_config_dialog.h | 37 ++++++ src/qt_gui/kbm_help_dialog.cpp | 101 +++++++++++++++++ src/qt_gui/kbm_help_dialog.h | 151 +++++++++++++++++++++++++ src/qt_gui/main_window.cpp | 10 ++ 5 files changed, 486 insertions(+) create mode 100644 src/qt_gui/kbm_config_dialog.cpp create mode 100644 src/qt_gui/kbm_config_dialog.h create mode 100644 src/qt_gui/kbm_help_dialog.cpp create mode 100644 src/qt_gui/kbm_help_dialog.h diff --git a/src/qt_gui/kbm_config_dialog.cpp b/src/qt_gui/kbm_config_dialog.cpp new file mode 100644 index 00000000000..a340668a63c --- /dev/null +++ b/src/qt_gui/kbm_config_dialog.cpp @@ -0,0 +1,187 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "kbm_config_dialog.h" +#include "kbm_help_dialog.h" + +#include +#include +#include "common/config.h" +#include "common/path_util.h" +#include "game_info.h" +#include "src/sdl_window.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +EditorDialog::EditorDialog(QWidget* parent) : QDialog(parent) { + + setWindowTitle("Edit Config File"); + resize(600, 400); + + // Create the editor widget + editor = new QPlainTextEdit(this); + editorFont.setPointSize(10); // Set default text size + editor->setFont(editorFont); // Apply font to the editor + + // Create the game selection combo box + gameComboBox = new QComboBox(this); + gameComboBox->addItem("default"); // Add default option + /* + gameComboBox = new QComboBox(this); + layout->addWidget(gameComboBox); // Add the combobox for selecting game configurations + + // Populate the combo box with game configurations + QStringList gameConfigs = GameInfoClass::GetGameInfo(this); + gameComboBox->addItems(gameConfigs); + gameComboBox->setCurrentText("default.ini"); // Set the default selection + */ + // Load all installed games + loadInstalledGames(); + + // Create Save, Cancel, and Help buttons + QPushButton* saveButton = new QPushButton("Save", this); + QPushButton* cancelButton = new QPushButton("Cancel", this); + QPushButton* helpButton = new QPushButton("Help", this); + + // Layout for the game selection and buttons + QHBoxLayout* topLayout = new QHBoxLayout(); + topLayout->addWidget(gameComboBox); + topLayout->addStretch(); + topLayout->addWidget(saveButton); + topLayout->addWidget(cancelButton); + topLayout->addWidget(helpButton); + + // Main layout with editor and buttons + QVBoxLayout* layout = new QVBoxLayout(this); + layout->addLayout(topLayout); + layout->addWidget(editor); + + // Load the default config file content into the editor + loadFile(gameComboBox->currentText()); + + // Connect button and combo box signals + connect(saveButton, &QPushButton::clicked, this, &EditorDialog::onSaveClicked); + connect(cancelButton, &QPushButton::clicked, this, &EditorDialog::onCancelClicked); + connect(helpButton, &QPushButton::clicked, this, &EditorDialog::onHelpClicked); + connect(gameComboBox, &QComboBox::currentTextChanged, this, + &EditorDialog::onGameSelectionChanged); +} + +void EditorDialog::loadFile(QString game) { + + // to make sure the files and the directory do exist + const auto config_file = Config::GetFoolproofKbmConfigFile(game.toStdString()); + QFile file(config_file); + + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&file); + editor->setPlainText(in.readAll()); + originalConfig = editor->toPlainText(); + file.close(); + } else { + QMessageBox::warning(this, "Error", "Could not open the file for reading"); + } +} + +void EditorDialog::saveFile(QString game) { + + // to make sure the files and the directory do exist + const auto config_file = Config::GetFoolproofKbmConfigFile(game.toStdString()); + QFile file(config_file); + + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream out(&file); + out << editor->toPlainText(); + file.close(); + } else { + QMessageBox::warning(this, "Error", "Could not open the file for writing"); + } +} + +// Override the close event to show the save confirmation dialog only if changes were made +void EditorDialog::closeEvent(QCloseEvent* event) { + if (hasUnsavedChanges()) { + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, "Save Changes", "Do you want to save changes?", + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + + if (reply == QMessageBox::Yes) { + saveFile(gameComboBox->currentText()); + event->accept(); // Close the dialog + } else if (reply == QMessageBox::No) { + event->accept(); // Close the dialog without saving + } else { + event->ignore(); // Cancel the close event + } + } else { + event->accept(); // No changes, close the dialog without prompting + } +} +void EditorDialog::keyPressEvent(QKeyEvent* event) { + if (event->key() == Qt::Key_Escape) { + close(); // Trigger the close action, same as pressing the close button + } else { + QDialog::keyPressEvent(event); // Call the base class implementation for other keys + } +} + +void EditorDialog::onSaveClicked() { + saveFile(gameComboBox->currentText()); + reject(); // Close the dialog +} + +void EditorDialog::onCancelClicked() { + reject(); // Close the dialog +} +bool isHelpOpen = false; +HelpDialog* helpDialog; +void EditorDialog::onHelpClicked() { + if (!isHelpOpen) { + helpDialog = new HelpDialog(this); + helpDialog->setWindowTitle("Help"); + helpDialog->setAttribute(Qt::WA_DeleteOnClose); // Clean up on close + // Get the position and size of the Config window + QRect configGeometry = this->geometry(); + int helpX = configGeometry.x() + configGeometry.width() + 10; // 10 pixels offset + int helpY = configGeometry.y(); + // Move the Help dialog to the right side of the Config window + helpDialog->move(helpX, helpY); + helpDialog->show(); + isHelpOpen = true; + } else { + helpDialog->close(); + isHelpOpen = false; + } +} + +bool EditorDialog::hasUnsavedChanges() { + // Compare the current content with the original content to check if there are unsaved changes + return editor->toPlainText() != originalConfig; +} +void EditorDialog::loadInstalledGames() { + QStringList filePaths; + for (const auto& installLoc : Config::getGameInstallDirs()) { + QString installDir; + Common::FS::PathToQString(installDir, installLoc); + QDir parentFolder(installDir); + QFileInfoList fileList = parentFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const auto& fileInfo : fileList) { + if (fileInfo.isDir() && !fileInfo.filePath().endsWith("-UPDATE")) { + gameComboBox->addItem(fileInfo.fileName()); // Add game name to combo box + } + } + } +} +QString previousGame = "default"; +void EditorDialog::onGameSelectionChanged(const QString& game) { + saveFile(previousGame); + loadFile(gameComboBox->currentText()); // Reload file based on the selected game + previousGame = gameComboBox->currentText(); +} diff --git a/src/qt_gui/kbm_config_dialog.h b/src/qt_gui/kbm_config_dialog.h new file mode 100644 index 00000000000..062e7b0ad83 --- /dev/null +++ b/src/qt_gui/kbm_config_dialog.h @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include "string" + +class EditorDialog : public QDialog { + Q_OBJECT // Necessary for using Qt's meta-object system (signals/slots) + public : explicit EditorDialog(QWidget* parent = nullptr); // Constructor + +protected: + void closeEvent(QCloseEvent* event) override; // Override close event + void keyPressEvent(QKeyEvent* event) override; + +private: + QPlainTextEdit* editor; // Editor widget for the config file + QFont editorFont; // To handle the text size + QString originalConfig; // Starting config string + std::string gameId; + + QComboBox* gameComboBox; // Combo box for selecting game configurations + + void loadFile(QString game); // Function to load the config file + void saveFile(QString game); // Function to save the config file + void loadInstalledGames(); // Helper to populate gameComboBox + bool hasUnsavedChanges(); // Checks for unsaved changes + +private slots: + void onSaveClicked(); // Save button slot + void onCancelClicked(); // Slot for handling cancel button + void onHelpClicked(); // Slot for handling help button + void onGameSelectionChanged(const QString& game); // Slot for game selection changes +}; diff --git a/src/qt_gui/kbm_help_dialog.cpp b/src/qt_gui/kbm_help_dialog.cpp new file mode 100644 index 00000000000..feb24ce5d27 --- /dev/null +++ b/src/qt_gui/kbm_help_dialog.cpp @@ -0,0 +1,101 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "kbm_help_dialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ExpandableSection::ExpandableSection(const QString& title, const QString& content, + QWidget* parent = nullptr) + : QWidget(parent) { + QVBoxLayout* layout = new QVBoxLayout(this); + + // Button to toggle visibility of content + toggleButton = new QPushButton(title); + layout->addWidget(toggleButton); + + // QTextBrowser for content (initially hidden) + contentBrowser = new QTextBrowser(); + contentBrowser->setPlainText(content); + contentBrowser->setVisible(false); + + // Remove scrollbars from QTextBrowser + contentBrowser->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + contentBrowser->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + // Set size policy to allow vertical stretching only + contentBrowser->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + + // Calculate and set initial height based on content + updateContentHeight(); + + layout->addWidget(contentBrowser); + + // Connect button click to toggle visibility + connect(toggleButton, &QPushButton::clicked, [this]() { + contentBrowser->setVisible(!contentBrowser->isVisible()); + if (contentBrowser->isVisible()) { + updateContentHeight(); // Update height when expanding + } + emit expandedChanged(); // Notify for layout adjustments + }); + + // Connect to update height if content changes + connect(contentBrowser->document(), &QTextDocument::contentsChanged, this, + &ExpandableSection::updateContentHeight); + + // Minimal layout settings for spacing + layout->setSpacing(2); + layout->setContentsMargins(0, 0, 0, 0); +} + +HelpDialog::HelpDialog(QWidget* parent) : QDialog(parent) { + // Main layout for the help dialog + QVBoxLayout* mainLayout = new QVBoxLayout(this); + + // Container widget for the scroll area + QWidget* containerWidget = new QWidget; + QVBoxLayout* containerLayout = new QVBoxLayout(containerWidget); + + // Add expandable sections to container layout + auto* quickstartSection = new ExpandableSection("Quickstart", quickstart()); + auto* faqSection = new ExpandableSection("FAQ", faq()); + auto* syntaxSection = new ExpandableSection("Syntax", syntax()); + auto* specialSection = new ExpandableSection("Special Bindings", special()); + auto* bindingsSection = new ExpandableSection("Keybindings", bindings()); + + containerLayout->addWidget(quickstartSection); + containerLayout->addWidget(faqSection); + containerLayout->addWidget(syntaxSection); + containerLayout->addWidget(specialSection); + containerLayout->addWidget(bindingsSection); + containerLayout->addStretch(1); + + // Scroll area wrapping the container + QScrollArea* scrollArea = new QScrollArea; + scrollArea->setWidgetResizable(true); + scrollArea->setWidget(containerWidget); + + // Add the scroll area to the main dialog layout + mainLayout->addWidget(scrollArea); + setLayout(mainLayout); + + // Minimum size for the dialog + setMinimumSize(500, 400); + + // Re-adjust dialog layout when any section expands/collapses + connect(quickstartSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize); + connect(faqSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize); + connect(syntaxSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize); + connect(specialSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize); + connect(bindingsSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize); +} \ No newline at end of file diff --git a/src/qt_gui/kbm_help_dialog.h b/src/qt_gui/kbm_help_dialog.h new file mode 100644 index 00000000000..b6bc6e08604 --- /dev/null +++ b/src/qt_gui/kbm_help_dialog.h @@ -0,0 +1,151 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include +#include +#include +#include +#include + +class ExpandableSection : public QWidget { + Q_OBJECT +public: + explicit ExpandableSection(const QString& title, const QString& content, QWidget* parent); + +signals: + void expandedChanged(); // Signal to indicate layout size change + +private: + QPushButton* toggleButton; + QTextBrowser* contentBrowser; // Changed from QLabel to QTextBrowser + QPropertyAnimation* animation; + int contentHeight; + void updateContentHeight() { + int contentHeight = contentBrowser->document()->size().height(); + contentBrowser->setMinimumHeight(contentHeight + 5); + contentBrowser->setMaximumHeight(contentHeight + 5); + } +}; + +class HelpDialog : public QDialog { + Q_OBJECT +public: + explicit HelpDialog(QWidget* parent = nullptr); + +private: + QString quickstart() { + return + R"(The keyboard remapping backend, GUI and documentation have been written by kalaposfos + +In this section, you will find information about the project, its features and help on setting up your ideal setup. +To view the config file's syntax, check out the Syntax tab, for keybind names, visit Normal Keybinds and Special Bindings, and if you are here to view emulator-wide keybinds, you can find it in the FAQ section. +This project started out because I didn't like the original unchangeable keybinds, but rather than waiting for someone else to do it, I implemented this myself. From the default keybinds, you can clearly tell this was a project built for Bloodborne, but ovbiously you can make adjustments however you like. +)"; + } + QString faq() { + return + R"(Q: What are the emulator-wide keybinds? +A: -F12: Triggers Rdoc capture +-F11: Toggles fullscreen +-F10: Toggles FPS counter +-Ctrl F10: Open the debug menu +-F9: Pauses emultor, if the debug menu is open +-F8: Reparses the config file while in-game +-F7: Toggles mouse capture and mouse input + +Q: How do I change between mouse and controller joystick input, and why is it even required? +A: You can switch between them with F9, and it is required, because mouse input is done with polling, which means mouse movement is checked every frame, and if it didn't move, the code manually sets the emulator's virtual controller to 0 (back to the center), even if other input devices would update it. + +Q: What happens if I accidentally make a typo in the config? +A: The code recognises the line as wrong, and skip it, so the rest of the file will get parsed, but that line in question will be treated like a comment line. + +Q: I want to bind to , but your code doesn't support ! +A: Some keys are intentionally omitted, but if you read the bindings through, and you're sure it is not there and isn't one of the intentionally disabled ones, reach out to me by opening an issue on https://github.com/kalaposfos13/shadPS4 or on Discord (@kalaposfos). +)"; + } + QString syntax() { + return + R"(This is the full list of currently supported mouse and keyboard inputs, and how to use them. +Emulator-reserved keys: F1 through F12, Insert, PrintScreen, Delete, Home, End, PgUp, PgDown + +Syntax (aka how a line can look like): +#Comment line + = , , ; + = , ; + = ; + +Examples: +#Interact +cross = e; +#Heavy attack (in BB) +r2 = leftbutton, lshift; +#Move forward +axis_left_y_minus = w; + +You can make a comment line by putting # as the first character. +Whitespace doesn't matter,