summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorGravatar bunnei2016-06-10 22:28:58 -0400
committerGravatar GitHub2016-06-10 22:28:58 -0400
commitf99961581ee129c44625dbd8890fab349253271a (patch)
tree9a2610d391d795b533054a91c22763e869bdd62b /src/common
parentMerge pull request #1896 from citra-emu/revert-1893-interpreter-split (diff)
parentfixup! fixup! Refactor input system (diff)
downloadyuzu-f99961581ee129c44625dbd8890fab349253271a.tar.gz
yuzu-f99961581ee129c44625dbd8890fab349253271a.tar.xz
yuzu-f99961581ee129c44625dbd8890fab349253271a.zip
Merge pull request #1789 from wwylele/input-refactor
Refactor input mapping & implement circle pad modifier
Diffstat (limited to 'src/common')
-rw-r--r--src/common/emu_window.cpp24
-rw-r--r--src/common/emu_window.h46
-rw-r--r--src/common/key_map.cpp126
-rw-r--r--src/common/key_map.h59
4 files changed, 232 insertions, 23 deletions
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index b2807354a..08270dd88 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -11,12 +11,28 @@
11#include "emu_window.h" 11#include "emu_window.h"
12#include "video_core/video_core.h" 12#include "video_core/video_core.h"
13 13
14void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) { 14void EmuWindow::ButtonPressed(Service::HID::PadState pad) {
15 pad_state.hex |= KeyMap::GetPadKey(key).hex; 15 pad_state.hex |= pad.hex;
16} 16}
17 17
18void EmuWindow::KeyReleased(KeyMap::HostDeviceKey key) { 18void EmuWindow::ButtonReleased(Service::HID::PadState pad) {
19 pad_state.hex &= ~KeyMap::GetPadKey(key).hex; 19 pad_state.hex &= ~pad.hex;
20}
21
22void EmuWindow::CirclePadUpdated(float x, float y) {
23 constexpr int MAX_CIRCLEPAD_POS = 0x9C; // Max value for a circle pad position
24
25 // Make sure the coordinates are in the unit circle,
26 // otherwise normalize it.
27 float r = x * x + y * y;
28 if (r > 1) {
29 r = std::sqrt(r);
30 x /= r;
31 y /= r;
32 }
33
34 circle_pad_x = static_cast<s16>(x * MAX_CIRCLEPAD_POS);
35 circle_pad_y = static_cast<s16>(y * MAX_CIRCLEPAD_POS);
20} 36}
21 37
22/** 38/**
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index 7c3486dea..57e303b6d 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -12,10 +12,6 @@
12 12
13#include "core/hle/service/hid/hid.h" 13#include "core/hle/service/hid/hid.h"
14 14
15namespace KeyMap {
16struct HostDeviceKey;
17}
18
19/** 15/**
20 * Abstraction class used to provide an interface between emulation code and the frontend 16 * Abstraction class used to provide an interface between emulation code and the frontend
21 * (e.g. SDL, QGLWidget, GLFW, etc...). 17 * (e.g. SDL, QGLWidget, GLFW, etc...).
@@ -76,11 +72,27 @@ public:
76 72
77 virtual void ReloadSetKeymaps() = 0; 73 virtual void ReloadSetKeymaps() = 0;
78 74
79 /// Signals a key press action to the HID module 75 /**
80 void KeyPressed(KeyMap::HostDeviceKey key); 76 * Signals a button press action to the HID module.
77 * @param pad_state indicates which button to press
78 * @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad.
79 */
80 void ButtonPressed(Service::HID::PadState pad_state);
81
82 /**
83 * Signals a button release action to the HID module.
84 * @param pad_state indicates which button to press
85 * @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad.
86 */
87 void ButtonReleased(Service::HID::PadState pad_state);
81 88
82 /// Signals a key release action to the HID module 89 /**
83 void KeyReleased(KeyMap::HostDeviceKey key); 90 * Signals a circle pad change action to the HID module.
91 * @param x new x-coordinate of the circle pad, in the range [-1.0, 1.0]
92 * @param y new y-coordinate of the circle pad, in the range [-1.0, 1.0]
93 * @note the coordinates will be normalized if the radius is larger than 1
94 */
95 void CirclePadUpdated(float x, float y);
84 96
85 /** 97 /**
86 * Signal that a touch pressed event has occurred (e.g. mouse click pressed) 98 * Signal that a touch pressed event has occurred (e.g. mouse click pressed)
@@ -100,8 +112,9 @@ public:
100 void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y); 112 void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y);
101 113
102 /** 114 /**
103 * Gets the current pad state (which buttons are pressed and the circle pad direction). 115 * Gets the current pad state (which buttons are pressed).
104 * @note This should be called by the core emu thread to get a state set by the window thread. 116 * @note This should be called by the core emu thread to get a state set by the window thread.
117 * @note This doesn't include analog input like circle pad direction
105 * @todo Fix this function to be thread-safe. 118 * @todo Fix this function to be thread-safe.
106 * @return PadState object indicating the current pad state 119 * @return PadState object indicating the current pad state
107 */ 120 */
@@ -110,6 +123,16 @@ public:
110 } 123 }
111 124
112 /** 125 /**
126 * Gets the current circle pad state.
127 * @note This should be called by the core emu thread to get a state set by the window thread.
128 * @todo Fix this function to be thread-safe.
129 * @return std::tuple of (x, y), where `x` and `y` are the circle pad coordinates
130 */
131 std::tuple<s16, s16> GetCirclePadState() const {
132 return std::make_tuple(circle_pad_x, circle_pad_y);
133 }
134
135 /**
113 * Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed). 136 * Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed).
114 * @note This should be called by the core emu thread to get a state set by the window thread. 137 * @note This should be called by the core emu thread to get a state set by the window thread.
115 * @todo Fix this function to be thread-safe. 138 * @todo Fix this function to be thread-safe.
@@ -200,6 +223,8 @@ protected:
200 pad_state.hex = 0; 223 pad_state.hex = 0;
201 touch_x = 0; 224 touch_x = 0;
202 touch_y = 0; 225 touch_y = 0;
226 circle_pad_x = 0;
227 circle_pad_y = 0;
203 touch_pressed = false; 228 touch_pressed = false;
204 } 229 }
205 virtual ~EmuWindow() {} 230 virtual ~EmuWindow() {}
@@ -260,6 +285,9 @@ private:
260 u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) 285 u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320)
261 u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240) 286 u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240)
262 287
288 s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156)
289 s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156)
290
263 /** 291 /**
264 * Clip the provided coordinates to be inside the touchscreen area. 292 * Clip the provided coordinates to be inside the touchscreen area.
265 */ 293 */
diff --git a/src/common/key_map.cpp b/src/common/key_map.cpp
index 844d5df68..ad311d66b 100644
--- a/src/common/key_map.cpp
+++ b/src/common/key_map.cpp
@@ -2,24 +2,138 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "key_map.h"
6#include <map> 5#include <map>
7 6
7#include "common/emu_window.h"
8#include "common/key_map.h"
9
8namespace KeyMap { 10namespace KeyMap {
9 11
10static std::map<HostDeviceKey, Service::HID::PadState> key_map; 12// TODO (wwylele): currently we treat c-stick as four direction buttons
13// and map it directly to EmuWindow::ButtonPressed.
14// It should go the analog input way like circle pad does.
15const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{
16 Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y,
17 Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR,
18 Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE,
19 Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT,
20 Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT,
21
22 IndirectTarget::CirclePadUp,
23 IndirectTarget::CirclePadDown,
24 IndirectTarget::CirclePadLeft,
25 IndirectTarget::CirclePadRight,
26 IndirectTarget::CirclePadModifier,
27}};
28
29static std::map<HostDeviceKey, KeyTarget> key_map;
11static int next_device_id = 0; 30static int next_device_id = 0;
12 31
32static bool circle_pad_up = false;
33static bool circle_pad_down = false;
34static bool circle_pad_left = false;
35static bool circle_pad_right = false;
36static bool circle_pad_modifier = false;
37
38static void UpdateCirclePad(EmuWindow& emu_window) {
39 constexpr float SQRT_HALF = 0.707106781;
40 int x = 0, y = 0;
41
42 if (circle_pad_right)
43 ++x;
44 if (circle_pad_left)
45 --x;
46 if (circle_pad_up)
47 ++y;
48 if (circle_pad_down)
49 --y;
50
51 float modifier = circle_pad_modifier ? Settings::values.pad_circle_modifier_scale : 1.0;
52 emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0 : SQRT_HALF), y * modifier * (x == 0 ? 1.0 : SQRT_HALF));
53}
54
13int NewDeviceId() { 55int NewDeviceId() {
14 return next_device_id++; 56 return next_device_id++;
15} 57}
16 58
17void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState) { 59void SetKeyMapping(HostDeviceKey key, KeyTarget target) {
18 key_map[key].hex = padState.hex; 60 key_map[key] = target;
61}
62
63void ClearKeyMapping(int device_id) {
64 auto iter = key_map.begin();
65 while (iter != key_map.end()) {
66 if (iter->first.device_id == device_id)
67 key_map.erase(iter++);
68 else
69 ++iter;
70 }
19} 71}
20 72
21Service::HID::PadState GetPadKey(HostDeviceKey key) { 73void PressKey(EmuWindow& emu_window, HostDeviceKey key) {
22 return key_map[key]; 74 auto target = key_map.find(key);
75 if (target == key_map.end())
76 return;
77
78 if (target->second.direct) {
79 emu_window.ButtonPressed({{target->second.target.direct_target_hex}});
80 } else {
81 switch (target->second.target.indirect_target) {
82 case IndirectTarget::CirclePadUp:
83 circle_pad_up = true;
84 UpdateCirclePad(emu_window);
85 break;
86 case IndirectTarget::CirclePadDown:
87 circle_pad_down = true;
88 UpdateCirclePad(emu_window);
89 break;
90 case IndirectTarget::CirclePadLeft:
91 circle_pad_left = true;
92 UpdateCirclePad(emu_window);
93 break;
94 case IndirectTarget::CirclePadRight:
95 circle_pad_right = true;
96 UpdateCirclePad(emu_window);
97 break;
98 case IndirectTarget::CirclePadModifier:
99 circle_pad_modifier = true;
100 UpdateCirclePad(emu_window);
101 break;
102 }
103 }
104}
105
106void ReleaseKey(EmuWindow& emu_window,HostDeviceKey key) {
107 auto target = key_map.find(key);
108 if (target == key_map.end())
109 return;
110
111 if (target->second.direct) {
112 emu_window.ButtonReleased({{target->second.target.direct_target_hex}});
113 } else {
114 switch (target->second.target.indirect_target) {
115 case IndirectTarget::CirclePadUp:
116 circle_pad_up = false;
117 UpdateCirclePad(emu_window);
118 break;
119 case IndirectTarget::CirclePadDown:
120 circle_pad_down = false;
121 UpdateCirclePad(emu_window);
122 break;
123 case IndirectTarget::CirclePadLeft:
124 circle_pad_left = false;
125 UpdateCirclePad(emu_window);
126 break;
127 case IndirectTarget::CirclePadRight:
128 circle_pad_right = false;
129 UpdateCirclePad(emu_window);
130 break;
131 case IndirectTarget::CirclePadModifier:
132 circle_pad_modifier = false;
133 UpdateCirclePad(emu_window);
134 break;
135 }
136 }
23} 137}
24 138
25} 139}
diff --git a/src/common/key_map.h b/src/common/key_map.h
index 68f7e2f99..b62f017c6 100644
--- a/src/common/key_map.h
+++ b/src/common/key_map.h
@@ -4,12 +4,51 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
7#include <tuple> 8#include <tuple>
8#include "core/hle/service/hid/hid.h" 9#include "core/hle/service/hid/hid.h"
9 10
11class EmuWindow;
12
10namespace KeyMap { 13namespace KeyMap {
11 14
12/** 15/**
16 * Represents key mapping targets that are not real 3DS buttons.
17 * They will be handled by KeyMap and translated to 3DS input.
18 */
19enum class IndirectTarget {
20 CirclePadUp,
21 CirclePadDown,
22 CirclePadLeft,
23 CirclePadRight,
24 CirclePadModifier,
25};
26
27/**
28 * Represents a key mapping target. It can be a PadState that represents real 3DS buttons,
29 * or an IndirectTarget.
30 */
31struct KeyTarget {
32 bool direct;
33 union {
34 u32 direct_target_hex;
35 IndirectTarget indirect_target;
36 } target;
37
38 KeyTarget() : direct(true) {
39 target.direct_target_hex = 0;
40 }
41
42 KeyTarget(Service::HID::PadState pad) : direct(true) {
43 target.direct_target_hex = pad.hex;
44 }
45
46 KeyTarget(IndirectTarget i) : direct(false) {
47 target.indirect_target = i;
48 }
49};
50
51/**
13 * Represents a key for a specific host device. 52 * Represents a key for a specific host device.
14 */ 53 */
15struct HostDeviceKey { 54struct HostDeviceKey {
@@ -27,19 +66,31 @@ struct HostDeviceKey {
27 } 66 }
28}; 67};
29 68
69extern const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets;
70
30/** 71/**
31 * Generates a new device id, which uniquely identifies a host device within KeyMap. 72 * Generates a new device id, which uniquely identifies a host device within KeyMap.
32 */ 73 */
33int NewDeviceId(); 74int NewDeviceId();
34 75
35/** 76/**
36 * Maps a device-specific key to a PadState. 77 * Maps a device-specific key to a target (a PadState or an IndirectTarget).
78 */
79void SetKeyMapping(HostDeviceKey key, KeyTarget target);
80
81/**
82 * Clears all key mappings belonging to one device.
83 */
84void ClearKeyMapping(int device_id);
85
86/**
87 * Maps a key press action and call the corresponding function in EmuWindow
37 */ 88 */
38void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState); 89void PressKey(EmuWindow& emu_window, HostDeviceKey key);
39 90
40/** 91/**
41 * Gets the PadState that's mapped to the provided device-specific key. 92 * Maps a key release action and call the corresponding function in EmuWindow
42 */ 93 */
43Service::HID::PadState GetPadKey(HostDeviceKey key); 94void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key);
44 95
45} 96}