[PR #1356] [MERGED] Added keyboard and mouse input remapping, mouse movement to joystick logic, GUI and more #2066

Closed
opened 2026-02-27 21:15:03 +03:00 by kerem · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/shadps4-emu/shadPS4/pull/1356
Author: @kalaposfos13
Created: 10/12/2024
Status: Merged
Merged: 1/31/2025
Merged by: @georgemoralis

Base: mainHead: main


📝 Commits (10+)

  • 81e0f14 added support for loading keyboard config from file
  • 94c0764 final minor update before pull request
  • 37dcdce fix messing up the merge
  • f6d54bf fix waitEvent to correctly handle mouse inputs
  • 3dda62f add license
  • 9820022 Applied coding style fixes
  • 22e4ab8 clang-format fucked up the .ini file
  • 31caf01 Merge branch 'shadps4-emu:main' into main
  • 45f05c0 actually fix clang changing ini syntax
  • b15810d remove big commented out code blocks,

📊 Changes

17 files changed (+1994 additions, -284 deletions)

View changed files

📝 CMakeLists.txt (+8 -0)
📝 README.md (+29 -27)
📝 src/common/config.cpp (+106 -15)
📝 src/common/config.h (+3 -2)
📝 src/core/libraries/pad/pad.cpp (+4 -4)
📝 src/imgui/renderer/imgui_core.cpp (+1 -1)
src/input/input_handler.cpp (+676 -0)
src/input/input_handler.h (+407 -0)
src/input/input_mouse.cpp (+74 -0)
src/input/input_mouse.h (+18 -0)
src/qt_gui/kbm_config_dialog.cpp (+237 -0)
src/qt_gui/kbm_config_dialog.h (+38 -0)
src/qt_gui/kbm_help_dialog.cpp (+112 -0)
src/qt_gui/kbm_help_dialog.h (+169 -0)
📝 src/qt_gui/main_window.cpp (+10 -0)
📝 src/sdl_window.cpp (+99 -233)
📝 src/sdl_window.h (+3 -2)

📄 Description

An updated overview of the PR as of 2 months later, since so much has changed that not a lot remains from the original version:

The current state of input handling

  • Most controllers work out of the box, with Xbox controllers' back button emulating a touchpad press as well.
  • However, these are the default bindings, and they are unchangeable.
  • Keyboard inputs are technically supported, but only as single buttons, you can't rebind them and the configuration is basically unplayabe.
  • You can't use the mouse at all.

I decided that since more and more games are finally becoming more and more playable, an update to this system is really needed, as a core part of PC gaming is the ability to rebind controls however you want, and a lot of people prefer using KBM over controller.

An overview of the changes

  • I added the ability to rebind your mouse, keyboard and controller inputs, with up to 3 inputs per output.
  • You can create a custom configuration for every game in your library.
  • I added a GUI for this (accessed by the previously unused Controller button) where you can edit your bindings straight from the launcher. You can even reload the configuration mid-game, giving you the ability to change keybinds without restarting the emulator.
  • I added an implementation of mouse-to-joystick emulation, making controlling the camera in games like Bloodborne with your mouse movement possible.
  • A more detailed user manual can be found by clicking the Help button in the aforementioned config editor.

A technical overview of the control flow of the new input handling system

  1. Upon launching a game, the config is read in from the correct file. Next, the main SDL event handling loop is started. A separate timer is also created for mouse polling, which runs on a completely different system than everything else.
  2. The event handling loop waits for an event. If one is found, and it is a controller, keyboard or mouse (button or wheel) event, the main part of input handling starts.
  3. Based on the event, a custom input ID is calculated (these are just the SDL ID-s but with an offset based on which device it is, as all of them start at 0). For analog inputs, the distance is also stored.
  4. Next, we add or remove this ID based on the event type to the list of currently active inputs (for example, we add it if it's a keydown, but remove it if it's a keyup event). If that list changed (holding down a keyboard button will generate multiple keydown events, for example, so not every event changes the list), we recalculate the state of the emulated controller, otherwise, we finish the handling of this event here.
  5. If the list changed, the following things happen: First, we reset the "new" state of the controller (from now on, this refers to the emulated one). It has two states: the actual and the "new", and the later is used by the algorithm, and when it finishes, changes the actual state to the newly calculated state.
  6. We then iterate over the list of all bindings. This is a sorted list, with the bindings whose inputs have more keys being higher priority than those with less. (example: [a, b] > [c] and [a, b] < [c, d, e]). For every binding, we check if all of its input ID-s are in the list of active ID-s, and if so, we flag them as "used" (The list actually stores ID - bool pairs, and the flag is reset to false every new input frame). If an input's all ID-s are found, but all of them are "used", that means the input is overridden by another one (example: [w, lalt] overrides [w], so pressing [w, lalt] doesn't activate both). This is why the bindings being sorted matters.
  7. If a binding's input is determined to be valid and not overridden, we then update the corresponding output's "new" state. If it's a button, we set its "button pressed" flag to true, meaning that if any of the inputs bound to this is active, it will be pressed, and only becomes unpressed when all of those are. If it's an axis, we add the offset that is stored in the binding to it (That is either +-127 if it's a button input, or the value we read in with the input ID, and if one of the inputs is analog (you can bind an axis and a button to an axis, and that makes that axis only activate if the button is help as well)) we pass the value from that. This is what makes WASD feel much better, as now holding A and D now centers the joystick, since one adds 127 and the other adds -127, canceling each other out.
  8. The actual controller state is updated from the new controller state.

This explanation leaves things like halfmode_joystick and key_toggle handling out, but it is already quite complicated without those.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/shadps4-emu/shadPS4/pull/1356 **Author:** [@kalaposfos13](https://github.com/kalaposfos13) **Created:** 10/12/2024 **Status:** ✅ Merged **Merged:** 1/31/2025 **Merged by:** [@georgemoralis](https://github.com/georgemoralis) **Base:** `main` ← **Head:** `main` --- ### 📝 Commits (10+) - [`81e0f14`](https://github.com/shadps4-emu/shadPS4/commit/81e0f143cc602a851c9e86e7dc937d288645f64c) added support for loading keyboard config from file - [`94c0764`](https://github.com/shadps4-emu/shadPS4/commit/94c076494ae4d3061a57959eb90c3b3dbad3054d) final minor update before pull request - [`37dcdce`](https://github.com/shadps4-emu/shadPS4/commit/37dcdcec3978b1350ac80212037fd8de87894b10) fix messing up the merge - [`f6d54bf`](https://github.com/shadps4-emu/shadPS4/commit/f6d54bf75c28e60e9028fded421047cb6861d589) fix waitEvent to correctly handle mouse inputs - [`3dda62f`](https://github.com/shadps4-emu/shadPS4/commit/3dda62fcba19135414ebaacd01d30e945f142e7a) add license - [`9820022`](https://github.com/shadps4-emu/shadPS4/commit/98200221f59a656b218f3f781073e67c2762c399) Applied coding style fixes - [`22e4ab8`](https://github.com/shadps4-emu/shadPS4/commit/22e4ab866bd9e5019b3055d5682de45dd89a07cd) clang-format fucked up the .ini file - [`31caf01`](https://github.com/shadps4-emu/shadPS4/commit/31caf01366153c187aafe60c58ed9b8e9677c202) Merge branch 'shadps4-emu:main' into main - [`45f05c0`](https://github.com/shadps4-emu/shadPS4/commit/45f05c067d1175c208e546ea61c0d3142e64471c) actually fix clang changing ini syntax - [`b15810d`](https://github.com/shadps4-emu/shadPS4/commit/b15810d56f44e199aeb7fd67e660beffa6262e45) remove big commented out code blocks, ### 📊 Changes **17 files changed** (+1994 additions, -284 deletions) <details> <summary>View changed files</summary> 📝 `CMakeLists.txt` (+8 -0) 📝 `README.md` (+29 -27) 📝 `src/common/config.cpp` (+106 -15) 📝 `src/common/config.h` (+3 -2) 📝 `src/core/libraries/pad/pad.cpp` (+4 -4) 📝 `src/imgui/renderer/imgui_core.cpp` (+1 -1) ➕ `src/input/input_handler.cpp` (+676 -0) ➕ `src/input/input_handler.h` (+407 -0) ➕ `src/input/input_mouse.cpp` (+74 -0) ➕ `src/input/input_mouse.h` (+18 -0) ➕ `src/qt_gui/kbm_config_dialog.cpp` (+237 -0) ➕ `src/qt_gui/kbm_config_dialog.h` (+38 -0) ➕ `src/qt_gui/kbm_help_dialog.cpp` (+112 -0) ➕ `src/qt_gui/kbm_help_dialog.h` (+169 -0) 📝 `src/qt_gui/main_window.cpp` (+10 -0) 📝 `src/sdl_window.cpp` (+99 -233) 📝 `src/sdl_window.h` (+3 -2) </details> ### 📄 Description An updated overview of the PR as of 2 months later, since so much has changed that not a lot remains from the original version: The current state of input handling - - Most controllers work out of the box, with Xbox controllers' back button emulating a touchpad press as well. - However, these are the default bindings, and they are unchangeable. - Keyboard inputs are technically supported, but only as single buttons, you can't rebind them and the configuration is basically unplayabe. - You can't use the mouse at all. I decided that since more and more games are finally becoming more and more playable, an update to this system is really needed, as a core part of PC gaming is the ability to rebind controls however you want, and a lot of people prefer using KBM over controller. An overview of the changes - - I added the ability to rebind your mouse, keyboard and controller inputs, with up to 3 inputs per output. - You can create a custom configuration for every game in your library. - I added a GUI for this (accessed by the previously unused Controller button) where you can edit your bindings straight from the launcher. You can even reload the configuration mid-game, giving you the ability to change keybinds without restarting the emulator. - I added an implementation of mouse-to-joystick emulation, making controlling the camera in games like Bloodborne with your mouse movement possible. - A more detailed user manual can be found by clicking the Help button in the aforementioned config editor. A technical overview of the control flow of the new input handling system - 0. Upon launching a game, the config is read in from the correct file. Next, the main SDL event handling loop is started. A separate timer is also created for mouse polling, which runs on a completely different system than everything else. 1. The event handling loop waits for an event. If one is found, and it is a controller, keyboard or mouse (button or wheel) event, the main part of input handling starts. 2. Based on the event, a custom input ID is calculated (these are just the SDL ID-s but with an offset based on which device it is, as all of them start at 0). For analog inputs, the distance is also stored. 3. Next, we add or remove this ID based on the event type to the list of currently active inputs (for example, we add it if it's a keydown, but remove it if it's a keyup event). If that list changed (holding down a keyboard button will generate multiple keydown events, for example, so not every event changes the list), we recalculate the state of the emulated controller, otherwise, we finish the handling of this event here. 4. If the list changed, the following things happen: First, we reset the "new" state of the controller (from now on, this refers to the emulated one). It has two states: the actual and the "new", and the later is used by the algorithm, and when it finishes, changes the actual state to the newly calculated state. 5. We then iterate over the list of all bindings. This is a sorted list, with the bindings whose inputs have more keys being higher priority than those with less. (example: [a, b] > [c] and [a, b] < [c, d, e]). For every binding, we check if all of its input ID-s are in the list of active ID-s, and if so, we flag them as "used" (The list actually stores ID - bool pairs, and the flag is reset to false every new input frame). If an input's all ID-s are found, but all of them are "used", that means the input is overridden by another one (example: [w, lalt] overrides [w], so pressing [w, lalt] doesn't activate both). This is why the bindings being sorted matters. 6. If a binding's input is determined to be valid and not overridden, we then update the corresponding output's "new" state. If it's a button, we set its "button pressed" flag to true, meaning that if any of the inputs bound to this is active, it will be pressed, and only becomes unpressed when all of those are. If it's an axis, we add the offset that is stored in the binding to it (That is either +-127 if it's a button input, or the value we read in with the input ID, and if one of the inputs is analog (you can bind an axis and a button to an axis, and that makes that axis only activate if the button is help as well)) we pass the value from that. This is what makes WASD feel much better, as now holding A and D now centers the joystick, since one adds 127 and the other adds -127, canceling each other out. 7. The actual controller state is updated from the new controller state. This explanation leaves things like halfmode_joystick and key_toggle handling out, but it is already quite complicated without those. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
kerem 2026-02-27 21:15:03 +03:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/shadPS4#2066
No description provided.