From 1bd70d73c00697f0705ba9b51da5938146224a18 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Sun, 23 Aug 2020 08:04:26 -0400
Subject: [PATCH] configuration/input: Add support for mouse button clicks

Supports the Left, Right, Middle, Backward and Forward mouse buttons.
---
 .../configuration/configure_input_player.cpp  | 41 +++++++++++++++++--
 .../configuration/configure_input_player.h    |  5 ++-
 .../configuration/configure_input_player.ui   |  2 +-
 .../configure_mouse_advanced.cpp              | 40 ++++++++++++++++--
 .../configuration/configure_mouse_advanced.h  |  5 ++-
 5 files changed, 82 insertions(+), 11 deletions(-)

diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 68d0d5db72..bff90a82e3 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -86,6 +86,16 @@ constexpr int GetIndexFromControllerType(Settings::ControllerType type) {
 
 QString GetKeyName(int key_code) {
     switch (key_code) {
+    case Qt::LeftButton:
+        return QObject::tr("Click 0");
+    case Qt::RightButton:
+        return QObject::tr("Click 1");
+    case Qt::MiddleButton:
+        return QObject::tr("Click 2");
+    case Qt::BackButton:
+        return QObject::tr("Click 3");
+    case Qt::ForwardButton:
+        return QObject::tr("Click 4");
     case Qt::Key_Shift:
         return QObject::tr("Shift");
     case Qt::Key_Control:
@@ -648,9 +658,9 @@ void ConfigureInputPlayer::HandleClick(
     button->setText(tr("[waiting]"));
     button->setFocus();
 
-    // The first two input devices are always Any and Keyboard. If the user filtered to a
-    // controller, then they don't want keyboard input
-    want_keyboard_keys = ui->comboDevices->currentIndex() < 2;
+    // The first two input devices are always Any and Keyboard/Mouse. If the user filtered to a
+    // controller, then they don't want keyboard/mouse input
+    want_keyboard_mouse = ui->comboDevices->currentIndex() < 2;
 
     input_setter = new_input_setter;
 
@@ -660,6 +670,9 @@ void ConfigureInputPlayer::HandleClick(
         poller->Start();
     }
 
+    QWidget::grabMouse();
+    QWidget::grabKeyboard();
+
     if (type == InputCommon::Polling::DeviceType::Button) {
         InputCommon::GetGCButtons()->BeginConfiguration();
     } else {
@@ -677,6 +690,9 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params,
         poller->Stop();
     }
 
+    QWidget::releaseMouse();
+    QWidget::releaseKeyboard();
+
     InputCommon::GetGCButtons()->EndConfiguration();
     InputCommon::GetGCAnalogs()->EndConfiguration();
 
@@ -688,13 +704,29 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params,
     input_setter = std::nullopt;
 }
 
+void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) {
+    if (!input_setter || !event) {
+        return;
+    }
+
+    if (want_keyboard_mouse) {
+        SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->button())},
+                         false);
+    } else {
+        // We don't want any mouse buttons, so don't stop polling
+        return;
+    }
+
+    SetPollingResult({}, true);
+}
+
 void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
     if (!input_setter || !event) {
         return;
     }
 
     if (event->key() != Qt::Key_Escape) {
-        if (want_keyboard_keys) {
+        if (want_keyboard_mouse) {
             SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
                              false);
         } else {
@@ -702,6 +734,7 @@ void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
             return;
         }
     }
+
     SetPollingResult({}, true);
 }
 
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index a86db82006..ca189019df 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -85,6 +85,9 @@ private:
     /// Finish polling and configure input using the input_setter.
     void SetPollingResult(const Common::ParamPackage& params, bool abort);
 
+    /// Handle mouse button press events.
+    void mousePressEvent(QMouseEvent* event) override;
+
     /// Handle key press events.
     void keyPressEvent(QKeyEvent* event) override;
 
@@ -150,7 +153,7 @@ private:
 
     /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
     /// keyboard events are ignored.
