From 1d1329af23221be31c244889609415e0fb0b2641 Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Fri, 20 Jan 2017 22:46:39 +0200
Subject: [PATCH] HID: use ButtonDevice

---
 src/core/frontend/input.h        |  6 +++++
 src/core/hle/service/hid/hid.cpp | 45 +++++++++++++++++++++++++++++++-
 src/core/hle/service/hid/hid.h   |  3 +++
 src/core/settings.cpp            |  3 +++
 src/core/settings.h              | 44 +++++++++++++++++++++++++++++++
 5 files changed, 100 insertions(+), 1 deletion(-)

diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h
index a0c51df0c9..63e64ac67f 100644
--- a/src/core/frontend/input.h
+++ b/src/core/frontend/input.h
@@ -94,4 +94,10 @@ std::unique_ptr<InputDeviceType> CreateDevice(const std::string& params) {
     return pair->second->Create(package);
 }
 
+/**
+ * A button device is an input device that returns bool as status.
+ * true for pressed; false for released.
+ */
+using ButtonDevice = InputDevice<bool>;
+
 } // namespace Input
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index fb3acb507c..0da7314184 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -2,10 +2,14 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <algorithm>
+#include <atomic>
 #include <cmath>
+#include <memory>
 #include "common/logging/log.h"
 #include "core/core_timing.h"
 #include "core/frontend/emu_window.h"
+#include "core/frontend/input.h"
 #include "core/hle/kernel/event.h"
 #include "core/hle/kernel/shared_memory.h"
 #include "core/hle/service/hid/hid.h"
@@ -44,6 +48,10 @@ constexpr u64 pad_update_ticks = BASE_CLOCK_RATE_ARM11 / 234;
 constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE_ARM11 / 104;
 constexpr u64 gyroscope_update_ticks = BASE_CLOCK_RATE_ARM11 / 101;
 
+static std::atomic<bool> is_device_reload_pending;
+static std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
+    buttons;
+
 static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) {
     // 30 degree and 60 degree are angular thresholds for directions
     constexpr float TAN30 = 0.577350269f;
@@ -74,10 +82,38 @@ static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) {
     return state;
 }
 
+static void LoadInputDevices() {
+    std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
+                   Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
+                   buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
+}
+
+static void UnloadInputDevices() {
+    for (auto& button : buttons) {
+        button.reset();
+    }
+}
+
 static void UpdatePadCallback(u64 userdata, int cycles_late) {
     SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
 
-    PadState state = VideoCore::g_emu_window->GetPadState();
+    if (is_device_reload_pending.exchange(false))
+        LoadInputDevices();
+
+    PadState state;
+    using namespace Settings::NativeButton;
+    state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
+    state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
+    state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
+    state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
+    state.right.Assign(buttons[Right - BUTTON_HID_BEGIN]->GetStatus());
+    state.left.Assign(buttons[Left - BUTTON_HID_BEGIN]->GetStatus());
+    state.up.Assign(buttons[Up - BUTTON_HID_BEGIN]->GetStatus());
+    state.down.Assign(buttons[Down - BUTTON_HID_BEGIN]->GetStatus());
+    state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
+    state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
+    state.start.Assign(buttons[Start - BUTTON_HID_BEGIN]->GetStatus());
+    state.select.Assign(buttons[Select - BUTTON_HID_BEGIN]->GetStatus());
 
     // Get current circle pad position and update circle pad direction
     s16 circle_pad_x, circle_pad_y;
@@ -313,6 +349,8 @@ void Init() {
     AddService(new HID_U_Interface);
     AddService(new HID_SPVR_Interface);
 
+    is_device_reload_pending.store(true);
+
     using Kernel::MemoryPermission;
     shared_mem =
         SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read,
@@ -350,6 +388,11 @@ void Shutdown() {
     event_accelerometer = nullptr;
     event_gyroscope = nullptr;
     event_debug_pad = nullptr;
+    UnloadInputDevices();
+}
+
+void ReloadInputDevices() {
+    is_device_reload_pending.store(true);
 }
 
 } // namespace HID
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index c7f4ee1386..b828abe4b5 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -297,5 +297,8 @@ void Init();
 
 /// Shutdown HID service
 void Shutdown();
+
+/// Reload input devices. Used when input configuration changed
+void ReloadInputDevices();
 }
 }
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 3a32b70aa5..a598f9f2f5 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -4,6 +4,7 @@
 
 #include "audio_core/audio_core.h"
 #include "core/gdbstub/gdbstub.h"
+#include "core/hle/service/hid/hid.h"
 #include "settings.h"
 #include "video_core/video_core.h"
 
@@ -29,6 +30,8 @@ void Apply() {
 
     AudioCore::SelectSink(values.sink_id);
     AudioCore::EnableStretching(values.enable_audio_stretching);
+
+    Service::HID::ReloadInputDevices();
 }
 
 } // namespace
diff --git a/src/core/settings.h b/src/core/settings.h
index b6c75531fc..dba57bd6cd 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -69,6 +69,48 @@ static const std::array<Values, NUM_INPUTS> All = {{
 }};
 }
 
+namespace NativeButton {
+enum Values {
+    A,
+    B,
+    X,
+    Y,
+    Up,
+    Down,
+    Left,
+    Right,
+    L,
+    R,
+    Start,
+    Select,
+
+    ZL,
+    ZR,
+
+    Home,
+
+    NumButtons,
+};
+
+constexpr int BUTTON_HID_BEGIN = A;
+constexpr int BUTTON_IR_BEGIN = ZL;
+constexpr int BUTTON_NS_BEGIN = Home;
+
+constexpr int BUTTON_HID_END = BUTTON_IR_BEGIN;
+constexpr int BUTTON_IR_END = BUTTON_NS_BEGIN;
+constexpr int BUTTON_NS_END = NumButtons;
+
+constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN;
+constexpr int NUM_BUTTONS_IR = BUTTON_IR_END - BUTTON_IR_BEGIN;
+constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN;
+
+static const std::array<const char*, NumButtons> mapping = {{
+    "button_a", "button_b", "button_x", "button_y", "button_up", "button_down", "button_left",
+    "button_right", "button_l", "button_r", "button_start", "button_select", "button_zl",
+    "button_zr", "button_home",
+}};
+} // namespace NativeButton
+
 struct Values {
     // CheckNew3DS
     bool is_new_3ds;
@@ -77,6 +119,8 @@ struct Values {
     std::array<int, NativeInput::NUM_INPUTS> input_mappings;
     float pad_circle_modifier_scale;
 
+    std::array<std::string, NativeButton::NumButtons> buttons;
+
     // Core
     bool use_cpu_jit;
 
-- 
GitLab