From cf27b36f44c60f9ee03c4947815770f00ba8c10f Mon Sep 17 00:00:00 2001
From: pineappleEA <pineaea@gmail.com>
Date: Sun, 7 Mar 2021 01:23:43 +0100
Subject: [PATCH] early-access version 1508

---
 README.md                                     |  2 +-
 src/input_common/keyboard.cpp                 | 12 ++++---
 src/input_common/mouse/mouse_input.cpp        | 36 +++++++++++++++++++
 src/input_common/mouse/mouse_input.h          |  5 +++
 src/input_common/mouse/mouse_poller.cpp       | 20 ++++++++---
 .../configuration/configure_input_player.cpp  |  3 +-
 6 files changed, 66 insertions(+), 12 deletions(-)

diff --git a/README.md b/README.md
index d3516de6f..0116dfb67 100755
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 yuzu emulator early access
 =============
 
-This is the source code for early-access 1507.
+This is the source code for early-access 1508.
 
 ## Legal Notice
 
diff --git a/src/input_common/keyboard.cpp b/src/input_common/keyboard.cpp
index fa0e60ac1..c467ff4c5 100755
--- a/src/input_common/keyboard.cpp
+++ b/src/input_common/keyboard.cpp
@@ -19,16 +19,18 @@ public:
 
     bool GetStatus() const override {
         if (toggle) {
-            return toggled_status.load();
+            return toggled_status.load(std::memory_order_relaxed);
         }
         return status.load();
     }
 
     void ToggleButton() {
-        if (!lock) {
-            lock = true;
-            toggled_status.store(!toggled_status.load());
+        if (lock) {
+            return;
         }
+        lock = true;
+        const bool old_toggle_status = toggled_status.load();
+        toggled_status.store(!old_toggle_status);
     }
 
     void UnlockButton() {
@@ -41,7 +43,7 @@ private:
     std::shared_ptr<KeyButtonList> key_button_list;
     std::atomic<bool> status{false};
     std::atomic<bool> toggled_status{false};
-    bool lock = {};
+    bool lock{false};
     const bool toggle;
 };
 
diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp
index d81e790ee..329e416c7 100755
--- a/src/input_common/mouse/mouse_input.cpp
+++ b/src/input_common/mouse/mouse_input.cpp
@@ -162,6 +162,42 @@ void Mouse::EndConfiguration() {
     configuring = false;
 }
 
+bool Mouse::ToggleButton(std::size_t button_) {
+    if (button_ >= mouse_info.size()) {
+        return false;
+    }
+    const auto button = 1U << button_;
+    const bool button_state = (toggle_buttons & button) != 0;
+    const bool button_lock = (lock_buttons & button) != 0;
+
+    if (button_lock) {
+        return button_state;
+    }
+
+    lock_buttons |= static_cast<u16>(button);
+
+    if (button_state) {
+        toggle_buttons &= static_cast<u16>(0xFF - button);
+    } else {
+        toggle_buttons |= static_cast<u16>(button);
+    }
+
+    return !button_state;
+}
+
+bool Mouse::UnlockButton(std::size_t button_) {
+    if (button_ >= mouse_info.size()) {
+        return false;
+    }
+
+    const auto button = 1U << button_;
+    const bool button_state = (toggle_buttons & button) != 0;
+
+    lock_buttons &= static_cast<u16>(0xFF - button);
+
+    return button_state;
+}
+
 Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() {
     return mouse_queue;
 }
diff --git a/src/input_common/mouse/mouse_input.h b/src/input_common/mouse/mouse_input.h
index 3622fe080..750d9b011 100755
--- a/src/input_common/mouse/mouse_input.h
+++ b/src/input_common/mouse/mouse_input.h
@@ -69,6 +69,9 @@ public:
      */
     void ReleaseButton(MouseButton button_);
 
+    [[nodiscard]] bool ToggleButton(std::size_t button_);
+    [[nodiscard]] bool UnlockButton(std::size_t button_);
+
     [[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue();
     [[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const;
 
@@ -94,6 +97,8 @@ private:
     };
 
     u16 buttons{};
+    u16 toggle_buttons{};
+    u16 lock_buttons{};
     std::thread update_thread;
     MouseButton last_button{MouseButton::Undefined};
     std::array<MouseInfo, 7> mouse_info;
diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp
index bb56787ee..0e1db54fb 100755
--- a/src/input_common/mouse/mouse_poller.cpp
+++ b/src/input_common/mouse/mouse_poller.cpp
@@ -14,16 +14,25 @@ namespace InputCommon {
 
 class MouseButton final : public Input::ButtonDevice {
 public:
-    explicit MouseButton(u32 button_, const MouseInput::Mouse* mouse_input_)
-        : button(button_), mouse_input(mouse_input_) {}
+    explicit MouseButton(u32 button_, bool toggle_, MouseInput::Mouse* mouse_input_)
+        : button(button_), toggle(toggle_), mouse_input(mouse_input_) {}
 
     bool GetStatus() const override {
-        return mouse_input->GetMouseState(button).pressed;
+        const bool button_state = mouse_input->GetMouseState(button).pressed;
+        if (!toggle) {
+            return button_state;
+        }
+
+        if (button_state) {
+            return mouse_input->ToggleButton(button);
+        }
+        return mouse_input->UnlockButton(button);
     }
 
 private:
     const u32 button;
-    const MouseInput::Mouse* mouse_input;
+    const bool toggle;
+    MouseInput::Mouse* mouse_input;
 };
 
 MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
@@ -32,8 +41,9 @@ MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_
 std::unique_ptr<Input::ButtonDevice> MouseButtonFactory::Create(
     const Common::ParamPackage& params) {
     const auto button_id = params.Get("button", 0);
+    const auto toggle = params.Get("toggle", false);
 
-    return std::make_unique<MouseButton>(button_id, mouse_input.get());
+    return std::make_unique<MouseButton>(button_id, toggle, mouse_input.get());
 }
 
 Common::ParamPackage MouseButtonFactory::GetNextInput() const {
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 93e5df655..c9318c562 100755
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -159,7 +159,8 @@ QString ButtonToText(const Common::ParamPackage& param) {
     if (param.Get("engine", "") == "mouse") {
         if (param.Has("button")) {
             const QString button_str = QString::number(int(param.Get("button", 0)));
-            return QObject::tr("Click %1").arg(button_str);
+            const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : "");
+            return QObject::tr("%1Click %2").arg(toggle, button_str);
         }
         return GetKeyName(param.Get("code", 0));
     }