From 57aaf00a0c7db0c5a98f6609afdc1dbaf41c32ef Mon Sep 17 00:00:00 2001 From: german77 Date: Wed, 15 Feb 2023 20:57:45 -0600 Subject: [PATCH 1/2] Qt: Fix mouse scalling --- src/yuzu/bootmanager.cpp | 24 ++++++++---------------- src/yuzu/bootmanager.h | 2 -- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 352300e882..a64e63a399 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -401,12 +401,6 @@ qreal GRenderWindow::windowPixelRatio() const { return devicePixelRatioF(); } -std::pair GRenderWindow::ScaleTouch(const QPointF& pos) const { - const qreal pixel_ratio = windowPixelRatio(); - return {static_cast(std::max(std::round(pos.x() * pixel_ratio), qreal{0.0})), - static_cast(std::max(std::round(pos.y() * pixel_ratio), qreal{0.0}))}; -} - void GRenderWindow::closeEvent(QCloseEvent* event) { emit Closed(); QWidget::closeEvent(event); @@ -649,10 +643,9 @@ 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()->PressButton(pos.x(), pos.y(), touch_x, touch_y, button); emit MouseActivity(); } @@ -665,11 +658,10 @@ 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(pos.x(), pos.y(), touch_x, touch_y, center_x, center_y); if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { QCursor::setPos(mapToGlobal(QPoint{center_x, center_y})); @@ -697,8 +689,8 @@ void GRenderWindow::wheelEvent(QWheelEvent* event) { void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { QList 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()); } } @@ -707,8 +699,8 @@ void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) { QList 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(); diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 092c6206f4..627e19f427 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -184,8 +184,6 @@ public: void CaptureScreenshot(const QString& screenshot_path); - std::pair ScaleTouch(const QPointF& pos) const; - /** * Instructs the window to re-launch the application using the specified program_index. * @param program_index Specifies the index within the application of the program to launch. From 17207939e50b64592f93c623219b70d26272df4d Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Thu, 16 Feb 2023 13:38:50 -0600 Subject: [PATCH 2/2] input_common: Split mouse input into individual devices --- src/core/hid/emulated_console.cpp | 3 +- src/core/hid/emulated_devices.cpp | 3 + src/input_common/drivers/mouse.cpp | 67 +++++++++++++------ src/input_common/drivers/mouse.h | 38 +++++++++-- src/input_common/input_mapping.cpp | 4 ++ src/yuzu/bootmanager.cpp | 10 ++- .../configuration/configure_input_player.cpp | 2 +- src/yuzu/configuration/configure_ringcon.cpp | 2 +- src/yuzu/main.cpp | 8 +++ src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | 8 ++- 10 files changed, 114 insertions(+), 31 deletions(-) diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 1c91bbe40c..17d6633798 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -23,7 +23,8 @@ void EmulatedConsole::SetTouchParams() { // We can't use mouse as touch if native mouse is enabled if (!Settings::values.mouse_enabled) { - touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; + touch_params[index++] = + Common::ParamPackage{"engine:mouse,axis_x:0,axis_y:1,button:0,port:2"}; } touch_params[index++] = diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 836f32c0f8..578a6ff612 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -34,9 +34,12 @@ void EmulatedDevices::ReloadInput() { // First two axis are reserved for mouse position key_index = 2; for (auto& mouse_device : mouse_analog_devices) { + // Mouse axis are only mapped on port 1, pad 0 Common::ParamPackage mouse_params; mouse_params.Set("engine", "mouse"); mouse_params.Set("axis", static_cast(key_index)); + mouse_params.Set("port", 1); + mouse_params.Set("pad", 0); mouse_device = Common::Input::CreateInputDevice(mouse_params); key_index++; } diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index faf9cbdc33..da50e0a249 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -15,23 +15,39 @@ 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); + PreSetController(real_mouse_identifier); + PreSetController(touch_identifier); + + // Initialize all mouse axis PreSetAxis(identifier, mouse_axis_x); PreSetAxis(identifier, mouse_axis_y); 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(real_mouse_identifier, mouse_axis_x); + PreSetAxis(real_mouse_identifier, mouse_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); }); } @@ -39,7 +55,7 @@ void Mouse::UpdateThread(std::stop_token stop_token) { Common::SetCurrentThreadName("Mouse"); constexpr int update_time = 10; while (!stop_token.stop_requested()) { - if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { + if (Settings::values.mouse_panning) { // Slow movement by 4% last_mouse_change *= 0.96f; const float sensitivity = @@ -57,17 +73,7 @@ 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) { - // If native mouse is enabled just set the screen coordinates - if (Settings::values.mouse_enabled) { - SetAxis(identifier, mouse_axis_x, touch_x); - SetAxis(identifier, mouse_axis_y, touch_y); - return; - } - - SetAxis(identifier, touch_axis_x, touch_x); - SetAxis(identifier, touch_axis_y, touch_y); - +void Mouse::Move(int x, int y, int center_x, int center_y) { if (Settings::values.mouse_panning) { auto mouse_change = (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast(); @@ -113,20 +119,41 @@ void Mouse::MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int } } -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::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::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(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(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(button), true); +} + void Mouse::ReleaseButton(MouseButton button) { SetButton(identifier, static_cast(button), false); + SetButton(real_mouse_identifier, static_cast(button), false); + SetButton(touch_identifier, static_cast(button), false); - if (!Settings::values.mouse_panning && !Settings::values.mouse_enabled) { + if (!Settings::values.mouse_panning) { SetAxis(identifier, mouse_axis_x, 0); SetAxis(identifier, mouse_axis_y, 0); } diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 72073cc232..f3b65bdd1d 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -37,13 +37,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 diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp index d6e49d2c5b..6990a86b9e 100644 --- a/src/input_common/input_mapping.cpp +++ b/src/input_common/input_mapping.cpp @@ -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 (!Settings::values.enable_udp_controller && data.engine == "cemuhookudp" && data.type != EngineInputType::Motion) { diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index a64e63a399..17acd3933b 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -645,7 +645,10 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) { const auto pos = mapFromGlobal(QCursor::pos()); const auto [touch_x, touch_y] = MapToTouchScreen(pos.x(), pos.y()); const auto button = QtButtonToMouseButton(event->button()); - input_subsystem->GetMouse()->PressButton(pos.x(), pos.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(); } @@ -661,7 +664,10 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { 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(pos.x(), pos.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); if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { QCursor::setPos(mapToGlobal(QPoint{center_x, center_y})); diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 723690e710..50b62293eb 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -1490,7 +1490,7 @@ void ConfigureInputPlayer::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 ConfigureInputPlayer::wheelEvent(QWheelEvent* event) { diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index 1275f10c89..71afbc4232 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp @@ -371,7 +371,7 @@ void ConfigureRingController::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 ConfigureRingController::keyPressEvent(QKeyEvent* event) { diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a1c18ff90d..a689a32dbd 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1165,6 +1165,14 @@ void GMainWindow::InitializeHotkeys() { Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue()); }); connect_shortcut(QStringLiteral("Toggle Mouse Panning"), [&] { + if (Settings::values.mouse_enabled) { + Settings::values.mouse_panning = false; + QMessageBox::warning( + this, tr("Emulated mouse is enabled"), + tr("Real mouse input and mouse panning are incompatible. Please disable the " + "emulated mouse in input advanced settings to allow mouse panning.")); + return; + } Settings::values.mouse_panning = !Settings::values.mouse_panning; if (Settings::values.mouse_panning) { render_window->installEventFilter(render_window); diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 5450b8c38a..5153cdb792 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp @@ -62,7 +62,9 @@ void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { const auto mouse_button = SDLButtonToMouseButton(button); if (state == SDL_PRESSED) { const auto [touch_x, touch_y] = MouseToTouchPos(x, y); - input_subsystem->GetMouse()->PressButton(x, y, touch_x, touch_y, mouse_button); + input_subsystem->GetMouse()->PressButton(x, y, mouse_button); + input_subsystem->GetMouse()->PressMouseButton(mouse_button); + input_subsystem->GetMouse()->PressTouchButton(touch_x, touch_y, mouse_button); } else { input_subsystem->GetMouse()->ReleaseButton(mouse_button); } @@ -70,7 +72,9 @@ void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { const auto [touch_x, touch_y] = MouseToTouchPos(x, y); - input_subsystem->GetMouse()->MouseMove(x, y, touch_x, touch_y, 0, 0); + input_subsystem->GetMouse()->Move(x, y, 0, 0); + input_subsystem->GetMouse()->MouseMove(touch_x, touch_y); + input_subsystem->GetMouse()->TouchMove(touch_x, touch_y); } void EmuWindow_SDL2::OnFingerDown(float x, float y, std::size_t id) {