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);