From 8042ce7e1999e7953db804f852799cb33d08f91c Mon Sep 17 00:00:00 2001
From: Narr the Reg <juangerman-13@hotmail.com>
Date: Thu, 5 Jan 2023 19:16:55 -0600
Subject: [PATCH] input_common: Create an update engine

---
 src/common/input.h                            |  3 ---
 src/core/hid/emulated_controller.cpp          | 10 -------
 .../helpers/stick_from_buttons.cpp            | 17 +++++++-----
 src/input_common/main.cpp                     | 26 +++++++++++++++++++
 4 files changed, 37 insertions(+), 19 deletions(-)

diff --git a/src/common/input.h b/src/common/input.h
index fc14fd7bf..d27b1d772 100644
--- a/src/common/input.h
+++ b/src/common/input.h
@@ -292,9 +292,6 @@ class InputDevice {
 public:
     virtual ~InputDevice() = default;
 
-    // Request input device to update if necessary
-    virtual void SoftUpdate() {}
-
     // Force input device to update data regardless of the current state
     virtual void ForceUpdate() {}
 
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 71364c323..7a01f3f4c 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -1434,16 +1434,6 @@ AnalogSticks EmulatedController::GetSticks() const {
         return {};
     }
 
-    // Some drivers like stick from buttons need constant refreshing
-    for (auto& device : stick_devices) {
-        if (!device) {
-            continue;
-        }
-        lock.unlock();
-        device->SoftUpdate();
-        lock.lock();
-    }
-
     return controller.analog_stick_state;
 }
 
diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp
index 82aa6ac2f..f3a0b3419 100644
--- a/src/input_common/helpers/stick_from_buttons.cpp
+++ b/src/input_common/helpers/stick_from_buttons.cpp
@@ -13,11 +13,11 @@ class Stick final : public Common::Input::InputDevice {
 public:
     using Button = std::unique_ptr<Common::Input::InputDevice>;
 
-    Stick(Button up_, Button down_, Button left_, Button right_, Button modifier_,
+    Stick(Button up_, Button down_, Button left_, Button right_, Button modifier_, Button updater_,
           float modifier_scale_, float modifier_angle_)
         : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)),
-          right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_),
-          modifier_angle(modifier_angle_) {
+          right(std::move(right_)), modifier(std::move(modifier_)), updater(std::move(updater_)),
+          modifier_scale(modifier_scale_), modifier_angle(modifier_angle_) {
         up->SetCallback({
             .on_change =
                 [this](const Common::Input::CallbackStatus& callback_) {
@@ -48,6 +48,9 @@ public:
                     UpdateModButtonStatus(callback_);
                 },
         });
+        updater->SetCallback({
+            .on_change = [this](const Common::Input::CallbackStatus& callback_) { SoftUpdate(); },
+        });
         last_x_axis_value = 0.0f;
         last_y_axis_value = 0.0f;
     }
@@ -248,7 +251,7 @@ public:
         modifier->ForceUpdate();
     }
 
-    void SoftUpdate() override {
+    void SoftUpdate() {
         Common::Input::CallbackStatus status{
             .type = Common::Input::InputType::Stick,
             .stick_status = GetStatus(),
@@ -308,6 +311,7 @@ private:
     Button left;
     Button right;
     Button modifier;
+    Button updater;
     float modifier_scale{};
     float modifier_angle{};
     float angle{};
@@ -331,11 +335,12 @@ std::unique_ptr<Common::Input::InputDevice> StickFromButton::Create(
     auto left = Common::Input::CreateInputDeviceFromString(params.Get("left", null_engine));
     auto right = Common::Input::CreateInputDeviceFromString(params.Get("right", null_engine));
     auto modifier = Common::Input::CreateInputDeviceFromString(params.Get("modifier", null_engine));
+    auto updater = Common::Input::CreateInputDeviceFromString("engine:updater,button:0");
     auto modifier_scale = params.Get("modifier_scale", 0.5f);
     auto modifier_angle = params.Get("modifier_angle", 5.5f);
     return std::make_unique<Stick>(std::move(up), std::move(down), std::move(left),
-                                   std::move(right), std::move(modifier), modifier_scale,
-                                   modifier_angle);
+                                   std::move(right), std::move(modifier), std::move(updater),
+                                   modifier_scale, modifier_angle);
 }
 
 } // namespace InputCommon
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 4dc92f482..e0b2131ed 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -28,6 +28,28 @@
 
 namespace InputCommon {
 
+/// Dummy engine to get periodic updates
+class UpdateEngine final : public InputEngine {
+public:
+    explicit UpdateEngine(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
+        PreSetController(identifier);
+    }
+
+    void PumpEvents() {
+        SetButton(identifier, 0, last_state);
+        last_state = !last_state;
+    }
+
+private:
+    static constexpr PadIdentifier identifier = {
+        .guid = Common::UUID{},
+        .port = 0,
+        .pad = 0,
+    };
+
+    bool last_state{};
+};
+
 struct InputSubsystem::Impl {
     template <typename Engine>
     void RegisterEngine(std::string name, std::shared_ptr<Engine>& engine) {
@@ -45,6 +67,7 @@ struct InputSubsystem::Impl {
     void Initialize() {
         mapping_factory = std::make_shared<MappingFactory>();
 
+        RegisterEngine("updater", update_engine);
         RegisterEngine("keyboard", keyboard);
         RegisterEngine("mouse", mouse);
         RegisterEngine("touch", touch_screen);
@@ -74,6 +97,7 @@ struct InputSubsystem::Impl {
     }
 
     void Shutdown() {
+        UnregisterEngine(update_engine);
         UnregisterEngine(keyboard);
         UnregisterEngine(mouse);
         UnregisterEngine(touch_screen);
@@ -252,6 +276,7 @@ struct InputSubsystem::Impl {
     }
 
     void PumpEvents() const {
+        update_engine->PumpEvents();
 #ifdef HAVE_SDL2
         sdl->PumpEvents();
 #endif
@@ -263,6 +288,7 @@ struct InputSubsystem::Impl {
 
     std::shared_ptr<MappingFactory> mapping_factory;
 
+    std::shared_ptr<UpdateEngine> update_engine;
     std::shared_ptr<Keyboard> keyboard;
     std::shared_ptr<Mouse> mouse;
     std::shared_ptr<TouchScreen> touch_screen;