Skip to content

Commit c4bfaa6

Browse files
authored
Added keyboard and mouse input remapping, mouse movement to joystick logic, GUI and more (#1356)
* added support for loading keyboard config from file * final minor update before pull request * fix messing up the merge * fix waitEvent to correctly handle mouse inputs * add license * Applied coding style fixes * clang-format fucked up the .ini file * actually fix clang changing ini syntax use relative path for the ini file * remove big commented out code blocks, and fixed platform-dependent code * fix windows hating me * added mouse config option * added toggle for mouse movement input (f7) * fix license and style * add numpad support i accidentally left out * added support for mouse wheel (to buttons only) * if keyboard config doesn't exist, autogenerate it * added keybinds for "walk mode" * Mouse movement input is now off by default * code cleanup and misc fixes * delete config file since it is now autogenerated * F6 = F7 + F9 * added better mouse handling with config options * Added capslock support * fix clang-format * Added support for mod key toggle key * F6 and F7 are removed, F9 captures and enables the mouse * Encapsulated globals and new classes in a new namespace * Added mouse side button support * Added per-game config * relocated input parser to the new namespace * changed parser parameters to make it possible to use it from the gui * added home, end, pgup and pgdown * Resolved merge conflict and refactored code * Updated default keybindings * Changed input handling to be single-threaded * General code cleanup * Start working on new backend * Mouse polling, CMakeLists, and basic framework * Output update handling, and reworked file creating, reading and parsing * Parsing works now * Single key button inputs work now * Axis outputs work now * Wheel works now (for me), l2/r2 handling improvements, and misc bugfixes * Downgraded prints to log_debug, and implemented input hierarchy * Implemented key toggle * Added mouse parameter parsing * clang-format * Fixed clang and added a const keyword for mac * Fix input hierarchy * Fixed joysick halfmodes, and possibly the last update on input hierarchy * clang-format * Rewrote the default config to reflect new changes * clang * Update code style * Updated sorting to accomodate for that one specific edge case * Fix default config and the latest bug with input hiearchy * Fix typo * Temporarily added my GUI * Update cmakelists * Possible fix for Gravity Rush * Update Help text, default config, and clang * Updated README with the new keybind info * okay so maybe the gravity rush fix might have slightly broken the joystick halfmode and key toggle * Fixed mistakenly overwriting the last opened config with the default one if the GUI is opened multiple times in a session * Updated Help descriptions and fixed mouse movement default parameters * Fix crash if the Help dialog was opened a second time If it's closed with the top right close button instead of clicking the Help button again, a required flag wasn't reset, making the next click on Help try to close a nonexistent window and segfault * Added closing the config also closing the Help window, and fixed more segfaults due to mismatched flags * Initial controller support * clang and debug print cleanup * Initial axis-to-button logic * Updated Help text * Added 'Reset to Default' button in GUI * Minor text and description updates + fixed an issue with Help text box rendering * Fix button-to-touchpad logic and l2/r2 handling, as they are both axes and buttons The touchpad's button state was correctly handled, so games that use that were fine, but the touchDown flag was always set to true, so games that use this flag had problems, like Gravity Rush * Fix merge conflict * Clang * Added back back button to touchpad binding * Added touchpad button handling * Added end-of-line comments and fixed some crashes happening with the VS debugger * Apply recent changes from kbm-only * Deadzone + initial directional axis-to-button mapping * Added that one missing space in the README. Are you all happy now? * Fixups from making everything use SDL * Revert directional joystick code and fix a memory leak * Change config directory name again to conform to project standards * Clang * Revert the old deeadzone code and properly add the new one * Clang
1 parent f3810ce commit c4bfaa6

17 files changed

+1994
-284
lines changed

CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,10 @@ set(IMGUI src/imgui/imgui_config.h
854854

855855
set(INPUT src/input/controller.cpp
856856
src/input/controller.h
857+
src/input/input_handler.cpp
858+
src/input/input_handler.h
859+
src/input/input_mouse.cpp
860+
src/input/input_mouse.h
857861
)
858862

859863
set(EMULATOR src/emulator.cpp
@@ -903,6 +907,10 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
903907
src/qt_gui/trophy_viewer.h
904908
src/qt_gui/elf_viewer.cpp
905909
src/qt_gui/elf_viewer.h
910+
src/qt_gui/kbm_config_dialog.cpp
911+
src/qt_gui/kbm_config_dialog.h
912+
src/qt_gui/kbm_help_dialog.cpp
913+
src/qt_gui/kbm_help_dialog.h
906914
src/qt_gui/main_window_themes.cpp
907915
src/qt_gui/main_window_themes.h
908916
src/qt_gui/settings_dialog.cpp

README.md

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ Check the build instructions for [**macOS**](https://github.com/shadps4-emu/shad
7777

7878
For more information on how to test, debug and report issues with the emulator or games, read the [**Debugging documentation**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md).
7979

80-
# Keyboard mapping
80+
# Keyboard and Mouse Mappings
8181

8282
> [!NOTE]
8383
> Some keyboards may also require you to hold the Fn key to use the F\* keys. Mac users should use the Command key instead of Control, and need to use Command+F11 for full screen to avoid conflicting with system key bindings.
@@ -92,32 +92,34 @@ F12 | Trigger RenderDoc Capture
9292
> [!NOTE]
9393
> Xbox and DualShock controllers work out of the box.
9494
95-
| Controller button | Keyboard equivalent |
96-
|-------------|-------------|
97-
LEFT AXIS UP | W |
98-
LEFT AXIS DOWN | S |
99-
LEFT AXIS LEFT | A |
100-
LEFT AXIS RIGHT | D |
101-
RIGHT AXIS UP | I |
102-
RIGHT AXIS DOWN | K |
103-
RIGHT AXIS LEFT | J |
104-
RIGHT AXIS RIGHT | L |
105-
TRIANGLE | Numpad 8 or C |
106-
CIRCLE | Numpad 6 or B |
107-
CROSS | Numpad 2 or N |
108-
SQUARE | Numpad 4 or V |
109-
PAD UP | UP |
110-
PAD DOWN | DOWN |
111-
PAD LEFT | LEFT |
112-
PAD RIGHT | RIGHT |
113-
OPTIONS | RETURN |
114-
BACK BUTTON / TOUCH PAD | SPACE |
115-
L1 | Q |
116-
R1 | U |
117-
L2 | E |
118-
R2 | O |
119-
L3 | X |
120-
R3 | M |
95+
The default controls are inspired by the *Elden Ring* PC controls. Inputs support up to three keys per binding, mouse buttons, mouse movement mapped to joystick input, and more.
96+
97+
| Action | Default Key(s) |
98+
|-------------|-----------------------------|
99+
| Triangle | F |
100+
| Circle | Space |
101+
| Cross | E |
102+
| Square | R |
103+
| Pad Up | W, LAlt / Mouse Wheel Up |
104+
| Pad Down | S, LAlt / Mouse Wheel Down |
105+
| Pad Left | A, LAlt / Mouse Wheel Left |
106+
| Pad Right | D, LAlt / Mouse Wheel Right |
107+
| L1 | Right Button, LShift |
108+
| R1 | Left Button |
109+
| L2 | Right Button |
110+
| R2 | Left Button, LShift |
111+
| L3 | X |
112+
| R3 | Q / Middle Button |
113+
| Options | Escape |
114+
| Touchpad | G |
115+
116+
| Joystick | Default Input |
117+
|--------------------|----------------|
118+
| Left Joystick | WASD |
119+
| Right Joystick | Mouse movement |
120+
121+
Keyboard and mouse inputs can be customized in the settings menu by clicking the Controller button, and further details and help on controls are also found there. Custom bindings are saved per-game.
122+
121123

122124
# Main team
123125

src/common/config.cpp

Lines changed: 106 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ static std::string logType = "async";
4646
static std::string userName = "shadPS4";
4747
static std::string updateChannel;
4848
static std::string chooseHomeTab;
49-
static u16 deadZoneLeft = 2.0;
50-
static u16 deadZoneRight = 2.0;
5149
static std::string backButtonBehavior = "left";
5250
static bool useSpecialPad = false;
5351
static int specialPadClass = 1;
@@ -151,14 +149,6 @@ bool getEnableDiscordRPC() {
151149
return enableDiscordRPC;
152150
}
153151

154-
u16 leftDeadZone() {
155-
return deadZoneLeft;
156-
}
157-
158-
u16 rightDeadZone() {
159-
return deadZoneRight;
160-
}
161-
162152
s16 getCursorState() {
163153
return cursorState;
164154
}
@@ -661,8 +651,6 @@ void load(const std::filesystem::path& path) {
661651
if (data.contains("Input")) {
662652
const toml::value& input = data.at("Input");
663653

664-
deadZoneLeft = toml::find_or<float>(input, "deadZoneLeft", 2.0);
665-
deadZoneRight = toml::find_or<float>(input, "deadZoneRight", 2.0);
666654
cursorState = toml::find_or<int>(input, "cursorState", HideCursorState::Idle);
667655
cursorHideTimeout = toml::find_or<int>(input, "cursorHideTimeout", 5);
668656
backButtonBehavior = toml::find_or<std::string>(input, "backButtonBehavior", "left");
@@ -785,8 +773,6 @@ void save(const std::filesystem::path& path) {
785773
data["General"]["separateUpdateEnabled"] = separateupdatefolder;
786774
data["General"]["compatibilityEnabled"] = compatibilityData;
787775
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
788-
data["Input"]["deadZoneLeft"] = deadZoneLeft;
789-
data["Input"]["deadZoneRight"] = deadZoneRight;
790776
data["Input"]["cursorState"] = cursorState;
791777
data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
792778
data["Input"]["backButtonBehavior"] = backButtonBehavior;
@@ -919,4 +905,109 @@ void setDefaultValues() {
919905
checkCompatibilityOnStartup = false;
920906
}
921907

922-
} // namespace Config
908+
constexpr std::string_view GetDefaultKeyboardConfig() {
909+
return R"(#Feeling lost? Check out the Help section!
910+
911+
#Keyboard bindings
912+
913+
triangle = f
914+
circle = space
915+
cross = e
916+
square = r
917+
918+
pad_up = w, lalt
919+
pad_up = mousewheelup
920+
pad_down = s, lalt
921+
pad_down = mousewheeldown
922+
pad_left = a, lalt
923+
pad_left = mousewheelleft
924+
pad_right = d, lalt
925+
pad_right = mousewheelright
926+
927+
l1 = rightbutton, lshift
928+
r1 = leftbutton
929+
l2 = rightbutton
930+
r2 = leftbutton, lshift
931+
l3 = x
932+
r3 = q
933+
r3 = middlebutton
934+
935+
options = escape
936+
touchpad = g
937+
938+
key_toggle = i, lalt
939+
mouse_to_joystick = right
940+
mouse_movement_params = 0.5, 1, 0.125
941+
leftjoystick_halfmode = lctrl
942+
943+
axis_left_x_minus = a
944+
axis_left_x_plus = d
945+
axis_left_y_minus = w
946+
axis_left_y_plus = s
947+
948+
#Controller bindings
949+
950+
triangle = triangle
951+
cross = cross
952+
square = square
953+
circle = circle
954+
955+
l1 = l1
956+
l2 = l2
957+
l3 = l3
958+
r1 = r1
959+
r2 = r2
960+
r3 = r3
961+
962+
pad_up = pad_up
963+
pad_down = pad_down
964+
pad_left = pad_left
965+
pad_right = pad_right
966+
967+
options = options
968+
touchpad = back
969+
970+
axis_left_x = axis_left_x
971+
axis_left_y = axis_left_y
972+
973+
axis_right_x = axis_right_x
974+
axis_right_y = axis_right_y
975+
)";
976+
}
977+
std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id) {
978+
// Read configuration file of the game, and if it doesn't exist, generate it from default
979+
// If that doesn't exist either, generate that from getDefaultConfig() and try again
980+
// If even the folder is missing, we start with that.
981+
982+
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "input_config";
983+
const auto config_file = config_dir / (game_id + ".ini");
984+
const auto default_config_file = config_dir / "default.ini";
985+
986+
// Ensure the config directory exists
987+
if (!std::filesystem::exists(config_dir)) {
988+
std::filesystem::create_directories(config_dir);
989+
}
990+
991+
// Check if the default config exists
992+
if (!std::filesystem::exists(default_config_file)) {
993+
// If the default config is also missing, create it from getDefaultConfig()
994+
const auto default_config = GetDefaultKeyboardConfig();
995+
std::ofstream default_config_stream(default_config_file);
996+
if (default_config_stream) {
997+
default_config_stream << default_config;
998+
}
999+
}
1000+
1001+
// if empty, we only need to execute the function up until this point
1002+
if (game_id.empty()) {
1003+
return default_config_file;
1004+
}
1005+
1006+
// If game-specific config doesn't exist, create it from the default config
1007+
if (!std::filesystem::exists(config_file)) {
1008+
std::filesystem::copy(default_config_file, config_file);
1009+
}
1010+
return config_file;
1011+
}
1012+
1013+
} // namespace Config

src/common/config.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ std::string getUserName();
3737
std::string getUpdateChannel();
3838
std::string getChooseHomeTab();
3939

40-
u16 leftDeadZone();
41-
u16 rightDeadZone();
4240
s16 getCursorState();
4341
int getCursorHideTimeout();
4442
std::string getBackButtonBehavior();
@@ -152,6 +150,9 @@ std::string getEmulatorLanguage();
152150

153151
void setDefaultValues();
154152

153+
// todo: name and function location pending
154+
std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id = "");
155+
155156
// settings
156157
u32 GetLanguage();
157158
}; // namespace Config

src/core/libraries/pad/pad.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ int PS4_SYSV_ABI scePadGetControllerInformation(s32 handle, OrbisPadControllerIn
9595
pInfo->touchPadInfo.pixelDensity = 1;
9696
pInfo->touchPadInfo.resolution.x = 1920;
9797
pInfo->touchPadInfo.resolution.y = 950;
98-
pInfo->stickInfo.deadZoneLeft = Config::leftDeadZone();
99-
pInfo->stickInfo.deadZoneRight = Config::rightDeadZone();
98+
pInfo->stickInfo.deadZoneLeft = 1;
99+
pInfo->stickInfo.deadZoneRight = 1;
100100
pInfo->connectionType = ORBIS_PAD_PORT_TYPE_STANDARD;
101101
pInfo->connectedCount = 1;
102102
pInfo->connected = false;
@@ -106,8 +106,8 @@ int PS4_SYSV_ABI scePadGetControllerInformation(s32 handle, OrbisPadControllerIn
106106
pInfo->touchPadInfo.pixelDensity = 1;
107107
pInfo->touchPadInfo.resolution.x = 1920;
108108
pInfo->touchPadInfo.resolution.y = 950;
109-
pInfo->stickInfo.deadZoneLeft = Config::leftDeadZone();
110-
pInfo->stickInfo.deadZoneRight = Config::rightDeadZone();
109+
pInfo->stickInfo.deadZoneLeft = 1;
110+
pInfo->stickInfo.deadZoneRight = 1;
111111
pInfo->connectionType = ORBIS_PAD_PORT_TYPE_STANDARD;
112112
pInfo->connectedCount = 1;
113113
pInfo->connected = true;

src/imgui/renderer/imgui_core.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ bool ProcessEvent(SDL_Event* event) {
148148
case SDL_EVENT_MOUSE_BUTTON_DOWN: {
149149
const auto& io = GetIO();
150150
return io.WantCaptureMouse && io.Ctx->NavWindow != nullptr &&
151-
io.Ctx->NavWindow->ID != dock_id;
151+
(io.Ctx->NavWindow->Flags & ImGuiWindowFlags_NoNav) == 0;
152152
}
153153
case SDL_EVENT_TEXT_INPUT:
154154
case SDL_EVENT_KEY_DOWN: {

0 commit comments

Comments
 (0)