From d6b2fa652af37ac68124fe18bb21ca0f986655a3 Mon Sep 17 00:00:00 2001 From: Julio Centeno Date: Tue, 12 May 2026 17:29:42 -0300 Subject: [PATCH] Mouse mapping --- include/dolphin/pad.h | 4 ++ lib/dolphin/pad/pad.cpp | 97 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/include/dolphin/pad.h b/include/dolphin/pad.h index 180352894a..dd14bbc1a4 100644 --- a/include/dolphin/pad.h +++ b/include/dolphin/pad.h @@ -135,6 +135,10 @@ void PADSetAnalogMode(u32 mode); #define PAD_KEY_MOUSE_RIGHT (-4) #define PAD_KEY_MOUSE_X1 (-5) #define PAD_KEY_MOUSE_X2 (-6) +#define PAD_KEY_MOUSE_AXIS_X_POS (-7) +#define PAD_KEY_MOUSE_AXIS_X_NEG (-8) +#define PAD_KEY_MOUSE_AXIS_Y_POS (-9) +#define PAD_KEY_MOUSE_AXIS_Y_NEG (-10) typedef u16 PADButton; typedef u32 PADExtButton; typedef u16 PADAxis; diff --git a/lib/dolphin/pad/pad.cpp b/lib/dolphin/pad/pad.cpp index a596ac35b3..39f3b531f9 100644 --- a/lib/dolphin/pad/pad.cpp +++ b/lib/dolphin/pad/pad.cpp @@ -7,8 +7,11 @@ #include #include +#include +#include "../../window.hpp" + namespace { -constexpr int32_t k_mappingsFileVersion = 3; +constexpr int32_t k_mappingsFileVersion = 4; std::array g_defaultButtonsStandard{{ {SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_A}, @@ -289,6 +292,9 @@ std::array g_suppressLeftTrigger{}; std::array g_suppressRightTrigger{}; bool is_mouse_scancode(s32 scancode) { return scancode < PAD_KEY_INVALID; } +bool is_mouse_axis_scancode(s32 scancode) { + return scancode <= PAD_KEY_MOUSE_AXIS_X_POS && scancode >= PAD_KEY_MOUSE_AXIS_Y_NEG; +} bool is_mouse_button_pressed(s32 scancode) { const int32_t buttonNum = -(scancode + 1); if (buttonNum < 1 || buttonNum > 5) { @@ -590,7 +596,35 @@ static void apply_unblock_suppression(PADStatus& status, u32 port, bool captureH } } +static void update_relative_mouse_mode() { + static bool sRelativeMouseMode = false; + bool shouldBeRelative = false; + if (!g_blockPAD) { + for (uint32_t i = 0; i < PAD_CHANMAX; ++i) { + if (g_keyboardBindings[i].m_mappingsSet) { + for (const auto& binding : g_keyboardBindings[i].m_axisMapping) { + if (is_mouse_axis_scancode(binding.scancode)) { + shouldBeRelative = true; + break; + } + } + } + if (shouldBeRelative) + break; + } + } + + if (shouldBeRelative != sRelativeMouseMode) { + SDL_Window* window = aurora::window::get_sdl_window(); + if (window) { + SDL_SetWindowRelativeMouseMode(window, shouldBeRelative); + sRelativeMouseMode = shouldBeRelative; + } + } +} + uint32_t PADRead(PADStatus* status) { + update_relative_mouse_mode(); if (!g_keyboardBindingsLoaded) { g_keyboardBindingsLoaded = true; load_keyboard_bindings(); @@ -601,6 +635,11 @@ uint32_t PADRead(PADStatus* status) { const bool captureHeldInput = g_suppressHeldOnRead && !g_blockPAD; g_suppressHeldOnRead = false; + float mouseDx = 0, mouseDy = 0; + if (!g_blockPAD) { + SDL_GetRelativeMouseState(&mouseDx, &mouseDy); + } + uint32_t rumbleSupport = 0; for (uint32_t i = 0; i < PAD_CHANMAX; ++i) { memset(&status[i], 0, sizeof(PADStatus)); @@ -629,6 +668,60 @@ uint32_t PADRead(PADStatus* status) { bool pressed = false; if (binding.scancode > PAD_KEY_INVALID) { pressed = binding.scancode < numKeys && kbState[binding.scancode]; + } else if (is_mouse_axis_scancode(binding.scancode)) { + float delta = 0; + switch (binding.scancode) { + case PAD_KEY_MOUSE_AXIS_X_POS: + delta = std::max(0.0f, mouseDx); + break; + case PAD_KEY_MOUSE_AXIS_X_NEG: + delta = std::max(0.0f, -mouseDx); + break; + case PAD_KEY_MOUSE_AXIS_Y_POS: + delta = std::max(0.0f, -mouseDy); + break; + case PAD_KEY_MOUSE_AXIS_Y_NEG: + delta = std::max(0.0f, mouseDy); + break; + } + if (delta > 0) { + // Apply a slight curve to the sensitivity: amount = (delta^1.1) * 5.0 + // This makes slow movements precise and fast movements reach the 127 cap more naturally. + int amount = std::clamp(static_cast(std::pow(delta, 1.1f) * 5.0f), 0, 127); + switch (binding.padAxis) { + case PAD_AXIS_LEFT_X_POS: + lx += amount; + break; + case PAD_AXIS_LEFT_X_NEG: + lx -= amount; + break; + case PAD_AXIS_LEFT_Y_POS: + ly += amount; + break; + case PAD_AXIS_LEFT_Y_NEG: + ly -= amount; + break; + case PAD_AXIS_RIGHT_X_POS: + rx += amount; + break; + case PAD_AXIS_RIGHT_X_NEG: + rx -= amount; + break; + case PAD_AXIS_RIGHT_Y_POS: + ry += amount; + break; + case PAD_AXIS_RIGHT_Y_NEG: + ry -= amount; + break; + case PAD_AXIS_TRIGGER_L: + tl += static_cast(delta * 16.0f); + break; + case PAD_AXIS_TRIGGER_R: + tr += static_cast(delta * 16.0f); + break; + } + } + continue; } else if (is_mouse_scancode(binding.scancode)) { pressed = is_mouse_button_pressed(binding.scancode); } @@ -1145,7 +1238,7 @@ void PADClearKeyBindings(u32 port) { } constexpr uint32_t k_keyboardMagic = SBIG('KBND'); -constexpr int32_t k_keyboardVersion = 3; +constexpr int32_t k_keyboardVersion = 4; static void load_keyboard_bindings() { std::filesystem::path filePath = std::filesystem::path{aurora::g_config.configPath} / "keyboard_bindings.dat";