From 5c2c4a66490db0bc5a8e282699939fdd823e0dae Mon Sep 17 00:00:00 2001 From: Megamouse Date: Tue, 14 Jan 2025 00:03:56 +0100 Subject: [PATCH] input: issue basic mouse move event on window leave This may help with moving the mouse to the screen borders in windowed mode --- rpcs3/Emu/Io/MouseHandler.cpp | 6 +-- rpcs3/Emu/Io/MouseHandler.h | 2 +- rpcs3/Input/basic_mouse_handler.cpp | 84 +++++++++++++++++------------ rpcs3/Input/basic_mouse_handler.h | 1 + 4 files changed, 56 insertions(+), 37 deletions(-) diff --git a/rpcs3/Emu/Io/MouseHandler.cpp b/rpcs3/Emu/Io/MouseHandler.cpp index b6c09bcb0d..c80d7556dc 100644 --- a/rpcs3/Emu/Io/MouseHandler.cpp +++ b/rpcs3/Emu/Io/MouseHandler.cpp @@ -31,12 +31,12 @@ void MouseHandlerBase::save(utils::serial& ar) ar(inited ? m_info.max_connect : 0); } -bool MouseHandlerBase::is_time_for_update(double elapsed_time) +bool MouseHandlerBase::is_time_for_update(double elapsed_time_ms) { steady_clock::time_point now = steady_clock::now(); - const double elapsed = (now - last_update).count() / 1000'000.; + const double elapsed_ms = (now - last_update).count() / 1'000'000.; - if (elapsed > elapsed_time) + if (elapsed_ms > elapsed_time_ms) { last_update = now; return true; diff --git a/rpcs3/Emu/Io/MouseHandler.h b/rpcs3/Emu/Io/MouseHandler.h index 007f71ee23..8a88241523 100644 --- a/rpcs3/Emu/Io/MouseHandler.h +++ b/rpcs3/Emu/Io/MouseHandler.h @@ -127,7 +127,7 @@ protected: std::vector m_mice; steady_clock::time_point last_update{}; - bool is_time_for_update(double elapsed_time = 10.0); // 4-10 ms, let's use 10 for now + bool is_time_for_update(double elapsed_time_ms = 10.0); // 4-10 ms, let's use 10 for now public: shared_mutex mutex; diff --git a/rpcs3/Input/basic_mouse_handler.cpp b/rpcs3/Input/basic_mouse_handler.cpp index 30eed46cbd..4ce238441b 100644 --- a/rpcs3/Input/basic_mouse_handler.cpp +++ b/rpcs3/Input/basic_mouse_handler.cpp @@ -125,6 +125,18 @@ bool basic_mouse_handler::eventFilter(QObject* target, QEvent* ev) case QEvent::KeyRelease: Key(static_cast(ev), false); break; + case QEvent::Leave: + { + // Issue mouse move on leave. Otherwise we may not get any mouse event at the screen borders. + const QPoint window_pos = m_target->mapToGlobal(m_target->position()) / m_target->devicePixelRatio(); + const QPoint cursor_pos = QCursor::pos() - window_pos; + + if (cursor_pos.x() <= 0 || cursor_pos.x() >= m_target->width() || cursor_pos.y() <= 0 || cursor_pos.y() >= m_target->height()) + { + MouseMove(cursor_pos); + } + break; + } default: return false; } @@ -218,38 +230,44 @@ void basic_mouse_handler::MouseMove(QMouseEvent* event) if (is_time_for_update()) { - // get the screen dimensions - const QSize screen = m_target->size(); - const QPoint e_pos = event->pos(); - - if (m_target && m_target->isActive() && get_mouse_lock_state()) - { - // get the center of the screen in global coordinates - QPoint p_center = m_target->geometry().topLeft() + QPoint(screen.width() / 2, screen.height() / 2); - - // reset the mouse to the center for consistent results since edge movement won't be registered - QCursor::setPos(m_target->screen(), p_center); - - // convert the center into screen coordinates - p_center = m_target->mapFromGlobal(p_center); - - // current mouse position, starting at the center - static QPoint p_real(p_center); - - // get the delta of the mouse position to the screen center - const QPoint p_delta = e_pos - p_center; - - // update the current position without leaving the screen borders - p_real.setX(std::clamp(p_real.x() + p_delta.x(), 0, screen.width())); - p_real.setY(std::clamp(p_real.y() + p_delta.y(), 0, screen.height())); - - // pass the 'real' position and the current delta to the screen center - MouseHandlerBase::Move(0, p_real.x(), p_real.y(), screen.width(), screen.height(), true, p_delta.x(), p_delta.y()); - } - else - { - // pass the absolute position - MouseHandlerBase::Move(0, e_pos.x(), e_pos.y(), screen.width(), screen.height()); - } + MouseMove(event->pos()); + } +} + +void basic_mouse_handler::MouseMove(const QPoint& e_pos) +{ + if (!m_target) return; + + // get the screen dimensions + const QSize screen = m_target->size(); + + if (m_target->isActive() && get_mouse_lock_state()) + { + // get the center of the screen in global coordinates + QPoint p_center = m_target->geometry().topLeft() + QPoint(screen.width() / 2, screen.height() / 2); + + // reset the mouse to the center for consistent results since edge movement won't be registered + QCursor::setPos(m_target->screen(), p_center); + + // convert the center into screen coordinates + p_center = m_target->mapFromGlobal(p_center); + + // current mouse position, starting at the center + static QPoint p_real(p_center); + + // get the delta of the mouse position to the screen center + const QPoint p_delta = e_pos - p_center; + + // update the current position without leaving the screen borders + p_real.setX(std::clamp(p_real.x() + p_delta.x(), 0, screen.width())); + p_real.setY(std::clamp(p_real.y() + p_delta.y(), 0, screen.height())); + + // pass the 'real' position and the current delta to the screen center + MouseHandlerBase::Move(0, p_real.x(), p_real.y(), screen.width(), screen.height(), true, p_delta.x(), p_delta.y()); + } + else + { + // pass the absolute position + MouseHandlerBase::Move(0, e_pos.x(), e_pos.y(), screen.width(), screen.height()); } } diff --git a/rpcs3/Input/basic_mouse_handler.h b/rpcs3/Input/basic_mouse_handler.h index 2c5b58ab80..e10dafc2f6 100644 --- a/rpcs3/Input/basic_mouse_handler.h +++ b/rpcs3/Input/basic_mouse_handler.h @@ -24,6 +24,7 @@ public: void MouseButton(QMouseEvent* event, bool pressed); void MouseScroll(QWheelEvent* event); void MouseMove(QMouseEvent* event); + void MouseMove(const QPoint& e_pos); bool eventFilter(QObject* obj, QEvent* ev) override; private: