mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-05 06:21:26 +12:00
This should address the second point of #4502. A few notes: 1. it changes the current behaviour of the 'Fullscreen cursor'. Currently it defaults to be captive. This changes it so that it defaults to NOT being captive, but can be made captive with the CTRL+L key combination. 2. There are situations when in windowed mode it's possible to escape the captivity (it's like a minigame if you will). This requires the mouse movement to exceed the bounds of the window in a single event scan. It will just show up as a temporary visibility of the cursor when outside of the window bounds. It's not too difficult to 'fix', but might not be a likely enough scenario to warrant either. 3. There currently isn't an ability to change what this keyboard combo maps to, but it's inline with a collection of other similar keyboard mappings. I think adding such a more generic keyboard mapping system (not for just keypad items, but system items.. e.g. so that Emulator stop could be mapped to something other than CTRL+S etc) is a bit out-of-scope of this particular PR.
140 lines
4.5 KiB
C++
140 lines
4.5 KiB
C++
#include "basic_mouse_handler.h"
|
|
|
|
#include <QApplication>
|
|
#include <QCursor>
|
|
|
|
LOG_CHANNEL(input_log, "Input");
|
|
|
|
void basic_mouse_handler::Init(const u32 max_connect)
|
|
{
|
|
m_mice.emplace_back(Mouse());
|
|
memset(&m_info, 0, sizeof(MouseInfo));
|
|
m_info.max_connect = max_connect;
|
|
m_info.now_connect = std::min(::size32(m_mice), max_connect);
|
|
m_info.info = 0; // Ownership of mouse data: 0=Application, 1=System
|
|
for (u32 i = 1; i < max_connect; i++)
|
|
{
|
|
m_info.status[i] = CELL_MOUSE_STATUS_DISCONNECTED;
|
|
m_info.mode[i] = CELL_MOUSE_INFO_TABLET_MOUSE_MODE;
|
|
m_info.tablet_is_supported[i] = CELL_MOUSE_INFO_TABLET_NOT_SUPPORTED;
|
|
}
|
|
m_info.status[0] = CELL_MOUSE_STATUS_CONNECTED; // (TODO: Support for more mice)
|
|
m_info.vendor_id[0] = 0x1234;
|
|
m_info.product_id[0] = 0x1234;
|
|
}
|
|
|
|
basic_mouse_handler::basic_mouse_handler() : QObject()
|
|
{}
|
|
|
|
/* Sets the target window for the event handler, and also installs an event filter on the target. */
|
|
void basic_mouse_handler::SetTargetWindow(QWindow* target)
|
|
{
|
|
if (target != nullptr)
|
|
{
|
|
m_target = target;
|
|
target->installEventFilter(this);
|
|
}
|
|
else
|
|
{
|
|
// If this is hit, it probably means that some refactoring occurs because currently a gsframe is created in Load.
|
|
// We still want events so filter from application instead since target is null.
|
|
QApplication::instance()->installEventFilter(this);
|
|
input_log.error("Trying to set mouse handler to a null target window.");
|
|
}
|
|
}
|
|
|
|
bool basic_mouse_handler::eventFilter(QObject* target, QEvent* ev)
|
|
{
|
|
// !m_target is for future proofing when gsrender isn't automatically initialized on load to ensure events still occur
|
|
// !m_target->isVisible() is a hack since currently a guiless application will STILL inititialize a gsrender (providing a valid target)
|
|
if (!m_target || !m_target->isVisible() || target == m_target)
|
|
{
|
|
switch (ev->type())
|
|
{
|
|
case QEvent::MouseButtonPress:
|
|
MouseButtonDown(static_cast<QMouseEvent*>(ev));
|
|
break;
|
|
case QEvent::MouseButtonRelease:
|
|
MouseButtonUp(static_cast<QMouseEvent*>(ev));
|
|
break;
|
|
case QEvent::MouseMove:
|
|
MouseMove(static_cast<QMouseEvent*>(ev));
|
|
break;
|
|
case QEvent::Wheel:
|
|
MouseScroll(static_cast<QWheelEvent*>(ev));
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void basic_mouse_handler::MouseButtonDown(QMouseEvent* event)
|
|
{
|
|
if (event->button() == Qt::LeftButton) MouseHandlerBase::Button(CELL_MOUSE_BUTTON_1, 1);
|
|
else if (event->button() == Qt::RightButton) MouseHandlerBase::Button(CELL_MOUSE_BUTTON_2, 1);
|
|
else if (event->button() == Qt::MiddleButton) MouseHandlerBase::Button(CELL_MOUSE_BUTTON_3, 1);
|
|
}
|
|
|
|
void basic_mouse_handler::MouseButtonUp(QMouseEvent* event)
|
|
{
|
|
if (event->button() == Qt::LeftButton) MouseHandlerBase::Button(CELL_MOUSE_BUTTON_1, 0);
|
|
else if (event->button() == Qt::RightButton) MouseHandlerBase::Button(CELL_MOUSE_BUTTON_2, 0);
|
|
else if (event->button() == Qt::MiddleButton) MouseHandlerBase::Button(CELL_MOUSE_BUTTON_3, 0);
|
|
}
|
|
|
|
void basic_mouse_handler::MouseScroll(QWheelEvent* event)
|
|
{
|
|
MouseHandlerBase::Scroll(event->angleDelta().y());
|
|
}
|
|
|
|
bool basic_mouse_handler::get_mouse_lock_state()
|
|
{
|
|
if (m_target)
|
|
{
|
|
auto mouse_locked = m_target->property("mouse_locked");
|
|
if (mouse_locked.isValid())
|
|
return mouse_locked.toBool();
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void basic_mouse_handler::MouseMove(QMouseEvent* event)
|
|
{
|
|
if (is_time_for_update())
|
|
{
|
|
if (m_target && m_target->isActive() && get_mouse_lock_state())
|
|
{
|
|
// get the screen dimensions
|
|
const QSize screen = m_target->size();
|
|
|
|
// 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 = event->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(p_real.x(), p_real.y(), true, p_delta.x(), p_delta.y());
|
|
}
|
|
else
|
|
{
|
|
MouseHandlerBase::Move(event->x(), event->y());
|
|
}
|
|
}
|
|
}
|