From 03631f9b8fe75cf1c3a70a3094aeddcebffa4cf9 Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Thu, 12 May 2016 13:09:36 +0300
Subject: Refactor input subsystem

---
 src/common/key_map.cpp | 112 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 106 insertions(+), 6 deletions(-)

(limited to 'src/common/key_map.cpp')

diff --git a/src/common/key_map.cpp b/src/common/key_map.cpp
index 844d5df68b..c8f168aa11 100644
--- a/src/common/key_map.cpp
+++ b/src/common/key_map.cpp
@@ -2,24 +2,124 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "key_map.h"
 #include <map>
 
+#include "common/emu_window.h"
+#include "common/key_map.h"
+
 namespace KeyMap {
 
-static std::map<HostDeviceKey, Service::HID::PadState> key_map;
+// TODO (wwylele): currently we treat c-stick as four direction buttons
+//     and map it directly to EmuWindow::ButtonPressed.
+//     It should go the analog input way like circle pad does.
+const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{
+    Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y,
+    Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR,
+    Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE,
+    Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT,
+    Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT,
+
+    IndirectTarget::CIRCLE_PAD_UP,
+    IndirectTarget::CIRCLE_PAD_DOWN,
+    IndirectTarget::CIRCLE_PAD_LEFT,
+    IndirectTarget::CIRCLE_PAD_RIGHT,
+}};
+
+static std::map<HostDeviceKey, KeyTarget> key_map;
 static int next_device_id = 0;
 
+static bool circle_pad_up = false, circle_pad_down = false, circle_pad_left = false, circle_pad_right = false;
+
+static void UpdateCirclePad(EmuWindow& emu_window) {
+    constexpr float SQRT_HALF = 0.707106781;
+    int x = 0, y = 0;
+
+    if (circle_pad_right)
+        ++x;
+    if (circle_pad_left)
+        --x;
+    if (circle_pad_up)
+        ++y;
+    if (circle_pad_down)
+        --y;
+    // TODO: apply modifier here
+    emu_window.CirclePadUpdated(x * (y == 0 ? 1.0 : SQRT_HALF), y * (x == 0 ? 1.0 : SQRT_HALF));
+}
+
 int NewDeviceId() {
     return next_device_id++;
 }
 
-void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState) {
-    key_map[key].hex = padState.hex;
+void SetKeyMapping(HostDeviceKey key, KeyTarget target) {
+    key_map[key] = target;
 }
 
-Service::HID::PadState GetPadKey(HostDeviceKey key) {
-    return key_map[key];
+void ClearKeyMapping(int device_id) {
+    auto iter = key_map.begin();
+    while (iter != key_map.end()) {
+        if (iter->first.device_id == device_id)
+            key_map.erase(iter++);
+        else
+            ++iter;
+    }
+}
+
+void PressKey(EmuWindow& emu_window, HostDeviceKey key) {
+    auto target = key_map.find(key);
+    if (target == key_map.end())
+        return;
+
+    if (target->second.direct) {
+        emu_window.ButtonPressed({{target->second.target.direct_target_hex}});
+    } else {
+        switch (target->second.target.indirect_target) {
+        case IndirectTarget::CIRCLE_PAD_UP:
+            circle_pad_up = true;
+            UpdateCirclePad(emu_window);
+            break;
+        case IndirectTarget::CIRCLE_PAD_DOWN:
+            circle_pad_down = true;
+            UpdateCirclePad(emu_window);
+            break;
+        case IndirectTarget::CIRCLE_PAD_LEFT:
+            circle_pad_left = true;
+            UpdateCirclePad(emu_window);
+            break;
+        case IndirectTarget::CIRCLE_PAD_RIGHT:
+            circle_pad_right = true;
+            UpdateCirclePad(emu_window);
+            break;
+        }
+    }
+}
+
+void ReleaseKey(EmuWindow& emu_window,HostDeviceKey key) {
+    auto target = key_map.find(key);
+    if (target == key_map.end())
+        return;
+
+    if (target->second.direct) {
+        emu_window.ButtonReleased({{target->second.target.direct_target_hex}});
+    } else {
+        switch (target->second.target.indirect_target) {
+        case IndirectTarget::CIRCLE_PAD_UP:
+            circle_pad_up = false;
+            UpdateCirclePad(emu_window);
+            break;
+        case IndirectTarget::CIRCLE_PAD_DOWN:
+            circle_pad_down = false;
+            UpdateCirclePad(emu_window);
+            break;
+        case IndirectTarget::CIRCLE_PAD_LEFT:
+            circle_pad_left = false;
+            UpdateCirclePad(emu_window);
+            break;
+        case IndirectTarget::CIRCLE_PAD_RIGHT:
+            circle_pad_right = false;
+            UpdateCirclePad(emu_window);
+            break;
+        }
+    }
 }
 
 }
-- 
cgit v1.2.3-70-g09d2