From 5c55819b5744e797f5f43809cbb9b5ee99912956 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sun, 28 Jun 2026 02:57:03 +0200 Subject: [PATCH] emulated turntable: allow to map motion sensors --- rpcs3/Emu/Io/Turntable.cpp | 23 ++++++++++++ rpcs3/Emu/Io/emulated_pad_config.h | 37 +++++++++++++------ rpcs3/Emu/Io/pad_types.cpp | 15 ++++++++ rpcs3/Emu/Io/pad_types.h | 7 ++++ .../rpcs3qt/emulated_pad_settings_dialog.cpp | 12 ++++++ rpcs3/rpcs3qt/localized_emu.cpp | 5 +++ 6 files changed, 88 insertions(+), 11 deletions(-) diff --git a/rpcs3/Emu/Io/Turntable.cpp b/rpcs3/Emu/Io/Turntable.cpp index 261af88d16..1776fc9864 100644 --- a/rpcs3/Emu/Io/Turntable.cpp +++ b/rpcs3/Emu/Io/Turntable.cpp @@ -296,4 +296,27 @@ void usb_device_turntable::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpo break; } }); + + cfg->handle_motion_input(pad, [&buf](turntable_btn btn, pad_button /*pad_btn*/, u16 value, bool /*pressed*/, bool& /*abort*/) + { + switch (btn) + { + case turntable_btn::crossfader: + { + const u16 v = value & 0x03FF; // ensure 10-bit range + buf[21] = (v & 0xFF); // Crossfader, lower 8 bits + buf[22] = (v >> 8) & 0x03; // Crossfader, upper 2 bits + break; + } + case turntable_btn::effects_dial: + { + const u16 v = value & 0x03FF; // ensure 10-bit range + buf[19] = (v & 0xFF); // Effects Dial, lower 8 bits + buf[20] = (v >> 8) & 0x03; // Effects Dial, upper 2 bits + break; + } + default: + break; + } + }); } diff --git a/rpcs3/Emu/Io/emulated_pad_config.h b/rpcs3/Emu/Io/emulated_pad_config.h index eb54966583..5094ce9fee 100644 --- a/rpcs3/Emu/Io/emulated_pad_config.h +++ b/rpcs3/Emu/Io/emulated_pad_config.h @@ -90,14 +90,14 @@ public: void handle_input(std::shared_ptr pad, bool press_only, const std::function& func) const { - if (!pad || pad->is_copilot()) + if (!func || !pad || pad->is_copilot()) return; for (const ButtonExternal& button : pad->m_buttons_external) { if (button.m_pressed || !press_only) { - if (handle_input(func, button.m_offset, button.m_outKeyCode, button.m_value, button.m_pressed, true)) + if (handle_input_internal(func, button.m_offset, button.m_outKeyCode, button.m_value, button.m_pressed, true)) { return; } @@ -106,7 +106,21 @@ public: for (const AnalogStickExternal& stick : pad->m_sticks_external) { - if (handle_input(func, stick.m_offset, get_axis_keycode(stick.m_offset, stick.m_value), stick.m_value, true, true)) + if (handle_input_internal(func, stick.m_offset, get_axis_keycode(stick.m_offset, stick.m_value), stick.m_value, true, true)) + { + return; + } + } + } + + void handle_motion_input(std::shared_ptr pad, const std::function& func) const + { + if (!func || !pad || pad->is_copilot()) + return; + + for (const AnalogSensor& sensor : pad->m_sensors) + { + if (handle_input_internal(func, sensor.m_offset, sensor.m_keyCode, sensor.m_value, true, false)) { return; } @@ -124,7 +138,7 @@ public: const u32 offset = pad_button_offset(button); const u32 keycode = pad_button_keycode(button); - if (handle_input(func, offset, keycode, 255, true, true)) + if (handle_input_internal(func, offset, keycode, 255, true, true)) { return; } @@ -173,11 +187,11 @@ protected: return empty_set; } - bool handle_input(const std::function& func, u32 offset, u32 keycode, u16 value, bool pressed, bool check_axis) const + bool handle_input_internal(const std::function& func, u32 offset, u32 keycode, u16 value, bool pressed, bool check_axis) const { - m_mutex.lock(); + if (!func) return false; - bool abort = false; + m_mutex.lock(); const auto& btns = find_button(offset, keycode); if (btns.empty()) @@ -192,18 +206,19 @@ protected: case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y: case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X: case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y: - abort = handle_input(func, offset, static_cast(axis_direction::both), value, pressed, false); - break; + return handle_input_internal(func, offset, static_cast(axis_direction::both), value, pressed, false); default: break; } } - return abort; + return false; } + bool abort = false; + for (const auto& btn : btns) { - if (btn && func) + if (btn) { func(btn->btn_id(), btn->get(), value, pressed, abort); if (abort) break; diff --git a/rpcs3/Emu/Io/pad_types.cpp b/rpcs3/Emu/Io/pad_types.cpp index d5ef26f0d7..aa374a7fd8 100644 --- a/rpcs3/Emu/Io/pad_types.cpp +++ b/rpcs3/Emu/Io/pad_types.cpp @@ -40,6 +40,11 @@ void fmt_class_string::format(std::string& out, u64 arg) case pad_button::rs_x: return "Right Stick X-Axis"; case pad_button::rs_y: return "Right Stick Y-Axis"; case pad_button::pad_button_max_enum: return ""; + case pad_button::motion_x: return "Motion X"; + case pad_button::motion_y: return "Motion Y"; + case pad_button::motion_z: return "Motion Z"; + case pad_button::motion_g: return "Motion G"; + case pad_button::pad_motion_max_enum: return ""; case pad_button::mouse_button_1: return "Mouse Button 1"; case pad_button::mouse_button_2: return "Mouse Button 2"; case pad_button::mouse_button_3: return "Mouse Button 3"; @@ -87,6 +92,11 @@ u32 pad_button_offset(pad_button button) case pad_button::rs_right: return CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X; case pad_button::rs_x: return CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X; case pad_button::rs_y: return CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y; + case pad_button::motion_x: return CELL_PAD_BTN_OFFSET_SENSOR_X; + case pad_button::motion_y: return CELL_PAD_BTN_OFFSET_SENSOR_Y; + case pad_button::motion_z: return CELL_PAD_BTN_OFFSET_SENSOR_Z; + case pad_button::motion_g: return CELL_PAD_BTN_OFFSET_SENSOR_G; + case pad_button::pad_motion_max_enum: case pad_button::pad_button_max_enum: case pad_button::mouse_button_1: case pad_button::mouse_button_2: @@ -135,6 +145,11 @@ u32 pad_button_keycode(pad_button button) case pad_button::rs_x: return static_cast(axis_direction::both); case pad_button::rs_y: return static_cast(axis_direction::both); case pad_button::pad_button_max_enum: return 0; + case pad_button::motion_x: return 0; + case pad_button::motion_y: return 0; + case pad_button::motion_z: return 0; + case pad_button::motion_g: return 0; + case pad_button::pad_motion_max_enum: return 0; case pad_button::mouse_button_1: return 1; case pad_button::mouse_button_2: return 2; case pad_button::mouse_button_3: return 3; diff --git a/rpcs3/Emu/Io/pad_types.h b/rpcs3/Emu/Io/pad_types.h index 238e03ff1a..b7f844a22e 100644 --- a/rpcs3/Emu/Io/pad_types.h +++ b/rpcs3/Emu/Io/pad_types.h @@ -44,6 +44,13 @@ enum class pad_button : u8 pad_button_max_enum, + motion_x, + motion_y, + motion_z, + motion_g, + + pad_motion_max_enum, + // Special buttons for mouse input mouse_button_1, mouse_button_2, diff --git a/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp b/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp index 023a16d4e8..50c3178644 100644 --- a/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp @@ -280,6 +280,18 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) } } + if (std::is_same_v && (static_cast(i) == turntable_btn::crossfader || static_cast(i) == turntable_btn::effects_dial)) + { + for (int p = static_cast(pad_button::motion_x); p < static_cast(pad_button::pad_motion_max_enum); p++) + { + const QString translated = localized_emu::translated_pad_button(static_cast(p)); + combo->addItem(translated); + const int index = combo->findText(translated); + combo->setItemData(index, p, button_role::button); + combo->setItemData(index, i, button_role::emulated_button); + } + } + pad_button saved_btn_id = pad_button::pad_button_max_enum; switch (m_type) { diff --git a/rpcs3/rpcs3qt/localized_emu.cpp b/rpcs3/rpcs3qt/localized_emu.cpp index bfc0b52101..a6cb3b6dd8 100644 --- a/rpcs3/rpcs3qt/localized_emu.cpp +++ b/rpcs3/rpcs3qt/localized_emu.cpp @@ -36,6 +36,11 @@ QString localized_emu::translated_pad_button(pad_button btn) case pad_button::rs_x: return tr("Right Stick X-Axis"); case pad_button::rs_y: return tr("Right Stick Y-Axis"); case pad_button::pad_button_max_enum: return ""; + case pad_button::motion_x: return tr("Motion X"); + case pad_button::motion_y: return tr("Motion Y"); + case pad_button::motion_z: return tr("Motion Z"); + case pad_button::motion_g: return tr("Motion G"); + case pad_button::pad_motion_max_enum: return ""; case pad_button::mouse_button_1: return tr("Mouse 1"); case pad_button::mouse_button_2: return tr("Mouse 2"); case pad_button::mouse_button_3: return tr("Mouse 3");