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 01/11] 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 000000000..c769752ea --- /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 000000000..a97922004 --- /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 02/11] 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 e0e877a52..f5d50c6b1 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 c769752ea..62be8f590 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 a97922004..075a3996e 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 ad7d1b4a6..c81a495fe 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 ec8de354b..ad27ba4a5 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -72,7 +72,7 @@ public: 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 03/11] 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 1dde7223c..3a926bc97 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 9c71c96a8..3dfafade7 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 62be8f590..72e872550 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. + + const auto config_file = Config::getFoolproofKbmConfigFile(game_id); - // 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()) { + // 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 075a3996e..7dc3453ea 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 @@ public: 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 @@ public: // 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 04/11] 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 72e872550..8883d1099 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 7dc3453ea..2857d1c14 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 @@ public: // 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 @@ public: 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 @@ public: }; // 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 c81a495fe..cfa0e3eb3 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 ad27ba4a5..1c298682f 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 05/11] Single key button inputs work now --- src/input/input_handler.cpp | 184 +++++++++++++++++------------- src/input/input_handler.h | 10 +- src/sdl_window.cpp | 220 +++++------------------------------- 3 files changed, 144 insertions(+), 270 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 8883d1099..c72689c07 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(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT), + ControllerOutput(OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT), - ControllerOutput(0, Axis::TriggerLeft), - ControllerOutput(0, Axis::LeftY), - // etc. + // 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), - // signifies the end of the array - ControllerOutput(0, Axis::AxisMax), + 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 2857d1c14..73ad461cb 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 @@ public: }; -// 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 cfa0e3eb3..e7dfbae07 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; + // 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_D: - axis = Input::Axis::LeftX; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += 127; - } 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(-0x80, 0x80, axisvalue); - break; - case SDLK_W: - axis = Input::Axis::LeftY; - if (event->type == SDL_EVENT_KEY_DOWN) { - axisvalue += -127; - } else { - axisvalue = 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); } - 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 + // 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 06/11] Axis outputs work now --- src/input/input_handler.cpp | 129 ++++++++++++++++++++++++++++++------ src/input/input_handler.h | 23 +++---- src/sdl_window.cpp | 15 +++++ 3 files changed, 132 insertions(+), 35 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index c72689c07..2655c110e 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,18 +299,77 @@ 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)); + //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, -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; + } + 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!"); + } +} void updatePressedKeys(u32 value, bool is_pressed) { if (is_pressed) { @@ -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 73ad461cb..0f3291b96 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 @@ public: } // 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 @@ public: 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 @@ public: 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 @@ public: 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 e7dfbae07..8ff2f14f1 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 07/11] 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 2655c110e..50b924ccc 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 0f3291b96..175d2b23f 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 @@ public: 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 @@ public: 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 8ff2f14f1..21f266931 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 08/11] Downgraded prints to log_debug, and implemented input hierarchy --- src/input/input_handler.cpp | 107 +++++++++++++++++++++--------------- src/input/input_handler.h | 13 ++++- src/sdl_window.cpp | 1 - 3 files changed, 73 insertions(+), 48 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 50b924ccc..de3239b84 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(); + bool* flag1 = nullptr; + bool* flag2 = nullptr; + bool* flag3 = nullptr; - 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 + // 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 175d2b23f..7001b7152 100644 --- a/src/input/input_handler.h +++ b/src/input/input_handler.h @@ -218,10 +218,17 @@ public: // 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 @@ public: // 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 21f266931..62c202934 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 09/11] 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 de3239b84..6a54d233c 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 7001b7152..09929d358 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 @@ public: 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 10/11] 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 6a54d233c..77bd1c34c 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 11/11] clang-format --- src/input/input_handler.cpp | 184 ++++++++++++++++++++---------------- src/input/input_handler.h | 65 ++++++++----- src/sdl_window.cpp | 7 +- src/sdl_window.h | 2 +- 4 files changed, 146 insertions(+), 112 deletions(-) diff --git a/src/input/input_handler.cpp b/src/input/input_handler.cpp index 77bd1c34c..556ce3e97 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(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(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; + 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)); + 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 09929d358..cd752e967 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 @@ public: // 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 62c202934..acd34bc2d 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 1c298682f..4266165c1 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;