diff --git a/rpcs3/Input/mouse_gyro_state.cpp b/rpcs3/Input/mouse_gyro_state.cpp new file mode 100644 index 0000000000..05d9e50421 --- /dev/null +++ b/rpcs3/Input/mouse_gyro_state.cpp @@ -0,0 +1,63 @@ +#include "mouse_gyro_state.h" + +void mouse_gyro_state::clear() +{ + active = false; + reset = false; + gyro_x = DEFAULT_MOTION_X; + gyro_y = DEFAULT_MOTION_Y; + gyro_z = DEFAULT_MOTION_Z; +} + +void mouse_gyro_state::set_gyro_active() +{ + active = true; +} + +void mouse_gyro_state::set_gyro_reset() +{ + active = false; + reset = true; +} + +void mouse_gyro_state::set_gyro_xz(s32 off_x, s32 off_y) +{ + if (!active) + return; + + gyro_x = static_cast(std::clamp(off_x, 0, DEFAULT_MOTION_X * 2 - 1)); + gyro_z = static_cast(std::clamp(off_y, 0, DEFAULT_MOTION_Z * 2 - 1)); +} + +void mouse_gyro_state::set_gyro_y(s32 steps) +{ + if (!active) + return; + + gyro_y = static_cast(std::clamp(gyro_y + steps, 0, DEFAULT_MOTION_Y * 2 - 1)); +} + +void mouse_gyro_state::gyro_run(const std::shared_ptr& pad) +{ + if (!pad || !pad->is_connected()) + return; + + // Inject mouse-based motion sensor values into pad sensors for gyro emulation. + // The Qt frontend maps cursor offset and wheel input to absolute motion values while RMB is held. + if (reset) + { + // RMB released → reset motion + pad->m_sensors[0].m_value = DEFAULT_MOTION_X; + pad->m_sensors[1].m_value = DEFAULT_MOTION_Y; + pad->m_sensors[2].m_value = DEFAULT_MOTION_Z; + clear(); + } + else + { + // RMB held → accumulate motion + // Axes have been chosen as tested in Sly 4 minigames. Top-down view motion uses X/Z axes. + pad->m_sensors[0].m_value = gyro_x; // Mouse X → Motion X + pad->m_sensors[1].m_value = gyro_y; // Mouse Wheel → Motion Y + pad->m_sensors[2].m_value = gyro_z; // Mouse Y → Motion Z + } +} diff --git a/rpcs3/Input/mouse_gyro_state.h b/rpcs3/Input/mouse_gyro_state.h new file mode 100644 index 0000000000..bd4c870ff4 --- /dev/null +++ b/rpcs3/Input/mouse_gyro_state.h @@ -0,0 +1,33 @@ +#pragma once + +#include "util/types.hpp" +#include "Emu/Io/pad_types.h" + +#include + +// Mouse-based motion sensor emulation state. +class mouse_gyro_state +{ +private: + bool active = false; // Whether right mouse button is currently held (gyro active) + bool reset = false; // One-shot reset request on right mouse button release + s32 gyro_x = DEFAULT_MOTION_X; // Accumulated from mouse X position relative to center + s32 gyro_y = DEFAULT_MOTION_Y; // Accumulated from mouse wheel delta + s32 gyro_z = DEFAULT_MOTION_Z; // Accumulated from mouse Y position relative to center + +public: + void clear(); + + bool is_gyro_active() const { return active; } + bool needs_gyro_reset() const { return reset; } + s32 get_gyro_x() const { return gyro_x; } + s32 get_gyro_y() const { return gyro_y; } + s32 get_gyro_z() const { return gyro_z; } + + void set_gyro_active(); + void set_gyro_reset(); + void set_gyro_xz(s32 off_x, s32 off_y); + void set_gyro_y(s32 steps); + + void gyro_run(const std::shared_ptr& pad); +}; diff --git a/rpcs3/Input/pad_thread.cpp b/rpcs3/Input/pad_thread.cpp index af73aa7a57..27c1d33ee0 100644 --- a/rpcs3/Input/pad_thread.cpp +++ b/rpcs3/Input/pad_thread.cpp @@ -606,46 +606,13 @@ void pad_thread::operator()() apply_copilots(); - // Inject mouse-based motion sensor values into pad sensors for gyro emulation. - // The Qt frontend maps cursor offset and wheel input to absolute motion values while RMB is held. - if (Emu.IsRunning()) - { - const bool reset = m_mouse_gyro.reset; - - const s32 gyro_x = m_mouse_gyro.gyro_x; - const s32 gyro_y = m_mouse_gyro.gyro_y; - const s32 gyro_z = m_mouse_gyro.gyro_z; - - if (gyro_x || gyro_y || gyro_z || reset) - { - // Mouse-based gyro input is intentionally bound to Player 1 only. - auto& pad = m_pads[0]; - - if (pad && pad->is_connected()) - { - if (reset) - { - // RMB released → reset motion - pad->m_sensors[0].m_value = DEFAULT_MOTION_X; - pad->m_sensors[1].m_value = DEFAULT_MOTION_Y; - pad->m_sensors[2].m_value = DEFAULT_MOTION_Z; - m_mouse_gyro.clear(); - } - else - { - // RMB held → accumulate motion - // Axes have been chosen as tested in Sly 4 minigames. Top-down view motion uses X/Z axes. - pad->m_sensors[0].m_value = gyro_x; // Mouse X → Motion X - pad->m_sensors[1].m_value = gyro_y; // Mouse Wheel → Motion Y - pad->m_sensors[2].m_value = gyro_z; // Mouse Y → Motion Z - } - } - } - } - if (Emu.IsRunning()) { update_pad_states(); + + // Inject mouse-based motion sensor values into pad sensors for gyro emulation. + // Intentionally bound to Player 1 only. + m_mouse_gyro.gyro_run(m_pads[0]); } m_info.now_connect = connected_devices + num_ldd_pad; @@ -977,31 +944,3 @@ void pad_thread::open_home_menu() (result ? input_log.error : input_log.notice)("opened home menu with result %d", s32{result}); } } - -void pad_thread::mouse_gyro_rmb_down() -{ - m_mouse_gyro.rmb = true; -} - -void pad_thread::mouse_gyro_rmb_up() -{ - m_mouse_gyro.rmb = false; - m_mouse_gyro.reset = true; -} - -void pad_thread::mouse_gyro_set_xz(s32 off_x, s32 off_y) -{ - if (!m_mouse_gyro.rmb) - return; - - m_mouse_gyro.gyro_x = static_cast(std::clamp(off_x, 0, DEFAULT_MOTION_X * 2 - 1)); - m_mouse_gyro.gyro_z = static_cast(std::clamp(off_y, 0, DEFAULT_MOTION_Z * 2 - 1)); -} - -void pad_thread::mouse_gyro_set_y(s32 steps) -{ - if (!m_mouse_gyro.rmb) - return; - - m_mouse_gyro.gyro_y = static_cast(std::clamp(m_mouse_gyro.gyro_y + steps, 0, DEFAULT_MOTION_Y * 2 - 1)); -} diff --git a/rpcs3/Input/pad_thread.h b/rpcs3/Input/pad_thread.h index f4d66cb24b..894d93aaa5 100644 --- a/rpcs3/Input/pad_thread.h +++ b/rpcs3/Input/pad_thread.h @@ -5,6 +5,7 @@ #include "Emu/Io/pad_types.h" #include "Emu/Io/pad_config.h" #include "Emu/Io/pad_config_types.h" +#include "Input/mouse_gyro_state.h" #include "Utilities/mutex.h" #include @@ -41,10 +42,7 @@ public: static auto constexpr thread_name = "Pad Thread"sv; - void mouse_gyro_rmb_down(); - void mouse_gyro_rmb_up(); - void mouse_gyro_set_xz(s32 off_x, s32 off_y); - void mouse_gyro_set_y(s32 steps); + mouse_gyro_state m_mouse_gyro; protected: void Init(); @@ -72,27 +70,6 @@ private: bool m_resume_emulation_flag = false; bool m_ps_button_pressed = false; atomic_t m_home_menu_open = false; - - // Mouse-based motion sensor emulation state. - struct mouse_gyro_state - { - std::atomic rmb {false}; // Whether right mouse button is currently held (gyro active) - std::atomic gyro_x {DEFAULT_MOTION_X}; // Accumulated from mouse X position relative to center - std::atomic gyro_y {DEFAULT_MOTION_Y}; // Accumulated from mouse wheel delta - std::atomic gyro_z {DEFAULT_MOTION_Z}; // Accumulated from mouse Y position relative to center - std::atomic reset {false}; // One-shot reset request on right mouse button release - - void clear() - { - rmb = false; - gyro_x = DEFAULT_MOTION_X; - gyro_y = DEFAULT_MOTION_Y; - gyro_z = DEFAULT_MOTION_Z; - reset = false; - } - }; - - mouse_gyro_state m_mouse_gyro; }; namespace pad diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 5fbf0491e9..cca31dd52b 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -194,6 +194,7 @@ + @@ -1079,6 +1080,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath) $(QTDIR)\bin\moc.exe;%(FullPath) + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 100a9b1d8f..797b216a3f 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -1272,6 +1272,9 @@ Generated Files\Release + + Io + @@ -1511,6 +1514,9 @@ Io\camera + + Io + diff --git a/rpcs3/rpcs3qt/gs_frame.cpp b/rpcs3/rpcs3qt/gs_frame.cpp index 34eff7090b..061fb3c6cf 100644 --- a/rpcs3/rpcs3qt/gs_frame.cpp +++ b/rpcs3/rpcs3qt/gs_frame.cpp @@ -1234,7 +1234,7 @@ bool gs_frame::event(QEvent* ev) if (e->button() == Qt::RightButton) { // Enable mouse-driven gyro emulation while RMB is held. - pad_thr->mouse_gyro_rmb_down(); + pad_thr->m_mouse_gyro.set_gyro_active(); } break; } @@ -1244,7 +1244,7 @@ bool gs_frame::event(QEvent* ev) if (e->button() == Qt::RightButton) { // Disable gyro emulation and request a one-shot motion reset. - pad_thr->mouse_gyro_rmb_up(); + pad_thr->m_mouse_gyro.set_gyro_reset(); } break; } @@ -1260,7 +1260,7 @@ bool gs_frame::event(QEvent* ev) const s32 off_y = cur.y() - center.y() + DEFAULT_MOTION_Z; // Determine motion from relative mouse position while gyro emulation is active. - pad_thr->mouse_gyro_set_xz(off_x, off_y); + pad_thr->m_mouse_gyro.set_gyro_xz(off_x, off_y); break; } @@ -1272,7 +1272,7 @@ bool gs_frame::event(QEvent* ev) const s32 steps = e->angleDelta().y() / 120; // Accumulate mouse wheel steps while gyro emulation is active. - pad_thr->mouse_gyro_set_y(steps); + pad_thr->m_mouse_gyro.set_gyro_y(steps); break; }