Qt: Fix mouse scaling
Since yuzu-emu/yuzu#4949 any user that had a window scale different from 100% will have wrong mouse coordinates. This PR fixes the issue by removing the workaround for scaling since now it should be 1:1 at any scale. This PR also splits mouse input into 3 different devices. A physical mouse, touch and finally one for controllers. This solves the issue Zeikken85 had where having emulated mouse enabled had a weird behavior on stick input. As a final protection against setting invalid configs a warning message will show up if emulated mouse is enabled. Co-Authored-By: Narr the Reg <5944268+german77@users.noreply.github.com>
This commit is contained in:
@ -486,12 +486,6 @@ qreal GRenderWindow::windowPixelRatio() const {
|
||||
return devicePixelRatioF();
|
||||
}
|
||||
|
||||
std::pair<u32, u32> GRenderWindow::ScaleTouch(const QPointF pos) const {
|
||||
const qreal pixel_ratio = windowPixelRatio();
|
||||
return {static_cast<u32>(std::max(std::round(pos.x() * pixel_ratio), qreal{0.0})),
|
||||
static_cast<u32>(std::max(std::round(pos.y() * pixel_ratio), qreal{0.0}))};
|
||||
}
|
||||
|
||||
void GRenderWindow::closeEvent(QCloseEvent* event) {
|
||||
emit Closed();
|
||||
QWidget::closeEvent(event);
|
||||
@ -536,10 +530,12 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) {
|
||||
// Qt sometimes returns the parent coordinates. To avoid this we read the global mouse
|
||||
// coordinates and map them to the current render area
|
||||
const auto pos = mapFromGlobal(QCursor::pos());
|
||||
const auto [x, y] = ScaleTouch(pos);
|
||||
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
|
||||
const auto [touch_x, touch_y] = MapToTouchScreen(pos.x(), pos.y());
|
||||
const auto button = QtButtonToMouseButton(event->button());
|
||||
input_subsystem->GetMouse()->PressButton(x, y, touch_x, touch_y, button);
|
||||
|
||||
input_subsystem->GetMouse()->PressMouseButton(button);
|
||||
input_subsystem->GetMouse()->PressButton(pos.x(), pos.y(), button);
|
||||
input_subsystem->GetMouse()->PressTouchButton(touch_x, touch_y, button);
|
||||
|
||||
emit MouseActivity();
|
||||
}
|
||||
@ -552,11 +548,13 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
|
||||
// Qt sometimes returns the parent coordinates. To avoid this we read the global mouse
|
||||
// coordinates and map them to the current render area
|
||||
const auto pos = mapFromGlobal(QCursor::pos());
|
||||
const auto [x, y] = ScaleTouch(pos);
|
||||
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
|
||||
const auto [touch_x, touch_y] = MapToTouchScreen(pos.x(), pos.y());
|
||||
const int center_x = width() / 2;
|
||||
const int center_y = height() / 2;
|
||||
input_subsystem->GetMouse()->MouseMove(x, y, touch_x, touch_y, center_x, center_y);
|
||||
|
||||
input_subsystem->GetMouse()->MouseMove(touch_x, touch_y);
|
||||
input_subsystem->GetMouse()->TouchMove(touch_x, touch_y);
|
||||
input_subsystem->GetMouse()->Move(pos.x(), pos.y(), center_x, center_y);
|
||||
|
||||
emit MouseActivity();
|
||||
}
|
||||
@ -580,8 +578,8 @@ void GRenderWindow::wheelEvent(QWheelEvent* event) {
|
||||
void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) {
|
||||
QList<QTouchEvent::TouchPoint> touch_points = event->touchPoints();
|
||||
for (const auto& touch_point : touch_points) {
|
||||
const auto [x, y] = ScaleTouch(touch_point.pos());
|
||||
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
|
||||
const auto pos = touch_point.pos();
|
||||
const auto [touch_x, touch_y] = MapToTouchScreen(pos.x(), pos.y());
|
||||
input_subsystem->GetTouchScreen()->TouchPressed(touch_x, touch_y, touch_point.id());
|
||||
}
|
||||
}
|
||||
@ -590,8 +588,8 @@ void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) {
|
||||
QList<QTouchEvent::TouchPoint> touch_points = event->touchPoints();
|
||||
input_subsystem->GetTouchScreen()->ClearActiveFlag();
|
||||
for (const auto& touch_point : touch_points) {
|
||||
const auto [x, y] = ScaleTouch(touch_point.pos());
|
||||
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
|
||||
const auto pos = touch_point.pos();
|
||||
const auto [touch_x, touch_y] = MapToTouchScreen(pos.x(), pos.y());
|
||||
input_subsystem->GetTouchScreen()->TouchMoved(touch_x, touch_y, touch_point.id());
|
||||
}
|
||||
input_subsystem->GetTouchScreen()->ReleaseInactiveTouch();
|
||||
|
@ -885,7 +885,7 @@ void ConfigureInput::mousePressEvent(QMouseEvent* event) {
|
||||
}
|
||||
|
||||
const auto button = GRenderWindow::QtButtonToMouseButton(event->button());
|
||||
input_subsystem->GetMouse()->PressButton(0, 0, 0, 0, button);
|
||||
input_subsystem->GetMouse()->PressButton(0, 0, button);
|
||||
}
|
||||
|
||||
void ConfigureInput::wheelEvent(QWheelEvent* event) {
|
||||
|
@ -15,14 +15,24 @@ constexpr int mouse_axis_y = 1;
|
||||
constexpr int wheel_axis_x = 2;
|
||||
constexpr int wheel_axis_y = 3;
|
||||
constexpr int motion_wheel_y = 4;
|
||||
constexpr int touch_axis_x = 10;
|
||||
constexpr int touch_axis_y = 11;
|
||||
constexpr PadIdentifier identifier = {
|
||||
.guid = Common::UUID{},
|
||||
.port = 0,
|
||||
.pad = 0,
|
||||
};
|
||||
|
||||
constexpr PadIdentifier real_mouse_identifier = {
|
||||
.guid = Common::UUID{},
|
||||
.port = 1,
|
||||
.pad = 0,
|
||||
};
|
||||
|
||||
constexpr PadIdentifier touch_identifier = {
|
||||
.guid = Common::UUID{},
|
||||
.port = 2,
|
||||
.pad = 0,
|
||||
};
|
||||
|
||||
Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
||||
PreSetController(identifier);
|
||||
PreSetAxis(identifier, mouse_axis_x);
|
||||
@ -30,8 +40,8 @@ Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_))
|
||||
PreSetAxis(identifier, wheel_axis_x);
|
||||
PreSetAxis(identifier, wheel_axis_y);
|
||||
PreSetAxis(identifier, motion_wheel_y);
|
||||
PreSetAxis(identifier, touch_axis_x);
|
||||
PreSetAxis(identifier, touch_axis_y);
|
||||
PreSetAxis(touch_identifier, mouse_axis_x);
|
||||
PreSetAxis(touch_identifier, mouse_axis_y);
|
||||
update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); });
|
||||
}
|
||||
|
||||
@ -44,30 +54,40 @@ void Mouse::UpdateThread(std::stop_token stop_token) {
|
||||
}
|
||||
}
|
||||
|
||||
void Mouse::MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int center_y) {
|
||||
SetAxis(identifier, touch_axis_x, touch_x);
|
||||
SetAxis(identifier, touch_axis_y, touch_y);
|
||||
|
||||
if (button_pressed) {
|
||||
constexpr float sensitivity = 0.0012f;
|
||||
const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin;
|
||||
SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * sensitivity);
|
||||
SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * sensitivity);
|
||||
}
|
||||
void Mouse::MouseMove(f32 touch_x, f32 touch_y) {
|
||||
SetAxis(real_mouse_identifier, mouse_axis_x, touch_x);
|
||||
SetAxis(real_mouse_identifier, mouse_axis_y, touch_y);
|
||||
}
|
||||
|
||||
void Mouse::PressButton(int x, int y, f32 touch_x, f32 touch_y, MouseButton button) {
|
||||
SetAxis(identifier, touch_axis_x, touch_x);
|
||||
SetAxis(identifier, touch_axis_y, touch_y);
|
||||
void Mouse::TouchMove(f32 touch_x, f32 touch_y) {
|
||||
SetAxis(touch_identifier, mouse_axis_x, touch_x);
|
||||
SetAxis(touch_identifier, mouse_axis_y, touch_y);
|
||||
}
|
||||
|
||||
void Mouse::PressButton(int x, int y, MouseButton button) {
|
||||
SetButton(identifier, static_cast<int>(button), true);
|
||||
|
||||
// Set initial analog parameters
|
||||
mouse_origin = {x, y};
|
||||
last_mouse_position = {x, y};
|
||||
button_pressed = true;
|
||||
}
|
||||
|
||||
void Mouse::PressMouseButton(MouseButton button) {
|
||||
SetButton(real_mouse_identifier, static_cast<int>(button), true);
|
||||
}
|
||||
|
||||
void Mouse::PressTouchButton(f32 touch_x, f32 touch_y, MouseButton button) {
|
||||
SetAxis(touch_identifier, mouse_axis_x, touch_x);
|
||||
SetAxis(touch_identifier, mouse_axis_y, touch_y);
|
||||
SetButton(touch_identifier, static_cast<int>(button), true);
|
||||
}
|
||||
|
||||
void Mouse::ReleaseButton(MouseButton button) {
|
||||
SetButton(identifier, static_cast<int>(button), false);
|
||||
SetButton(real_mouse_identifier, static_cast<int>(button), false);
|
||||
SetButton(touch_identifier, static_cast<int>(button), false);
|
||||
|
||||
button_pressed = false;
|
||||
}
|
||||
|
||||
|
@ -36,13 +36,43 @@ public:
|
||||
* @param center_x the x-coordinate of the middle of the screen
|
||||
* @param center_y the y-coordinate of the middle of the screen
|
||||
*/
|
||||
void MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int center_y);
|
||||
void Move(int x, int y, int center_x, int center_y);
|
||||
|
||||
/**
|
||||
* Sets the status of all buttons bound with the key to pressed
|
||||
* @param key_code the code of the key to press
|
||||
* Signals that real mouse has moved.
|
||||
* @param x the absolute position on the touchscreen of the cursor
|
||||
* @param y the absolute position on the touchscreen of the cursor
|
||||
*/
|
||||
void PressButton(int x, int y, f32 touch_x, f32 touch_y, MouseButton button);
|
||||
void MouseMove(f32 touch_x, f32 touch_y);
|
||||
|
||||
/**
|
||||
* Signals that touch finger has moved.
|
||||
* @param x the absolute position on the touchscreen of the cursor
|
||||
* @param y the absolute position on the touchscreen of the cursor
|
||||
*/
|
||||
void TouchMove(f32 touch_x, f32 touch_y);
|
||||
|
||||
/**
|
||||
* Sets the status of a button to pressed
|
||||
* @param x the x-coordinate of the cursor
|
||||
* @param y the y-coordinate of the cursor
|
||||
* @param button the id of the button to press
|
||||
*/
|
||||
void PressButton(int x, int y, MouseButton button);
|
||||
|
||||
/**
|
||||
* Sets the status of a mouse button to pressed
|
||||
* @param button the id of the button to press
|
||||
*/
|
||||
void PressMouseButton(MouseButton button);
|
||||
|
||||
/**
|
||||
* Sets the status of touch finger to pressed
|
||||
* @param x the absolute position on the touchscreen of the cursor
|
||||
* @param y the absolute position on the touchscreen of the cursor
|
||||
* @param button the id of the button to press
|
||||
*/
|
||||
void PressTouchButton(f32 touch_x, f32 touch_y, MouseButton button);
|
||||
|
||||
/**
|
||||
* Sets the status of all buttons bound with the key to released
|
||||
|
@ -194,6 +194,10 @@ bool MappingFactory::IsDriverValid(const MappingData& data) const {
|
||||
if (data.engine == "keyboard" && data.pad.port != 0) {
|
||||
return false;
|
||||
}
|
||||
// Only port 0 can be mapped on the mouse
|
||||
if (data.engine == "mouse" && data.pad.port != 0) {
|
||||
return false;
|
||||
}
|
||||
// To prevent mapping with two devices we disable any UDP except motion
|
||||
if (data.engine == "cemuhookudp" && data.type != EngineInputType::Motion) {
|
||||
return false;
|
||||
|
Reference in New Issue
Block a user