summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/citra/config.cpp5
-rw-r--r--src/citra/default_ini.h8
-rw-r--r--src/citra/emu_window/emu_window_sdl2.cpp7
-rw-r--r--src/citra_qt/bootmanager.cpp7
-rw-r--r--src/citra_qt/config.cpp5
-rw-r--r--src/common/emu_window.cpp24
-rw-r--r--src/common/emu_window.h46
-rw-r--r--src/common/key_map.cpp112
-rw-r--r--src/common/key_map.h51
-rw-r--r--src/core/hle/service/hid/hid.cpp68
-rw-r--r--src/core/hle/service/hid/hid.h3
-rw-r--r--src/core/settings.h18
12 files changed, 279 insertions, 75 deletions
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index c5cb4fb38..4f6d0a464 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -44,12 +44,15 @@ bool Config::LoadINI(const std::string& default_contents, bool retry) {
44} 44}
45 45
46static const std::array<int, Settings::NativeInput::NUM_INPUTS> defaults = { 46static const std::array<int, Settings::NativeInput::NUM_INPUTS> defaults = {
47 // directly mapped keys
47 SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, 48 SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X,
48 SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_1, SDL_SCANCODE_2, 49 SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_1, SDL_SCANCODE_2,
49 SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_B, 50 SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_B,
50 SDL_SCANCODE_T, SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, 51 SDL_SCANCODE_T, SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H,
52 SDL_SCANCODE_I, SDL_SCANCODE_K, SDL_SCANCODE_J, SDL_SCANCODE_L,
53
54 // indirectly mapped keys
51 SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, 55 SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT,
52 SDL_SCANCODE_I, SDL_SCANCODE_K, SDL_SCANCODE_J, SDL_SCANCODE_L
53}; 56};
54 57
55void Config::ReadValues() { 58void Config::ReadValues() {
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index 49126356f..d0b258cab 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -23,14 +23,14 @@ pad_l =
23pad_r = 23pad_r =
24pad_zl = 24pad_zl =
25pad_zr = 25pad_zr =
26pad_sup =
27pad_sdown =
28pad_sleft =
29pad_sright =
30pad_cup = 26pad_cup =
31pad_cdown = 27pad_cdown =
32pad_cleft = 28pad_cleft =
33pad_cright = 29pad_cright =
30pad_circle_up =
31pad_circle_down =
32pad_circle_left =
33pad_circle_right =
34 34
35[Core] 35[Core]
36# The applied frameskip amount. Must be a power of two. 36# The applied frameskip amount. Must be a power of two.
diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/citra/emu_window/emu_window_sdl2.cpp
index 12cdd9d95..591f68aa4 100644
--- a/src/citra/emu_window/emu_window_sdl2.cpp
+++ b/src/citra/emu_window/emu_window_sdl2.cpp
@@ -40,9 +40,9 @@ void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
40 40
41void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { 41void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
42 if (state == SDL_PRESSED) { 42 if (state == SDL_PRESSED) {
43 KeyPressed({ key, keyboard_id }); 43 KeyMap::PressKey(*this, { key, keyboard_id });
44 } else if (state == SDL_RELEASED) { 44 } else if (state == SDL_RELEASED) {
45 KeyReleased({ key, keyboard_id }); 45 KeyMap::ReleaseKey(*this, { key, keyboard_id });
46 } 46 }
47} 47}
48 48
@@ -168,8 +168,9 @@ void EmuWindow_SDL2::DoneCurrent() {
168} 168}
169 169
170void EmuWindow_SDL2::ReloadSetKeymaps() { 170void EmuWindow_SDL2::ReloadSetKeymaps() {
171 KeyMap::ClearKeyMapping(keyboard_id);
171 for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { 172 for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
172 KeyMap::SetKeyMapping({ Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id }, Service::HID::pad_mapping[i]); 173 KeyMap::SetKeyMapping({ Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id }, KeyMap::mapping_targets[i]);
173 } 174 }
174} 175}
175 176
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 01b81c11c..414b2f8af 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -235,12 +235,12 @@ void GRenderWindow::closeEvent(QCloseEvent* event) {
235 235
236void GRenderWindow::keyPressEvent(QKeyEvent* event) 236void GRenderWindow::keyPressEvent(QKeyEvent* event)
237{ 237{
238 this->KeyPressed({event->key(), keyboard_id}); 238 KeyMap::PressKey(*this, { event->key(), keyboard_id });
239} 239}
240 240
241void GRenderWindow::keyReleaseEvent(QKeyEvent* event) 241void GRenderWindow::keyReleaseEvent(QKeyEvent* event)
242{ 242{
243 this->KeyReleased({event->key(), keyboard_id}); 243 KeyMap::ReleaseKey(*this, { event->key(), keyboard_id });
244} 244}
245 245
246void GRenderWindow::mousePressEvent(QMouseEvent *event) 246void GRenderWindow::mousePressEvent(QMouseEvent *event)
@@ -270,8 +270,9 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent *event)
270 270
271void GRenderWindow::ReloadSetKeymaps() 271void GRenderWindow::ReloadSetKeymaps()
272{ 272{
273 KeyMap::ClearKeyMapping(keyboard_id);
273 for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { 274 for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
274 KeyMap::SetKeyMapping({Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id}, Service::HID::pad_mapping[i]); 275 KeyMap::SetKeyMapping({ Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id }, KeyMap::mapping_targets[i]);
275 } 276 }
276} 277}
277 278
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index b5bb75537..ebee8c821 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -22,12 +22,15 @@ Config::Config() {
22} 22}
23 23
24static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults = { 24static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults = {
25 // directly mapped keys
25 Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, 26 Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X,
26 Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2, 27 Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2,
27 Qt::Key_M, Qt::Key_N, Qt::Key_B, 28 Qt::Key_M, Qt::Key_N, Qt::Key_B,
28 Qt::Key_T, Qt::Key_G, Qt::Key_F, Qt::Key_H, 29 Qt::Key_T, Qt::Key_G, Qt::Key_F, Qt::Key_H,
30 Qt::Key_I, Qt::Key_K, Qt::Key_J, Qt::Key_L,
31
32 // indirectly mapped keys
29 Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right, 33 Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right,
30 Qt::Key_I, Qt::Key_K, Qt::Key_J, Qt::Key_L
31}; 34};
32 35
33void Config::ReadValues() { 36void Config::ReadValues() {
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..0ae3ea2af 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 handle real buttons (A/B/X/Y/...), excluding analog input like 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 handle real buttons (A/B/X/Y/...), excluding analog input like 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 cirle 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..c8f168aa1 100644
--- a/src/common/key_map.cpp
+++ b/src/common/key_map.cpp
@@ -2,24 +2,124 @@
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::CIRCLE_PAD_UP,
23 IndirectTarget::CIRCLE_PAD_DOWN,
24 IndirectTarget::CIRCLE_PAD_LEFT,
25 IndirectTarget::CIRCLE_PAD_RIGHT,
26}};
27
28static std::map<HostDeviceKey, KeyTarget> key_map;
11static int next_device_id = 0; 29static int next_device_id = 0;
12 30
31static bool circle_pad_up = false, circle_pad_down = false, circle_pad_left = false, circle_pad_right = false;
32
33static void UpdateCirclePad(EmuWindow& emu_window) {
34 constexpr float SQRT_HALF = 0.707106781;
35 int x = 0, y = 0;
36
37 if (circle_pad_right)
38 ++x;
39 if (circle_pad_left)
40 --x;
41 if (circle_pad_up)
42 ++y;
43 if (circle_pad_down)
44 --y;
45 // TODO: apply modifier here
46 emu_window.CirclePadUpdated(x * (y == 0 ? 1.0 : SQRT_HALF), y * (x == 0 ? 1.0 : SQRT_HALF));
47}
48
13int NewDeviceId() { 49int NewDeviceId() {
14 return next_device_id++; 50 return next_device_id++;
15} 51}
16 52
17void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState) { 53void SetKeyMapping(HostDeviceKey key, KeyTarget target) {
18 key_map[key].hex = padState.hex; 54 key_map[key] = target;
19} 55}
20 56
21Service::HID::PadState GetPadKey(HostDeviceKey key) { 57void ClearKeyMapping(int device_id) {
22 return key_map[key]; 58 auto iter = key_map.begin();
59 while (iter != key_map.end()) {
60 if (iter->first.device_id == device_id)
61 key_map.erase(iter++);
62 else
63 ++iter;
64 }
65}
66
67void PressKey(EmuWindow& emu_window, HostDeviceKey key) {
68 auto target = key_map.find(key);
69 if (target == key_map.end())
70 return;
71
72 if (target->second.direct) {
73 emu_window.ButtonPressed({{target->second.target.direct_target_hex}});
74 } else {
75 switch (target->second.target.indirect_target) {
76 case IndirectTarget::CIRCLE_PAD_UP:
77 circle_pad_up = true;
78 UpdateCirclePad(emu_window);
79 break;
80 case IndirectTarget::CIRCLE_PAD_DOWN:
81 circle_pad_down = true;
82 UpdateCirclePad(emu_window);
83 break;
84 case IndirectTarget::CIRCLE_PAD_LEFT:
85 circle_pad_left = true;
86 UpdateCirclePad(emu_window);
87 break;
88 case IndirectTarget::CIRCLE_PAD_RIGHT:
89 circle_pad_right = true;
90 UpdateCirclePad(emu_window);
91 break;
92 }
93 }
94}
95
96void ReleaseKey(EmuWindow& emu_window,HostDeviceKey key) {
97 auto target = key_map.find(key);
98 if (target == key_map.end())
99 return;
100
101 if (target->second.direct) {
102 emu_window.ButtonReleased({{target->second.target.direct_target_hex}});
103 } else {
104 switch (target->second.target.indirect_target) {
105 case IndirectTarget::CIRCLE_PAD_UP:
106 circle_pad_up = false;
107 UpdateCirclePad(emu_window);
108 break;
109 case IndirectTarget::CIRCLE_PAD_DOWN:
110 circle_pad_down = false;
111 UpdateCirclePad(emu_window);
112 break;
113 case IndirectTarget::CIRCLE_PAD_LEFT:
114 circle_pad_left = false;
115 UpdateCirclePad(emu_window);
116 break;
117 case IndirectTarget::CIRCLE_PAD_RIGHT:
118 circle_pad_right = false;
119 UpdateCirclePad(emu_window);
120 break;
121 }
122 }
23} 123}
24 124
25} 125}
diff --git a/src/common/key_map.h b/src/common/key_map.h
index 68f7e2f99..0438a14e0 100644
--- a/src/common/key_map.h
+++ b/src/common/key_map.h
@@ -4,11 +4,42 @@
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
15enum class IndirectTarget {
16 CIRCLE_PAD_UP, CIRCLE_PAD_DOWN, CIRCLE_PAD_LEFT, CIRCLE_PAD_RIGHT,
17};
18
19/**
20 * Represents a key mapping target. It can be a PadState that represents 3DS real buttons,
21 * or an IndirectTarget.
22 */
23struct KeyTarget {
24 bool direct;
25 union {
26 u32 direct_target_hex;
27 IndirectTarget indirect_target;
28 } target;
29
30 KeyTarget() : direct(true) {
31 target.direct_target_hex = 0;
32 }
33
34 KeyTarget(Service::HID::PadState pad) : direct(true) {
35 target.direct_target_hex = pad.hex;
36 }
37
38 KeyTarget(IndirectTarget i) : direct(false) {
39 target.indirect_target = i;
40 }
41};
42
12/** 43/**
13 * Represents a key for a specific host device. 44 * Represents a key for a specific host device.
14 */ 45 */
@@ -27,19 +58,31 @@ struct HostDeviceKey {
27 } 58 }
28}; 59};
29 60
61extern const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets;
62
30/** 63/**
31 * Generates a new device id, which uniquely identifies a host device within KeyMap. 64 * Generates a new device id, which uniquely identifies a host device within KeyMap.
32 */ 65 */
33int NewDeviceId(); 66int NewDeviceId();
34 67
35/** 68/**
36 * Maps a device-specific key to a PadState. 69 * Maps a device-specific key to a target (a PadState or an IndirectTarget).
70 */
71void SetKeyMapping(HostDeviceKey key, KeyTarget target);
72
73/**
74 * Clears all key mappings belonging to one device.
75 */
76void ClearKeyMapping(int device_id);
77
78/**
79 * Maps a key press actions and call the corresponding function in EmuWindow
37 */ 80 */
38void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState); 81void PressKey(EmuWindow& emu_window, HostDeviceKey key);
39 82
40/** 83/**
41 * Gets the PadState that's mapped to the provided device-specific key. 84 * Maps a key release actions and call the corresponding function in EmuWindow
42 */ 85 */
43Service::HID::PadState GetPadKey(HostDeviceKey key); 86void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key);
44 87
45} 88}
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index d216cecb4..a48184495 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -19,8 +19,6 @@
19namespace Service { 19namespace Service {
20namespace HID { 20namespace HID {
21 21
22static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position
23
24// Handle to shared memory region designated to HID_User service 22// Handle to shared memory region designated to HID_User service
25static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; 23static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
26 24
@@ -39,38 +37,48 @@ static u32 next_gyroscope_index;
39static int enable_accelerometer_count = 0; // positive means enabled 37static int enable_accelerometer_count = 0; // positive means enabled
40static int enable_gyroscope_count = 0; // positive means enabled 38static int enable_gyroscope_count = 0; // positive means enabled
41 39
42const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping = {{ 40static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) {
43 Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y, 41 constexpr float TAN30 = 0.577350269, TAN60 = 1 / TAN30; // 30 degree and 60 degree are angular thresholds for directions
44 Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR, 42 constexpr int CIRCLE_PAD_THRESHOLD_SQUARE = 40 * 40; // a circle pad radius greater than 40 will trigger circle pad direction
45 Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE, 43 PadState state;
46 Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT, 44 state.hex = 0;
47 Service::HID::PAD_CIRCLE_UP, Service::HID::PAD_CIRCLE_DOWN, Service::HID::PAD_CIRCLE_LEFT, Service::HID::PAD_CIRCLE_RIGHT, 45
48 Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT 46 if (circle_pad_x * circle_pad_x + circle_pad_y * circle_pad_y > CIRCLE_PAD_THRESHOLD_SQUARE) {
49}}; 47 float t = std::abs(static_cast<float>(circle_pad_y) / circle_pad_x);
50 48
51 49 if (circle_pad_x != 0 && t < TAN60) {
52// TODO(peachum): 50 if (circle_pad_x > 0)
53// Add a method for setting analog input from joystick device for the circle Pad. 51 state.circle_right.Assign(1);
54// 52 else
55// This method should: 53 state.circle_left.Assign(1);
56// * Be called after both PadButton<Press, Release>(). 54 }
57// * Be called before PadUpdateComplete() 55
58// * Set current PadEntry.circle_pad_<axis> using analog data 56 if (circle_pad_x == 0 || t > TAN30) {
59// * Set PadData.raw_circle_pad_data 57 if (circle_pad_y > 0)
60// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41 58 state.circle_up.Assign(1);
61// * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41 59 else
62// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 60 state.circle_down.Assign(1);
63// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 61 }
62 }
63
64 return state;
65}
64 66
65void Update() { 67void Update() {
66 SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); 68 SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
67 const PadState state = VideoCore::g_emu_window->GetPadState();
68 69
69 if (mem == nullptr) { 70 if (mem == nullptr) {
70 LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!"); 71 LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!");
71 return; 72 return;
72 } 73 }
73 74
75 PadState state = VideoCore::g_emu_window->GetPadState();
76
77 // Get current circle pad positon and update circle pad direction
78 s16 circle_pad_x, circle_pad_y;
79 std::tie(circle_pad_x, circle_pad_y) = VideoCore::g_emu_window->GetCirclePadState();
80 state.hex |= GetCirclePadDirectionState(circle_pad_x, circle_pad_y).hex;
81
74 mem->pad.current_state.hex = state.hex; 82 mem->pad.current_state.hex = state.hex;
75 mem->pad.index = next_pad_index; 83 mem->pad.index = next_pad_index;
76 next_pad_index = (next_pad_index + 1) % mem->pad.entries.size(); 84 next_pad_index = (next_pad_index + 1) % mem->pad.entries.size();
@@ -88,13 +96,9 @@ void Update() {
88 // Update entry properties 96 // Update entry properties
89 pad_entry.current_state.hex = state.hex; 97 pad_entry.current_state.hex = state.hex;
90 pad_entry.delta_additions.hex = changed.hex & state.hex; 98 pad_entry.delta_additions.hex = changed.hex & state.hex;
91 pad_entry.delta_removals.hex = changed.hex & old_state.hex;; 99 pad_entry.delta_removals.hex = changed.hex & old_state.hex;
92 100 pad_entry.circle_pad_x = circle_pad_x;
93 // Set circle Pad 101 pad_entry.circle_pad_y = circle_pad_y;
94 pad_entry.circle_pad_x = state.circle_left ? -MAX_CIRCLEPAD_POS :
95 state.circle_right ? MAX_CIRCLEPAD_POS : 0x0;
96 pad_entry.circle_pad_y = state.circle_down ? -MAX_CIRCLEPAD_POS :
97 state.circle_up ? MAX_CIRCLEPAD_POS : 0x0;
98 102
99 // If we just updated index 0, provide a new timestamp 103 // If we just updated index 0, provide a new timestamp
100 if (mem->pad.index == 0) { 104 if (mem->pad.index == 0) {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 170d19ea8..669b1f723 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -215,9 +215,6 @@ const PadState PAD_CIRCLE_LEFT = {{1u << 29}};
215const PadState PAD_CIRCLE_UP = {{1u << 30}}; 215const PadState PAD_CIRCLE_UP = {{1u << 30}};
216const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; 216const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
217 217
218
219extern const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping;
220
221/** 218/**
222 * HID::GetIPCHandles service function 219 * HID::GetIPCHandles service function
223 * Inputs: 220 * Inputs:
diff --git a/src/core/settings.h b/src/core/settings.h
index ce2a31164..df5915442 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -13,29 +13,37 @@ namespace Settings {
13 13
14namespace NativeInput { 14namespace NativeInput {
15enum Values { 15enum Values {
16 // directly mapped keys
16 A, B, X, Y, 17 A, B, X, Y,
17 L, R, ZL, ZR, 18 L, R, ZL, ZR,
18 START, SELECT, HOME, 19 START, SELECT, HOME,
19 DUP, DDOWN, DLEFT, DRIGHT, 20 DUP, DDOWN, DLEFT, DRIGHT,
20 SUP, SDOWN, SLEFT, SRIGHT,
21 CUP, CDOWN, CLEFT, CRIGHT, 21 CUP, CDOWN, CLEFT, CRIGHT,
22
23 // indirectly mapped keys
24 CIRCLE_UP, CIRCLE_DOWN, CIRCLE_LEFT, CIRCLE_RIGHT,
25
22 NUM_INPUTS 26 NUM_INPUTS
23}; 27};
28
24static const std::array<const char*, NUM_INPUTS> Mapping = {{ 29static const std::array<const char*, NUM_INPUTS> Mapping = {{
30 // directly mapped keys
25 "pad_a", "pad_b", "pad_x", "pad_y", 31 "pad_a", "pad_b", "pad_x", "pad_y",
26 "pad_l", "pad_r", "pad_zl", "pad_zr", 32 "pad_l", "pad_r", "pad_zl", "pad_zr",
27 "pad_start", "pad_select", "pad_home", 33 "pad_start", "pad_select", "pad_home",
28 "pad_dup", "pad_ddown", "pad_dleft", "pad_dright", 34 "pad_dup", "pad_ddown", "pad_dleft", "pad_dright",
29 "pad_sup", "pad_sdown", "pad_sleft", "pad_sright", 35 "pad_cup", "pad_cdown", "pad_cleft", "pad_cright",
30 "pad_cup", "pad_cdown", "pad_cleft", "pad_cright" 36
37 // indirectly mapped keys
38 "pad_circle_up", "pad_circle_down", "pad_circle_left", "pad_circle_right"
31}}; 39}};
32static const std::array<Values, NUM_INPUTS> All = {{ 40static const std::array<Values, NUM_INPUTS> All = {{
33 A, B, X, Y, 41 A, B, X, Y,
34 L, R, ZL, ZR, 42 L, R, ZL, ZR,
35 START, SELECT, HOME, 43 START, SELECT, HOME,
36 DUP, DDOWN, DLEFT, DRIGHT, 44 DUP, DDOWN, DLEFT, DRIGHT,
37 SUP, SDOWN, SLEFT, SRIGHT, 45 CUP, CDOWN, CLEFT, CRIGHT,
38 CUP, CDOWN, CLEFT, CRIGHT 46 CIRCLE_UP, CIRCLE_DOWN, CIRCLE_LEFT, CIRCLE_RIGHT,
39}}; 47}};
40} 48}
41 49