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.