-    bool want_keyboard_keys = false;
+    bool want_keyboard_mouse = false;
 
     /// List of physical devices users can map with. If a SDL backed device is selected, then you
     /// can usue this device to get a default mapping.
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui
index eb826a9359..9bc6818944 100644
--- a/src/yuzu/configuration/configure_input_player.ui
+++ b/src/yuzu/configuration/configure_input_player.ui
@@ -143,7 +143,7 @@
             </item>
             <item>
              <property name="text">
-              <string>Keyboard</string>
+              <string>Keyboard/Mouse</string>
              </property>
             </item>
            </widget>
diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp
index 95e1ae8733..dcda8ab141 100644
--- a/src/yuzu/configuration/configure_mouse_advanced.cpp
+++ b/src/yuzu/configuration/configure_mouse_advanced.cpp
@@ -18,6 +18,16 @@
 
 static QString GetKeyName(int key_code) {
     switch (key_code) {
+    case Qt::LeftButton:
+        return QObject::tr("Click 0");
+    case Qt::RightButton:
+        return QObject::tr("Click 1");
+    case Qt::MiddleButton:
+        return QObject::tr("Click 2");
+    case Qt::BackButton:
+        return QObject::tr("Click 3");
+    case Qt::ForwardButton:
+        return QObject::tr("Click 4");
     case Qt::Key_Shift:
         return QObject::tr("Shift");
     case Qt::Key_Control:
@@ -188,9 +198,9 @@ void ConfigureMouseAdvanced::HandleClick(
     button->setText(tr("[press key]"));
     button->setFocus();
 
-    // Keyboard keys can only be used as button devices
-    want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button;
-    if (want_keyboard_keys) {
+    // Keyboard keys or mouse buttons can only be used as button devices
+    want_keyboard_mouse = type == InputCommon::Polling::DeviceType::Button;
+    if (want_keyboard_mouse) {
         const auto iter = std::find(button_map.begin(), button_map.end(), button);
         ASSERT(iter != button_map.end());
         const auto index = std::distance(button_map.begin(), iter);
@@ -205,6 +215,9 @@ void ConfigureMouseAdvanced::HandleClick(
         poller->Start();
     }
 
+    QWidget::grabMouse();
+    QWidget::grabKeyboard();
+
     timeout_timer->start(2500); // Cancel after 2.5 seconds
     poll_timer->start(50);      // Check for new inputs every 50ms
 }
@@ -216,6 +229,9 @@ void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params
         poller->Stop();
     }
 
+    QWidget::releaseMouse();
+    QWidget::releaseKeyboard();
+
     if (!abort) {
         (*input_setter)(params);
     }
@@ -224,13 +240,29 @@ void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params
     input_setter = std::nullopt;
 }
 
+void ConfigureMouseAdvanced::mousePressEvent(QMouseEvent* event) {
+    if (!input_setter || !event) {
+        return;
+    }
+
+    if (want_keyboard_mouse) {
+        SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->button())},
+                         false);
+    } else {
+        // We don't want any mouse buttons, so don't stop polling
+        return;
+    }
+
+    SetPollingResult({}, true);
+}
+
 void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) {
     if (!input_setter || !event) {
         return;
     }
 
     if (event->key() != Qt::Key_Escape) {
-        if (want_keyboard_keys) {
+        if (want_keyboard_mouse) {
             SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
                              false);
         } else {
diff --git a/src/yuzu/configuration/configure_mouse_advanced.h b/src/yuzu/configuration/configure_mouse_advanced.h
index 342b824128..e7d27dab7b 100644
--- a/src/yuzu/configuration/configure_mouse_advanced.h
+++ b/src/yuzu/configuration/configure_mouse_advanced.h
@@ -49,6 +49,9 @@ private:
     /// Finish polling and configure input using the input_setter
     void SetPollingResult(const Common::ParamPackage& params, bool abort);
 
+    /// Handle mouse button press events.
+    void mousePressEvent(QMouseEvent* event) override;
+
     /// Handle key press events.
     void keyPressEvent(QKeyEvent* event) override;
 
@@ -67,5 +70,5 @@ private:
 
     /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
     /// keyboard events are ignored.
-    bool want_keyboard_keys = false;
+    bool want_keyboard_mouse = false;
 };