From 466073de1ef288912e823b4f2e71a47ec14b89d3 Mon Sep 17 00:00:00 2001 From: luc-git <102831178+luc-git@users.noreply.github.com> Date: Mon, 5 Jun 2023 20:54:17 +0200 Subject: [PATCH] Confine Mouse (cross platform) * This pull request can confine the mouse cursor cross platform * In bootmanager.cpp the mouse cursor will be warp in the touchscreen area if it exits limits * The mouse cursor is warped too slowly and by clicking the mouse can change the focus window * The transparent QWidget "window_frame" prevent this to happen by showing it at fullscreen --- src/citra_qt/bootmanager.cpp | 67 +++++++++++++++---- src/citra_qt/bootmanager.h | 7 ++ src/citra_qt/configuration/config.cpp | 7 +- src/citra_qt/configuration/config.h | 2 +- src/citra_qt/configuration/configure.ui | 27 ++++---- .../configuration/configure_general.cpp | 4 ++ .../configuration/configure_general.ui | 7 ++ src/citra_qt/main.cpp | 5 ++ src/citra_qt/main.ui | 8 +++ src/citra_qt/uisettings.h | 3 + 10 files changed, 109 insertions(+), 28 deletions(-) diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index c89869418..5b9a238f6 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -12,6 +12,7 @@ #include #include "citra_qt/bootmanager.h" #include "citra_qt/main.h" +#include "citra_qt/uisettings.h" #include "common/color.h" #include "common/microprofile.h" #include "common/scm_rev.h" @@ -48,17 +49,6 @@ EmuThread::EmuThread(Frontend::GraphicsContext& core_context) : core_context(cor EmuThread::~EmuThread() = default; -static GMainWindow* GetMainWindow() { - const auto widgets = qApp->topLevelWidgets(); - for (QWidget* w : widgets) { - if (GMainWindow* main = qobject_cast(w)) { - return main; - } - } - - return nullptr; -} - void EmuThread::run() { MicroProfileOnThreadCreate("EmuThread"); const auto scope = core_context.Acquire(); @@ -386,6 +376,8 @@ GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread_, Core::Sys bool is_secondary_) : QWidget(parent_), EmuWindow(is_secondary_), emu_thread(emu_thread_), system{system_} { + window_frame = new QDialog(this); + window_frame->setWindowOpacity(0.004); setWindowTitle(QStringLiteral("Citra %1 | %2-%3") .arg(QString::fromUtf8(Common::g_build_name), QString::fromUtf8(Common::g_scm_branch), @@ -398,8 +390,8 @@ GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread_, Core::Sys this->setMouseTracking(true); strict_context_required = QGuiApplication::platformName() == QStringLiteral("wayland"); - GMainWindow* parent = GetMainWindow(); - connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); + main_window = qobject_cast(parent_); + connect(this, &GRenderWindow::FirstFrameDisplayed, main_window, &GMainWindow::OnLoadComplete); } GRenderWindow::~GRenderWindow() = default; @@ -486,9 +478,25 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) { return; // touch input is handled in TouchBeginEvent } + if (UISettings::values.confine_mouse_to_the_touchscreen.GetValue() && !confined) { + foreground_window = window(); + child_widget->grabMouse(); + window_frame->showFullScreen(); + foreground_window->move(main_window->pos()); + foreground_window->setFixedSize(main_window->size()); + foreground_window->setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint); + foreground_window->show(); + if (parentWidget() == nullptr) { + main_window->hide(); + } + confined = true; + } auto pos = event->pos(); if (event->button() == Qt::LeftButton) { const auto [x, y] = ScaleTouch(pos); + if (confined) { + ConfineMouse(); + } this->TouchPressed(x, y); } else if (event->button() == Qt::RightButton) { InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y()); @@ -503,6 +511,9 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { auto pos = event->pos(); const auto [x, y] = ScaleTouch(pos); + if (confined) { + ConfineMouse(); + } this->TouchMoved(x, y); InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y()); emit MouseActivity(); @@ -725,6 +736,7 @@ void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) { void GRenderWindow::OnEmulationStopping() { emu_thread = nullptr; + child_widget->releaseMouse(); } void GRenderWindow::showEvent(QShowEvent* event) { @@ -744,3 +756,32 @@ std::unique_ptr GRenderWindow::CreateSharedContext() #endif return std::make_unique(); } + +void GRenderWindow::ConfineMouse() { + auto layout = GetFramebufferLayout(); + auto posi = QCursor::pos(); + qint32 x_limit = + qBound(child_widget->mapToGlobal(QPoint(layout.bottom_screen.left, 0)).x(), posi.x(), + child_widget->mapToGlobal(QPoint(layout.bottom_screen.right, 0)).x()); + qint32 y_limit = + qBound(child_widget->mapToGlobal(QPoint(0, layout.bottom_screen.top)).y(), posi.y(), + child_widget->mapToGlobal(QPoint(0, layout.bottom_screen.bottom)).y()); + if (x_limit != posi.x() || y_limit != posi.y()) { + QCursor::setPos(x_limit, y_limit); + } +} + +void GRenderWindow::UnconfineMouse() { + if (!confined) { + return; + } + child_widget->releaseMouse(); + confined = false; + window_frame->close(); + foreground_window->setWindowFlags(Qt::Window); + foreground_window->setFixedSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); + foreground_window->show(); + if (parentWidget() == nullptr) { + main_window->show(); + } +} diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h index 59cdfab71..bfe85e8ab 100644 --- a/src/citra_qt/bootmanager.h +++ b/src/citra_qt/bootmanager.h @@ -17,6 +17,7 @@ class QKeyEvent; class QTouchEvent; class GRenderWindow; +class GMainWindow; namespace VideoCore { enum class LoadCallbackStage; @@ -161,6 +162,7 @@ public slots: void OnEmulationStarting(EmuThread* emu_thread); void OnEmulationStopping(); void OnFramebufferSizeChanged(); + void UnconfineMouse(); signals: /// Emitted when the window is closed @@ -178,12 +180,15 @@ private: void TouchBeginEvent(const QTouchEvent* event); void TouchUpdateEvent(const QTouchEvent* event); void TouchEndEvent(); + void ConfineMouse(); void OnMinimalClientAreaChangeRequest(std::pair minimal_size) override; bool InitializeOpenGL(); void InitializeSoftware(); bool LoadOpenGL(); + GMainWindow* main_window; + QDialog* window_frame; QWidget* child_widget = nullptr; @@ -200,6 +205,8 @@ private: QByteArray geometry; bool first_frame = false; bool has_focus = false; + bool confined = false; + QWidget* foreground_window; protected: void showEvent(QShowEvent* event) override; diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index 60b641397..824f9ef91 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -6,6 +6,7 @@ #include #include #include +#include "citra_qt/bootmanager.h" #include "citra_qt/configuration/config.h" #include "common/file_util.h" #include "common/settings.h" @@ -54,7 +55,7 @@ const std::array, Settings::NativeAnalog::NumAnalogs> Config: // This must be in alphabetical order according to action name as it must have the same order as // UISetting::values.shortcuts, which is alphabetically ordered. // clang-format off -const std::array Config::default_hotkeys {{ +const std::array Config::default_hotkeys {{ {QStringLiteral("Advance Frame"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::ApplicationShortcut}}, {QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::WidgetWithChildrenShortcut}}, {QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), Qt::WindowShortcut}}, @@ -83,6 +84,7 @@ const std::array Config::default_hotkeys {{ {QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), Qt::WindowShortcut}}, {QStringLiteral("Toggle Texture Dumping"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::ApplicationShortcut}}, {QStringLiteral("Toggle Custom Textures"), QStringLiteral("Main Window"), {QStringLiteral("F7"), Qt::ApplicationShortcut}}, + {QStringLiteral("Unconfine Mouse Cursor"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+U"), Qt::ApplicationShortcut}} }}; // clang-format on @@ -651,6 +653,7 @@ void Config::ReadShortcutValues() { qt_config->beginGroup(QStringLiteral("Shortcuts")); for (const auto& [name, group, shortcut] : default_hotkeys) { + auto [keyseq, context] = shortcut; qt_config->beginGroup(group); qt_config->beginGroup(name); // No longer using ReadSetting for shortcut.second as it innacurately returns a value of 1 @@ -759,6 +762,7 @@ void Config::ReadUIValues() { ReadBasicSetting(UISettings::values.pause_when_in_background); ReadBasicSetting(UISettings::values.hide_mouse); } + UISettings::values.hide_mouse = ReadSetting(QStringLiteral("ConfineMouse"), false).toBool(); qt_config->endGroup(); } @@ -1216,6 +1220,7 @@ void Config::SaveUIValues() { WriteBasicSetting(UISettings::values.show_console); WriteBasicSetting(UISettings::values.pause_when_in_background); WriteBasicSetting(UISettings::values.hide_mouse); + WriteBasicSetting(UISettings::values.confine_mouse_to_the_touchscreen); } qt_config->endGroup(); diff --git a/src/citra_qt/configuration/config.h b/src/citra_qt/configuration/config.h index 572745055..775d34350 100644 --- a/src/citra_qt/configuration/config.h +++ b/src/citra_qt/configuration/config.h @@ -26,7 +26,7 @@ public: static const std::array default_buttons; static const std::array, Settings::NativeAnalog::NumAnalogs> default_analogs; - static const std::array default_hotkeys; + static const std::array default_hotkeys; private: void Initialize(const std::string& config_name); diff --git a/src/citra_qt/configuration/configure.ui b/src/citra_qt/configuration/configure.ui index 1774ccbc1..9e4cd1e19 100644 --- a/src/citra_qt/configuration/configure.ui +++ b/src/citra_qt/configuration/configure.ui @@ -2,6 +2,14 @@ ConfigureDialog + + + 0 + 0 + 382 + 242 + + Citra Configuration @@ -9,19 +17,12 @@ - - - 150 - - - 150 - - + - 0 + 6 @@ -49,9 +50,9 @@ - - Enhancements - + + Enhancements + @@ -127,7 +128,7 @@
configuration/configure_debug.h
1 - + ConfigureStorage QWidget
configuration/configure_storage.h
diff --git a/src/citra_qt/configuration/configure_general.cpp b/src/citra_qt/configuration/configure_general.cpp index 3a223398f..74d0e476d 100644 --- a/src/citra_qt/configuration/configure_general.cpp +++ b/src/citra_qt/configuration/configure_general.cpp @@ -75,6 +75,8 @@ void ConfigureGeneral::SetConfiguration() { ui->toggle_update_check->setChecked( UISettings::values.check_for_update_on_start.GetValue()); ui->toggle_auto_update->setChecked(UISettings::values.update_on_close.GetValue()); + ui->toggle_confine_mouse_touchscreen->setChecked( + UISettings::values.confine_mouse_to_the_touchscreen.GetValue()); } if (Settings::values.frame_limit.GetValue() == 0) { @@ -171,6 +173,8 @@ void ConfigureGeneral::ApplyConfiguration() { UISettings::values.check_for_update_on_start = ui->toggle_update_check->isChecked(); UISettings::values.update_on_close = ui->toggle_auto_update->isChecked(); + UISettings::values.confine_mouse_to_the_touchscreen = + ui->toggle_confine_mouse_touchscreen->isChecked(); } } diff --git a/src/citra_qt/configuration/configure_general.ui b/src/citra_qt/configuration/configure_general.ui index 4452d69e4..b490ec458 100644 --- a/src/citra_qt/configuration/configure_general.ui +++ b/src/citra_qt/configuration/configure_general.ui @@ -43,6 +43,13 @@
+ + + + confine mouse touchscreen + + +
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 4f889cf22..76d74fca4 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -525,6 +525,7 @@ void GMainWindow::InitializeHotkeys() { const QString main_window = QStringLiteral("Main Window"); const QString fullscreen = QStringLiteral("Fullscreen"); + const QString unconfine_mouse = QStringLiteral("Unconfine Mouse Cursor"); const QString toggle_screen_layout = QStringLiteral("Toggle Screen Layout"); const QString swap_screens = QStringLiteral("Swap Screens"); const QString rotate_screens = QStringLiteral("Rotate Screens Upright"); @@ -655,6 +656,8 @@ void GMainWindow::InitializeHotkeys() { UpdateStatusBar(); } }); + connect(hotkey_registry.GetHotkey(main_window, unconfine_mouse, render_window), + &QShortcut::activated, ui->action_Unconfine_Mouse, &QAction::trigger); } void GMainWindow::SetDefaultUIGeometry() { @@ -749,6 +752,8 @@ void GMainWindow::ConnectWidgetEvents() { connect(this, &GMainWindow::CIAInstallFinished, this, &GMainWindow::OnCIAInstallFinished); connect(this, &GMainWindow::UpdateThemedIcons, multiplayer_state, &MultiplayerState::UpdateThemedIcons); + connect(ui->action_Unconfine_Mouse, &QAction::triggered, render_window, + &GRenderWindow::UnconfineMouse); } void GMainWindow::ConnectMenuEvents() { diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index 557322750..8eedd5c5f 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui @@ -601,6 +601,14 @@ QAction::NoRole + + + Unconfine Mouse + + + Unconfine the mouse cursor + + diff --git a/src/citra_qt/uisettings.h b/src/citra_qt/uisettings.h index 3bee8ffcb..4424860f9 100644 --- a/src/citra_qt/uisettings.h +++ b/src/citra_qt/uisettings.h @@ -133,6 +133,9 @@ struct Values { // logging Settings::Setting show_console{false, "showConsole"}; + + // ConfineMouse + Settings::Setting confine_mouse_to_the_touchscreen{false, "ConfineMouse"}; }; extern Values values;