diff options
| author | 2016-06-10 22:28:58 -0400 | |
|---|---|---|
| committer | 2016-06-10 22:28:58 -0400 | |
| commit | f99961581ee129c44625dbd8890fab349253271a (patch) | |
| tree | 9a2610d391d795b533054a91c22763e869bdd62b /src | |
| parent | Merge pull request #1896 from citra-emu/revert-1893-interpreter-split (diff) | |
| parent | fixup! fixup! Refactor input system (diff) | |
| download | yuzu-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')
| -rw-r--r-- | src/citra/config.cpp | 7 | ||||
| -rw-r--r-- | src/citra/default_ini.h | 13 | ||||
| -rw-r--r-- | src/citra/emu_window/emu_window_sdl2.cpp | 7 | ||||
| -rw-r--r-- | src/citra_qt/bootmanager.cpp | 7 | ||||
| -rw-r--r-- | src/citra_qt/config.cpp | 8 | ||||
| -rw-r--r-- | src/common/emu_window.cpp | 24 | ||||
| -rw-r--r-- | src/common/emu_window.h | 46 | ||||
| -rw-r--r-- | src/common/key_map.cpp | 126 | ||||
| -rw-r--r-- | src/common/key_map.h | 59 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.cpp | 68 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.h | 3 | ||||
| -rw-r--r-- | src/core/settings.h | 22 |
12 files changed, 315 insertions, 75 deletions
diff --git a/src/citra/config.cpp b/src/citra/config.cpp index c64de8e22..22cb51ea8 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp | |||
| @@ -44,12 +44,16 @@ bool Config::LoadINI(const std::string& default_contents, bool retry) { | |||
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | static const std::array<int, Settings::NativeInput::NUM_INPUTS> defaults = { | 46 | static 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 | 56 | SDL_SCANCODE_D, |
| 53 | }; | 57 | }; |
| 54 | 58 | ||
| 55 | void Config::ReadValues() { | 59 | void Config::ReadValues() { |
| @@ -58,6 +62,7 @@ void Config::ReadValues() { | |||
| 58 | Settings::values.input_mappings[Settings::NativeInput::All[i]] = | 62 | Settings::values.input_mappings[Settings::NativeInput::All[i]] = |
| 59 | sdl2_config->GetInteger("Controls", Settings::NativeInput::Mapping[i], defaults[i]); | 63 | sdl2_config->GetInteger("Controls", Settings::NativeInput::Mapping[i], defaults[i]); |
| 60 | } | 64 | } |
| 65 | Settings::values.pad_circle_modifier_scale = (float)sdl2_config->GetReal("Controls", "pad_circle_modifier_scale", 0.5); | ||
| 61 | 66 | ||
| 62 | // Core | 67 | // Core |
| 63 | Settings::values.frame_skip = sdl2_config->GetInteger("Core", "frame_skip", 0); | 68 | Settings::values.frame_skip = sdl2_config->GetInteger("Core", "frame_skip", 0); |
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 49126356f..a9017dcb3 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h | |||
| @@ -23,14 +23,19 @@ pad_l = | |||
| 23 | pad_r = | 23 | pad_r = |
| 24 | pad_zl = | 24 | pad_zl = |
| 25 | pad_zr = | 25 | pad_zr = |
| 26 | pad_sup = | ||
| 27 | pad_sdown = | ||
| 28 | pad_sleft = | ||
| 29 | pad_sright = | ||
| 30 | pad_cup = | 26 | pad_cup = |
| 31 | pad_cdown = | 27 | pad_cdown = |
| 32 | pad_cleft = | 28 | pad_cleft = |
| 33 | pad_cright = | 29 | pad_cright = |
| 30 | pad_circle_up = | ||
| 31 | pad_circle_down = | ||
| 32 | pad_circle_left = | ||
| 33 | pad_circle_right = | ||
| 34 | pad_circle_modifier = | ||
| 35 | |||
| 36 | # The applied modifier scale to circle pad. | ||
| 37 | # Must be in range of 0.0-1.0. Defaults to 0.5 | ||
| 38 | pad_circle_modifier_scale = | ||
| 34 | 39 | ||
| 35 | [Core] | 40 | [Core] |
| 36 | # The applied frameskip amount. Must be a power of two. | 41 | # 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 | ||
| 41 | void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { | 41 | void 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 | ||
| 170 | void EmuWindow_SDL2::ReloadSetKeymaps() { | 170 | void 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 | ||
| 236 | void GRenderWindow::keyPressEvent(QKeyEvent* event) | 236 | void 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 | ||
| 241 | void GRenderWindow::keyReleaseEvent(QKeyEvent* event) | 241 | void 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 | ||
| 246 | void GRenderWindow::mousePressEvent(QMouseEvent *event) | 246 | void GRenderWindow::mousePressEvent(QMouseEvent *event) |
| @@ -270,8 +270,9 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent *event) | |||
| 270 | 270 | ||
| 271 | void GRenderWindow::ReloadSetKeymaps() | 271 | void 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 6e4ba3907..ba7edaff9 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp | |||
| @@ -22,12 +22,16 @@ Config::Config() { | |||
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults = { | 24 | static 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 | 34 | Qt::Key_D, |
| 31 | }; | 35 | }; |
| 32 | 36 | ||
| 33 | void Config::ReadValues() { | 37 | void Config::ReadValues() { |
| @@ -36,6 +40,7 @@ void Config::ReadValues() { | |||
| 36 | Settings::values.input_mappings[Settings::NativeInput::All[i]] = | 40 | Settings::values.input_mappings[Settings::NativeInput::All[i]] = |
| 37 | qt_config->value(QString::fromStdString(Settings::NativeInput::Mapping[i]), defaults[i]).toInt(); | 41 | qt_config->value(QString::fromStdString(Settings::NativeInput::Mapping[i]), defaults[i]).toInt(); |
| 38 | } | 42 | } |
| 43 | Settings::values.pad_circle_modifier_scale = qt_config->value("pad_circle_modifier_scale", 0.5).toFloat(); | ||
| 39 | qt_config->endGroup(); | 44 | qt_config->endGroup(); |
| 40 | 45 | ||
| 41 | qt_config->beginGroup("Core"); | 46 | qt_config->beginGroup("Core"); |
| @@ -126,6 +131,7 @@ void Config::SaveValues() { | |||
| 126 | qt_config->setValue(QString::fromStdString(Settings::NativeInput::Mapping[i]), | 131 | qt_config->setValue(QString::fromStdString(Settings::NativeInput::Mapping[i]), |
| 127 | Settings::values.input_mappings[Settings::NativeInput::All[i]]); | 132 | Settings::values.input_mappings[Settings::NativeInput::All[i]]); |
| 128 | } | 133 | } |
| 134 | qt_config->setValue("pad_circle_modifier_scale", (double)Settings::values.pad_circle_modifier_scale); | ||
| 129 | qt_config->endGroup(); | 135 | qt_config->endGroup(); |
| 130 | 136 | ||
| 131 | qt_config->beginGroup("Core"); | 137 | qt_config->beginGroup("Core"); |
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 | ||
| 14 | void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) { | 14 | void EmuWindow::ButtonPressed(Service::HID::PadState pad) { |
| 15 | pad_state.hex |= KeyMap::GetPadKey(key).hex; | 15 | pad_state.hex |= pad.hex; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | void EmuWindow::KeyReleased(KeyMap::HostDeviceKey key) { | 18 | void EmuWindow::ButtonReleased(Service::HID::PadState pad) { |
| 19 | pad_state.hex &= ~KeyMap::GetPadKey(key).hex; | 19 | pad_state.hex &= ~pad.hex; |
| 20 | } | ||
| 21 | |||
| 22 | void 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 | ||
| 15 | namespace KeyMap { | ||
| 16 | struct 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 | |||
| 8 | namespace KeyMap { | 10 | namespace KeyMap { |
| 9 | 11 | ||
| 10 | static 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. | ||
| 15 | const 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 | |||
| 29 | static std::map<HostDeviceKey, KeyTarget> key_map; | ||
| 11 | static int next_device_id = 0; | 30 | static int next_device_id = 0; |
| 12 | 31 | ||
| 32 | static bool circle_pad_up = false; | ||
| 33 | static bool circle_pad_down = false; | ||
| 34 | static bool circle_pad_left = false; | ||
| 35 | static bool circle_pad_right = false; | ||
| 36 | static bool circle_pad_modifier = false; | ||
| 37 | |||
| 38 | static 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 | |||
| 13 | int NewDeviceId() { | 55 | int NewDeviceId() { |
| 14 | return next_device_id++; | 56 | return next_device_id++; |
| 15 | } | 57 | } |
| 16 | 58 | ||
| 17 | void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState) { | 59 | void SetKeyMapping(HostDeviceKey key, KeyTarget target) { |
| 18 | key_map[key].hex = padState.hex; | 60 | key_map[key] = target; |
| 61 | } | ||
| 62 | |||
| 63 | void 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 | ||
| 21 | Service::HID::PadState GetPadKey(HostDeviceKey key) { | 73 | void 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 | |||
| 106 | void 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 | ||
| 11 | class EmuWindow; | ||
| 12 | |||
| 10 | namespace KeyMap { | 13 | namespace 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 | */ | ||
| 19 | enum 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 | */ | ||
| 31 | struct 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 | */ |
| 15 | struct HostDeviceKey { | 54 | struct HostDeviceKey { |
| @@ -27,19 +66,31 @@ struct HostDeviceKey { | |||
| 27 | } | 66 | } |
| 28 | }; | 67 | }; |
| 29 | 68 | ||
| 69 | extern 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 | */ |
| 33 | int NewDeviceId(); | 74 | int 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 | */ | ||
| 79 | void SetKeyMapping(HostDeviceKey key, KeyTarget target); | ||
| 80 | |||
| 81 | /** | ||
| 82 | * Clears all key mappings belonging to one device. | ||
| 83 | */ | ||
| 84 | void ClearKeyMapping(int device_id); | ||
| 85 | |||
| 86 | /** | ||
| 87 | * Maps a key press action and call the corresponding function in EmuWindow | ||
| 37 | */ | 88 | */ |
| 38 | void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState); | 89 | void 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 | */ |
| 43 | Service::HID::PadState GetPadKey(HostDeviceKey key); | 94 | void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key); |
| 44 | 95 | ||
| 45 | } | 96 | } |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index d216cecb4..c975433f4 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -19,8 +19,6 @@ | |||
| 19 | namespace Service { | 19 | namespace Service { |
| 20 | namespace HID { | 20 | namespace HID { |
| 21 | 21 | ||
| 22 | static 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 |
| 25 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; | 23 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; |
| 26 | 24 | ||
| @@ -39,38 +37,48 @@ static u32 next_gyroscope_index; | |||
| 39 | static int enable_accelerometer_count = 0; // positive means enabled | 37 | static int enable_accelerometer_count = 0; // positive means enabled |
| 40 | static int enable_gyroscope_count = 0; // positive means enabled | 38 | static int enable_gyroscope_count = 0; // positive means enabled |
| 41 | 39 | ||
| 42 | const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping = {{ | 40 | static 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 | ||
| 65 | void Update() { | 67 | void 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 position 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}}; | |||
| 215 | const PadState PAD_CIRCLE_UP = {{1u << 30}}; | 215 | const PadState PAD_CIRCLE_UP = {{1u << 30}}; |
| 216 | const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; | 216 | const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; |
| 217 | 217 | ||
| 218 | |||
| 219 | extern 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 ea72f4d9c..f95e62390 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -13,29 +13,40 @@ namespace Settings { | |||
| 13 | 13 | ||
| 14 | namespace NativeInput { | 14 | namespace NativeInput { |
| 15 | enum Values { | 15 | enum 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 | CIRCLE_MODIFIER, | ||
| 26 | |||
| 22 | NUM_INPUTS | 27 | NUM_INPUTS |
| 23 | }; | 28 | }; |
| 29 | |||
| 24 | static const std::array<const char*, NUM_INPUTS> Mapping = {{ | 30 | static const std::array<const char*, NUM_INPUTS> Mapping = {{ |
| 31 | // directly mapped keys | ||
| 25 | "pad_a", "pad_b", "pad_x", "pad_y", | 32 | "pad_a", "pad_b", "pad_x", "pad_y", |
| 26 | "pad_l", "pad_r", "pad_zl", "pad_zr", | 33 | "pad_l", "pad_r", "pad_zl", "pad_zr", |
| 27 | "pad_start", "pad_select", "pad_home", | 34 | "pad_start", "pad_select", "pad_home", |
| 28 | "pad_dup", "pad_ddown", "pad_dleft", "pad_dright", | 35 | "pad_dup", "pad_ddown", "pad_dleft", "pad_dright", |
| 29 | "pad_sup", "pad_sdown", "pad_sleft", "pad_sright", | 36 | "pad_cup", "pad_cdown", "pad_cleft", "pad_cright", |
| 30 | "pad_cup", "pad_cdown", "pad_cleft", "pad_cright" | 37 | |
| 38 | // indirectly mapped keys | ||
| 39 | "pad_circle_up", "pad_circle_down", "pad_circle_left", "pad_circle_right", | ||
| 40 | "pad_circle_modifier", | ||
| 31 | }}; | 41 | }}; |
| 32 | static const std::array<Values, NUM_INPUTS> All = {{ | 42 | static const std::array<Values, NUM_INPUTS> All = {{ |
| 33 | A, B, X, Y, | 43 | A, B, X, Y, |
| 34 | L, R, ZL, ZR, | 44 | L, R, ZL, ZR, |
| 35 | START, SELECT, HOME, | 45 | START, SELECT, HOME, |
| 36 | DUP, DDOWN, DLEFT, DRIGHT, | 46 | DUP, DDOWN, DLEFT, DRIGHT, |
| 37 | SUP, SDOWN, SLEFT, SRIGHT, | 47 | CUP, CDOWN, CLEFT, CRIGHT, |
| 38 | CUP, CDOWN, CLEFT, CRIGHT | 48 | CIRCLE_UP, CIRCLE_DOWN, CIRCLE_LEFT, CIRCLE_RIGHT, |
| 49 | CIRCLE_MODIFIER, | ||
| 39 | }}; | 50 | }}; |
| 40 | } | 51 | } |
| 41 | 52 | ||
| @@ -46,6 +57,7 @@ struct Values { | |||
| 46 | 57 | ||
| 47 | // Controls | 58 | // Controls |
| 48 | std::array<int, NativeInput::NUM_INPUTS> input_mappings; | 59 | std::array<int, NativeInput::NUM_INPUTS> input_mappings; |
| 60 | float pad_circle_modifier_scale; | ||
| 49 | 61 | ||
| 50 | // Core | 62 | // Core |
| 51 | int frame_skip; | 63 | int frame_skip; |