diff options
| author | 2016-05-12 13:09:36 +0300 | |
|---|---|---|
| committer | 2016-05-15 13:24:22 +0300 | |
| commit | 03631f9b8fe75cf1c3a70a3094aeddcebffa4cf9 (patch) | |
| tree | 95edc62b3b8520a533e534bf4991159875fef3e5 /src/common | |
| parent | AudioCore: Implement time stretcher (#1737) (diff) | |
| download | yuzu-03631f9b8fe75cf1c3a70a3094aeddcebffa4cf9.tar.gz yuzu-03631f9b8fe75cf1c3a70a3094aeddcebffa4cf9.tar.xz yuzu-03631f9b8fe75cf1c3a70a3094aeddcebffa4cf9.zip | |
Refactor input subsystem
Diffstat (limited to 'src/common')
| -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 | 112 | ||||
| -rw-r--r-- | src/common/key_map.h | 51 |
4 files changed, 210 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 | ||
| 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..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 | ||
| 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 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 | |||
| 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::CIRCLE_PAD_UP, | ||
| 23 | IndirectTarget::CIRCLE_PAD_DOWN, | ||
| 24 | IndirectTarget::CIRCLE_PAD_LEFT, | ||
| 25 | IndirectTarget::CIRCLE_PAD_RIGHT, | ||
| 26 | }}; | ||
| 27 | |||
| 28 | static std::map<HostDeviceKey, KeyTarget> key_map; | ||
| 11 | static int next_device_id = 0; | 29 | static int next_device_id = 0; |
| 12 | 30 | ||
| 31 | static bool circle_pad_up = false, circle_pad_down = false, circle_pad_left = false, circle_pad_right = false; | ||
| 32 | |||
| 33 | static 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 | |||
| 13 | int NewDeviceId() { | 49 | int NewDeviceId() { |
| 14 | return next_device_id++; | 50 | return next_device_id++; |
| 15 | } | 51 | } |
| 16 | 52 | ||
| 17 | void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState) { | 53 | void SetKeyMapping(HostDeviceKey key, KeyTarget target) { |
| 18 | key_map[key].hex = padState.hex; | 54 | key_map[key] = target; |
| 19 | } | 55 | } |
| 20 | 56 | ||
| 21 | Service::HID::PadState GetPadKey(HostDeviceKey key) { | 57 | void 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 | |||
| 67 | void 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 | |||
| 96 | void 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 | ||
| 11 | class EmuWindow; | ||
| 12 | |||
| 10 | namespace KeyMap { | 13 | namespace KeyMap { |
| 11 | 14 | ||
| 15 | enum 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 | */ | ||
| 23 | struct 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 | ||
| 61 | extern 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 | */ |
| 33 | int NewDeviceId(); | 66 | int 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 | */ | ||
| 71 | void SetKeyMapping(HostDeviceKey key, KeyTarget target); | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Clears all key mappings belonging to one device. | ||
| 75 | */ | ||
| 76 | void ClearKeyMapping(int device_id); | ||
| 77 | |||
| 78 | /** | ||
| 79 | * Maps a key press actions and call the corresponding function in EmuWindow | ||
| 37 | */ | 80 | */ |
| 38 | void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState); | 81 | void 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 | */ |
| 43 | Service::HID::PadState GetPadKey(HostDeviceKey key); | 86 | void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key); |
| 44 | 87 | ||
| 45 | } | 88 | } |