diff options
| author | 2017-03-17 14:59:39 -0400 | |
|---|---|---|
| committer | 2017-03-17 14:59:39 -0400 | |
| commit | 423ab5e2bcf5a522e5f412447c05f648df57a14c (patch) | |
| tree | 1e60eaeffa59229254a47f885d2fe2cbbdc1a5c0 /src/core | |
| parent | Merge pull request #2618 from wwylele/log-less-filename (diff) | |
| parent | qt/config_input: don't connect for null button (diff) | |
| download | yuzu-423ab5e2bcf5a522e5f412447c05f648df57a14c.tar.gz yuzu-423ab5e2bcf5a522e5f412447c05f648df57a14c.tar.xz yuzu-423ab5e2bcf5a522e5f412447c05f648df57a14c.zip | |
Merge pull request #2497 from wwylele/input-2
Refactor input emulation & add SDL gamepad support
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/core/frontend/emu_window.cpp | 26 | ||||
| -rw-r--r-- | src/core/frontend/emu_window.h | 54 | ||||
| -rw-r--r-- | src/core/frontend/input.h | 110 | ||||
| -rw-r--r-- | src/core/frontend/key_map.cpp | 152 | ||||
| -rw-r--r-- | src/core/frontend/key_map.h | 93 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.cpp | 56 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.h | 37 | ||||
| -rw-r--r-- | src/core/settings.cpp | 3 | ||||
| -rw-r--r-- | src/core/settings.h | 80 |
10 files changed, 213 insertions, 401 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ffd67f074..61a0b1cc3 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -34,7 +34,6 @@ set(SRCS | |||
| 34 | frontend/camera/factory.cpp | 34 | frontend/camera/factory.cpp |
| 35 | frontend/camera/interface.cpp | 35 | frontend/camera/interface.cpp |
| 36 | frontend/emu_window.cpp | 36 | frontend/emu_window.cpp |
| 37 | frontend/key_map.cpp | ||
| 38 | frontend/motion_emu.cpp | 37 | frontend/motion_emu.cpp |
| 39 | gdbstub/gdbstub.cpp | 38 | gdbstub/gdbstub.cpp |
| 40 | hle/config_mem.cpp | 39 | hle/config_mem.cpp |
| @@ -218,7 +217,7 @@ set(HEADERS | |||
| 218 | frontend/camera/factory.h | 217 | frontend/camera/factory.h |
| 219 | frontend/camera/interface.h | 218 | frontend/camera/interface.h |
| 220 | frontend/emu_window.h | 219 | frontend/emu_window.h |
| 221 | frontend/key_map.h | 220 | frontend/input.h |
| 222 | frontend/motion_emu.h | 221 | frontend/motion_emu.h |
| 223 | gdbstub/gdbstub.h | 222 | gdbstub/gdbstub.h |
| 224 | hle/config_mem.h | 223 | hle/config_mem.h |
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index a155b657d..73a44bfe7 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp | |||
| @@ -7,33 +7,9 @@ | |||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/frontend/emu_window.h" | 9 | #include "core/frontend/emu_window.h" |
| 10 | #include "core/frontend/key_map.h" | 10 | #include "core/settings.h" |
| 11 | #include "video_core/video_core.h" | 11 | #include "video_core/video_core.h" |
| 12 | 12 | ||
| 13 | void EmuWindow::ButtonPressed(Service::HID::PadState pad) { | ||
| 14 | pad_state.hex |= pad.hex; | ||
| 15 | } | ||
| 16 | |||
| 17 | void EmuWindow::ButtonReleased(Service::HID::PadState pad) { | ||
| 18 | pad_state.hex &= ~pad.hex; | ||
| 19 | } | ||
| 20 | |||
| 21 | void EmuWindow::CirclePadUpdated(float x, float y) { | ||
| 22 | constexpr int MAX_CIRCLEPAD_POS = 0x9C; // Max value for a circle pad position | ||
| 23 | |||
| 24 | // Make sure the coordinates are in the unit circle, | ||
| 25 | // otherwise normalize it. | ||
| 26 | float r = x * x + y * y; | ||
| 27 | if (r > 1) { | ||
| 28 | r = std::sqrt(r); | ||
| 29 | x /= r; | ||
| 30 | y /= r; | ||
| 31 | } | ||
| 32 | |||
| 33 | circle_pad_x = static_cast<s16>(x * MAX_CIRCLEPAD_POS); | ||
| 34 | circle_pad_y = static_cast<s16>(y * MAX_CIRCLEPAD_POS); | ||
| 35 | } | ||
| 36 | |||
| 37 | /** | 13 | /** |
| 38 | * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout | 14 | * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout |
| 39 | * @param layout FramebufferLayout object describing the framebuffer size and screen positions | 15 | * @param layout FramebufferLayout object describing the framebuffer size and screen positions |
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 1ba64c92b..36f2667fa 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "common/framebuffer_layout.h" | 11 | #include "common/framebuffer_layout.h" |
| 12 | #include "common/math_util.h" | 12 | #include "common/math_util.h" |
| 13 | #include "core/hle/service/hid/hid.h" | ||
| 14 | 13 | ||
| 15 | /** | 14 | /** |
| 16 | * Abstraction class used to provide an interface between emulation code and the frontend | 15 | * Abstraction class used to provide an interface between emulation code and the frontend |
| @@ -52,30 +51,6 @@ public: | |||
| 52 | /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread | 51 | /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread |
| 53 | virtual void DoneCurrent() = 0; | 52 | virtual void DoneCurrent() = 0; |
| 54 | 53 | ||
| 55 | virtual void ReloadSetKeymaps() = 0; | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Signals a button press action to the HID module. | ||
| 59 | * @param pad_state indicates which button to press | ||
| 60 | * @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad. | ||
| 61 | */ | ||
| 62 | void ButtonPressed(Service::HID::PadState pad_state); | ||
| 63 | |||
| 64 | /** | ||
| 65 | * Signals a button release action to the HID module. | ||
| 66 | * @param pad_state indicates which button to press | ||
| 67 | * @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad. | ||
| 68 | */ | ||
| 69 | void ButtonReleased(Service::HID::PadState pad_state); | ||
| 70 | |||
| 71 | /** | ||
| 72 | * Signals a circle pad change action to the HID module. | ||
| 73 | * @param x new x-coordinate of the circle pad, in the range [-1.0, 1.0] | ||
| 74 | * @param y new y-coordinate of the circle pad, in the range [-1.0, 1.0] | ||
| 75 | * @note the coordinates will be normalized if the radius is larger than 1 | ||
| 76 | */ | ||
| 77 | void CirclePadUpdated(float x, float y); | ||
| 78 | |||
| 79 | /** | 54 | /** |
| 80 | * Signal that a touch pressed event has occurred (e.g. mouse click pressed) | 55 | * Signal that a touch pressed event has occurred (e.g. mouse click pressed) |
| 81 | * @param framebuffer_x Framebuffer x-coordinate that was pressed | 56 | * @param framebuffer_x Framebuffer x-coordinate that was pressed |
| @@ -115,27 +90,6 @@ public: | |||
| 115 | void GyroscopeChanged(float x, float y, float z); | 90 | void GyroscopeChanged(float x, float y, float z); |
| 116 | 91 | ||
| 117 | /** | 92 | /** |
| 118 | * Gets the current pad state (which buttons are pressed). | ||
| 119 | * @note This should be called by the core emu thread to get a state set by the window thread. | ||
| 120 | * @note This doesn't include analog input like circle pad direction | ||
| 121 | * @todo Fix this function to be thread-safe. | ||
| 122 | * @return PadState object indicating the current pad state | ||
| 123 | */ | ||
| 124 | Service::HID::PadState GetPadState() const { | ||
| 125 | return pad_state; | ||
| 126 | } | ||
| 127 | |||
| 128 | /** | ||
| 129 | * Gets the current circle pad state. | ||
| 130 | * @note This should be called by the core emu thread to get a state set by the window thread. | ||
| 131 | * @todo Fix this function to be thread-safe. | ||
| 132 | * @return std::tuple of (x, y), where `x` and `y` are the circle pad coordinates | ||
| 133 | */ | ||
| 134 | std::tuple<s16, s16> GetCirclePadState() const { | ||
| 135 | return std::make_tuple(circle_pad_x, circle_pad_y); | ||
| 136 | } | ||
| 137 | |||
| 138 | /** | ||
| 139 | * Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed). | 93 | * Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed). |
| 140 | * @note This should be called by the core emu thread to get a state set by the window thread. | 94 | * @note This should be called by the core emu thread to get a state set by the window thread. |
| 141 | * @todo Fix this function to be thread-safe. | 95 | * @todo Fix this function to be thread-safe. |
| @@ -230,11 +184,8 @@ protected: | |||
| 230 | // TODO: Find a better place to set this. | 184 | // TODO: Find a better place to set this. |
| 231 | config.min_client_area_size = std::make_pair(400u, 480u); | 185 | config.min_client_area_size = std::make_pair(400u, 480u); |
| 232 | active_config = config; | 186 | active_config = config; |
| 233 | pad_state.hex = 0; | ||
| 234 | touch_x = 0; | 187 | touch_x = 0; |
| 235 | touch_y = 0; | 188 | touch_y = 0; |
| 236 | circle_pad_x = 0; | ||
| 237 | circle_pad_y = 0; | ||
| 238 | touch_pressed = false; | 189 | touch_pressed = false; |
| 239 | accel_x = 0; | 190 | accel_x = 0; |
| 240 | accel_y = -512; | 191 | accel_y = -512; |
| @@ -304,9 +255,6 @@ private: | |||
| 304 | u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) | 255 | u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) |
| 305 | u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240) | 256 | u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240) |
| 306 | 257 | ||
| 307 | s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156) | ||
| 308 | s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156) | ||
| 309 | |||
| 310 | std::mutex accel_mutex; | 258 | std::mutex accel_mutex; |
| 311 | s16 accel_x; ///< Accelerometer X-axis value in native 3DS units | 259 | s16 accel_x; ///< Accelerometer X-axis value in native 3DS units |
| 312 | s16 accel_y; ///< Accelerometer Y-axis value in native 3DS units | 260 | s16 accel_y; ///< Accelerometer Y-axis value in native 3DS units |
| @@ -321,6 +269,4 @@ private: | |||
| 321 | * Clip the provided coordinates to be inside the touchscreen area. | 269 | * Clip the provided coordinates to be inside the touchscreen area. |
| 322 | */ | 270 | */ |
| 323 | std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y); | 271 | std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y); |
| 324 | |||
| 325 | Service::HID::PadState pad_state; | ||
| 326 | }; | 272 | }; |
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h new file mode 100644 index 000000000..0a5713dc0 --- /dev/null +++ b/src/core/frontend/input.h | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <string> | ||
| 9 | #include <tuple> | ||
| 10 | #include <unordered_map> | ||
| 11 | #include <utility> | ||
| 12 | #include "common/logging/log.h" | ||
| 13 | #include "common/param_package.h" | ||
| 14 | |||
| 15 | namespace Input { | ||
| 16 | |||
| 17 | /// An abstract class template for an input device (a button, an analog input, etc.). | ||
| 18 | template <typename StatusType> | ||
| 19 | class InputDevice { | ||
| 20 | public: | ||
| 21 | virtual ~InputDevice() = default; | ||
| 22 | virtual StatusType GetStatus() const { | ||
| 23 | return {}; | ||
| 24 | } | ||
| 25 | }; | ||
| 26 | |||
| 27 | /// An abstract class template for a factory that can create input devices. | ||
| 28 | template <typename InputDeviceType> | ||
| 29 | class Factory { | ||
| 30 | public: | ||
| 31 | virtual ~Factory() = default; | ||
| 32 | virtual std::unique_ptr<InputDeviceType> Create(const Common::ParamPackage&) = 0; | ||
| 33 | }; | ||
| 34 | |||
| 35 | namespace Impl { | ||
| 36 | |||
| 37 | template <typename InputDeviceType> | ||
| 38 | using FactoryListType = std::unordered_map<std::string, std::shared_ptr<Factory<InputDeviceType>>>; | ||
| 39 | |||
| 40 | template <typename InputDeviceType> | ||
| 41 | struct FactoryList { | ||
| 42 | static FactoryListType<InputDeviceType> list; | ||
| 43 | }; | ||
| 44 | |||
| 45 | template <typename InputDeviceType> | ||
| 46 | FactoryListType<InputDeviceType> FactoryList<InputDeviceType>::list; | ||
| 47 | |||
| 48 | } // namespace Impl | ||
| 49 | |||
| 50 | /** | ||
| 51 | * Registers an input device factory. | ||
| 52 | * @tparam InputDeviceType the type of input devices the factory can create | ||
| 53 | * @param name the name of the factory. Will be used to match the "engine" parameter when creating | ||
| 54 | * a device | ||
| 55 | * @param factory the factory object to register | ||
| 56 | */ | ||
| 57 | template <typename InputDeviceType> | ||
| 58 | void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) { | ||
| 59 | auto pair = std::make_pair(name, std::move(factory)); | ||
| 60 | if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) { | ||
| 61 | LOG_ERROR(Input, "Factory %s already registered", name.c_str()); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | /** | ||
| 66 | * Unregisters an input device factory. | ||
| 67 | * @tparam InputDeviceType the type of input devices the factory can create | ||
| 68 | * @param name the name of the factory to unregister | ||
| 69 | */ | ||
| 70 | template <typename InputDeviceType> | ||
| 71 | void UnregisterFactory(const std::string& name) { | ||
| 72 | if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) { | ||
| 73 | LOG_ERROR(Input, "Factory %s not registered", name.c_str()); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | /** | ||
| 78 | * Create an input device from given paramters. | ||
| 79 | * @tparam InputDeviceType the type of input devices to create | ||
| 80 | * @param params a serialized ParamPackage string contains all parameters for creating the device | ||
| 81 | */ | ||
| 82 | template <typename InputDeviceType> | ||
| 83 | std::unique_ptr<InputDeviceType> CreateDevice(const std::string& params) { | ||
| 84 | const Common::ParamPackage package(params); | ||
| 85 | const std::string engine = package.Get("engine", "null"); | ||
| 86 | const auto& factory_list = Impl::FactoryList<InputDeviceType>::list; | ||
| 87 | const auto pair = factory_list.find(engine); | ||
| 88 | if (pair == factory_list.end()) { | ||
| 89 | if (engine != "null") { | ||
| 90 | LOG_ERROR(Input, "Unknown engine name: %s", engine.c_str()); | ||
| 91 | } | ||
| 92 | return std::make_unique<InputDeviceType>(); | ||
| 93 | } | ||
| 94 | return pair->second->Create(package); | ||
| 95 | } | ||
| 96 | |||
| 97 | /** | ||
| 98 | * A button device is an input device that returns bool as status. | ||
| 99 | * true for pressed; false for released. | ||
| 100 | */ | ||
| 101 | using ButtonDevice = InputDevice<bool>; | ||
| 102 | |||
| 103 | /** | ||
| 104 | * An analog device is an input device that returns a tuple of x and y coordinates as status. The | ||
| 105 | * coordinates are within the unit circle. x+ is defined as right direction, and y+ is defined as up | ||
| 106 | * direction | ||
| 107 | */ | ||
| 108 | using AnalogDevice = InputDevice<std::tuple<float, float>>; | ||
| 109 | |||
| 110 | } // namespace Input | ||
diff --git a/src/core/frontend/key_map.cpp b/src/core/frontend/key_map.cpp deleted file mode 100644 index 15f0e079c..000000000 --- a/src/core/frontend/key_map.cpp +++ /dev/null | |||
| @@ -1,152 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <map> | ||
| 6 | #include "core/frontend/emu_window.h" | ||
| 7 | #include "core/frontend/key_map.h" | ||
| 8 | |||
| 9 | namespace KeyMap { | ||
| 10 | |||
| 11 | // TODO (wwylele): currently we treat c-stick as four direction buttons | ||
| 12 | // and map it directly to EmuWindow::ButtonPressed. | ||
| 13 | // It should go the analog input way like circle pad does. | ||
| 14 | const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{ | ||
| 15 | Service::HID::PAD_A, | ||
| 16 | Service::HID::PAD_B, | ||
| 17 | Service::HID::PAD_X, | ||
| 18 | Service::HID::PAD_Y, | ||
| 19 | Service::HID::PAD_L, | ||
| 20 | Service::HID::PAD_R, | ||
| 21 | Service::HID::PAD_ZL, | ||
| 22 | Service::HID::PAD_ZR, | ||
| 23 | Service::HID::PAD_START, | ||
| 24 | Service::HID::PAD_SELECT, | ||
| 25 | Service::HID::PAD_NONE, | ||
| 26 | Service::HID::PAD_UP, | ||
| 27 | Service::HID::PAD_DOWN, | ||
| 28 | Service::HID::PAD_LEFT, | ||
| 29 | Service::HID::PAD_RIGHT, | ||
| 30 | Service::HID::PAD_C_UP, | ||
| 31 | Service::HID::PAD_C_DOWN, | ||
| 32 | Service::HID::PAD_C_LEFT, | ||
| 33 | Service::HID::PAD_C_RIGHT, | ||
| 34 | |||
| 35 | IndirectTarget::CirclePadUp, | ||
| 36 | IndirectTarget::CirclePadDown, | ||
| 37 | IndirectTarget::CirclePadLeft, | ||
| 38 | IndirectTarget::CirclePadRight, | ||
| 39 | IndirectTarget::CirclePadModifier, | ||
| 40 | }}; | ||
| 41 | |||
| 42 | static std::map<HostDeviceKey, KeyTarget> key_map; | ||
| 43 | static int next_device_id = 0; | ||
| 44 | |||
| 45 | static bool circle_pad_up = false; | ||
| 46 | static bool circle_pad_down = false; | ||
| 47 | static bool circle_pad_left = false; | ||
| 48 | static bool circle_pad_right = false; | ||
| 49 | static bool circle_pad_modifier = false; | ||
| 50 | |||
| 51 | static void UpdateCirclePad(EmuWindow& emu_window) { | ||
| 52 | constexpr float SQRT_HALF = 0.707106781f; | ||
| 53 | int x = 0, y = 0; | ||
| 54 | |||
| 55 | if (circle_pad_right) | ||
| 56 | ++x; | ||
| 57 | if (circle_pad_left) | ||
| 58 | --x; | ||
| 59 | if (circle_pad_up) | ||
| 60 | ++y; | ||
| 61 | if (circle_pad_down) | ||
| 62 | --y; | ||
| 63 | |||
| 64 | float modifier = circle_pad_modifier ? Settings::values.pad_circle_modifier_scale : 1.0f; | ||
| 65 | emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0f : SQRT_HALF), | ||
| 66 | y * modifier * (x == 0 ? 1.0f : SQRT_HALF)); | ||
| 67 | } | ||
| 68 | |||
| 69 | int NewDeviceId() { | ||
| 70 | return next_device_id++; | ||
| 71 | } | ||
| 72 | |||
| 73 | void SetKeyMapping(HostDeviceKey key, KeyTarget target) { | ||
| 74 | key_map[key] = target; | ||
| 75 | } | ||
| 76 | |||
| 77 | void ClearKeyMapping(int device_id) { | ||
| 78 | auto iter = key_map.begin(); | ||
| 79 | while (iter != key_map.end()) { | ||
| 80 | if (iter->first.device_id == device_id) | ||
| 81 | key_map.erase(iter++); | ||
| 82 | else | ||
| 83 | ++iter; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | void PressKey(EmuWindow& emu_window, HostDeviceKey key) { | ||
| 88 | auto target = key_map.find(key); | ||
| 89 | if (target == key_map.end()) | ||
| 90 | return; | ||
| 91 | |||
| 92 | if (target->second.direct) { | ||
| 93 | emu_window.ButtonPressed({{target->second.target.direct_target_hex}}); | ||
| 94 | } else { | ||
| 95 | switch (target->second.target.indirect_target) { | ||
| 96 | case IndirectTarget::CirclePadUp: | ||
| 97 | circle_pad_up = true; | ||
| 98 | UpdateCirclePad(emu_window); | ||
| 99 | break; | ||
| 100 | case IndirectTarget::CirclePadDown: | ||
| 101 | circle_pad_down = true; | ||
| 102 | UpdateCirclePad(emu_window); | ||
| 103 | break; | ||
| 104 | case IndirectTarget::CirclePadLeft: | ||
| 105 | circle_pad_left = true; | ||
| 106 | UpdateCirclePad(emu_window); | ||
| 107 | break; | ||
| 108 | case IndirectTarget::CirclePadRight: | ||
| 109 | circle_pad_right = true; | ||
| 110 | UpdateCirclePad(emu_window); | ||
| 111 | break; | ||
| 112 | case IndirectTarget::CirclePadModifier: | ||
| 113 | circle_pad_modifier = true; | ||
| 114 | UpdateCirclePad(emu_window); | ||
| 115 | break; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key) { | ||
| 121 | auto target = key_map.find(key); | ||
| 122 | if (target == key_map.end()) | ||
| 123 | return; | ||
| 124 | |||
| 125 | if (target->second.direct) { | ||
| 126 | emu_window.ButtonReleased({{target->second.target.direct_target_hex}}); | ||
| 127 | } else { | ||
| 128 | switch (target->second.target.indirect_target) { | ||
| 129 | case IndirectTarget::CirclePadUp: | ||
| 130 | circle_pad_up = false; | ||
| 131 | UpdateCirclePad(emu_window); | ||
| 132 | break; | ||
| 133 | case IndirectTarget::CirclePadDown: | ||
| 134 | circle_pad_down = false; | ||
| 135 | UpdateCirclePad(emu_window); | ||
| 136 | break; | ||
| 137 | case IndirectTarget::CirclePadLeft: | ||
| 138 | circle_pad_left = false; | ||
| 139 | UpdateCirclePad(emu_window); | ||
| 140 | break; | ||
| 141 | case IndirectTarget::CirclePadRight: | ||
| 142 | circle_pad_right = false; | ||
| 143 | UpdateCirclePad(emu_window); | ||
| 144 | break; | ||
| 145 | case IndirectTarget::CirclePadModifier: | ||
| 146 | circle_pad_modifier = false; | ||
| 147 | UpdateCirclePad(emu_window); | ||
| 148 | break; | ||
| 149 | } | ||
| 150 | } | ||
| 151 | } | ||
| 152 | } | ||
diff --git a/src/core/frontend/key_map.h b/src/core/frontend/key_map.h deleted file mode 100644 index 040794578..000000000 --- a/src/core/frontend/key_map.h +++ /dev/null | |||
| @@ -1,93 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <tuple> | ||
| 9 | #include "core/hle/service/hid/hid.h" | ||
| 10 | |||
| 11 | class EmuWindow; | ||
| 12 | |||
| 13 | namespace KeyMap { | ||
| 14 | |||
| 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 | /** | ||
| 52 | * Represents a key for a specific host device. | ||
| 53 | */ | ||
| 54 | struct HostDeviceKey { | ||
| 55 | int key_code; | ||
| 56 | int device_id; ///< Uniquely identifies a host device | ||
| 57 | |||
| 58 | bool operator<(const HostDeviceKey& other) const { | ||
| 59 | return std::tie(key_code, device_id) < std::tie(other.key_code, other.device_id); | ||
| 60 | } | ||
| 61 | |||
| 62 | bool operator==(const HostDeviceKey& other) const { | ||
| 63 | return std::tie(key_code, device_id) == std::tie(other.key_code, other.device_id); | ||
| 64 | } | ||
| 65 | }; | ||
| 66 | |||
| 67 | extern const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets; | ||
| 68 | |||
| 69 | /** | ||
| 70 | * Generates a new device id, which uniquely identifies a host device within KeyMap. | ||
| 71 | */ | ||
| 72 | int NewDeviceId(); | ||
| 73 | |||
| 74 | /** | ||
| 75 | * Maps a device-specific key to a target (a PadState or an IndirectTarget). | ||
| 76 | */ | ||
| 77 | void SetKeyMapping(HostDeviceKey key, KeyTarget target); | ||
| 78 | |||
| 79 | /** | ||
| 80 | * Clears all key mappings belonging to one device. | ||
| 81 | */ | ||
| 82 | void ClearKeyMapping(int device_id); | ||
| 83 | |||
| 84 | /** | ||
| 85 | * Maps a key press action and call the corresponding function in EmuWindow | ||
| 86 | */ | ||
| 87 | void PressKey(EmuWindow& emu_window, HostDeviceKey key); | ||
| 88 | |||
| 89 | /** | ||
| 90 | * Maps a key release action and call the corresponding function in EmuWindow | ||
| 91 | */ | ||
| 92 | void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key); | ||
| 93 | } | ||
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index fb3acb507..b19e831fe 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -2,10 +2,14 @@ | |||
| 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 <algorithm> | ||
| 6 | #include <atomic> | ||
| 5 | #include <cmath> | 7 | #include <cmath> |
| 8 | #include <memory> | ||
| 6 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 7 | #include "core/core_timing.h" | 10 | #include "core/core_timing.h" |
| 8 | #include "core/frontend/emu_window.h" | 11 | #include "core/frontend/emu_window.h" |
| 12 | #include "core/frontend/input.h" | ||
| 9 | #include "core/hle/kernel/event.h" | 13 | #include "core/hle/kernel/event.h" |
| 10 | #include "core/hle/kernel/shared_memory.h" | 14 | #include "core/hle/kernel/shared_memory.h" |
| 11 | #include "core/hle/service/hid/hid.h" | 15 | #include "core/hle/service/hid/hid.h" |
| @@ -44,6 +48,11 @@ constexpr u64 pad_update_ticks = BASE_CLOCK_RATE_ARM11 / 234; | |||
| 44 | constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE_ARM11 / 104; | 48 | constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE_ARM11 / 104; |
| 45 | constexpr u64 gyroscope_update_ticks = BASE_CLOCK_RATE_ARM11 / 101; | 49 | constexpr u64 gyroscope_update_ticks = BASE_CLOCK_RATE_ARM11 / 101; |
| 46 | 50 | ||
| 51 | static std::atomic<bool> is_device_reload_pending; | ||
| 52 | static std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> | ||
| 53 | buttons; | ||
| 54 | static std::unique_ptr<Input::AnalogDevice> circle_pad; | ||
| 55 | |||
| 47 | static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { | 56 | static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { |
| 48 | // 30 degree and 60 degree are angular thresholds for directions | 57 | // 30 degree and 60 degree are angular thresholds for directions |
| 49 | constexpr float TAN30 = 0.577350269f; | 58 | constexpr float TAN30 = 0.577350269f; |
| @@ -74,14 +83,48 @@ static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { | |||
| 74 | return state; | 83 | return state; |
| 75 | } | 84 | } |
| 76 | 85 | ||
| 86 | static void LoadInputDevices() { | ||
| 87 | std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, | ||
| 88 | Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END, | ||
| 89 | buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); | ||
| 90 | circle_pad = Input::CreateDevice<Input::AnalogDevice>( | ||
| 91 | Settings::values.analogs[Settings::NativeAnalog::CirclePad]); | ||
| 92 | } | ||
| 93 | |||
| 94 | static void UnloadInputDevices() { | ||
| 95 | for (auto& button : buttons) { | ||
| 96 | button.reset(); | ||
| 97 | } | ||
| 98 | circle_pad.reset(); | ||
| 99 | } | ||
| 100 | |||
| 77 | static void UpdatePadCallback(u64 userdata, int cycles_late) { | 101 | static void UpdatePadCallback(u64 userdata, int cycles_late) { |
| 78 | SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); | 102 | SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); |
| 79 | 103 | ||
| 80 | PadState state = VideoCore::g_emu_window->GetPadState(); | 104 | if (is_device_reload_pending.exchange(false)) |
| 105 | LoadInputDevices(); | ||
| 106 | |||
| 107 | PadState state; | ||
| 108 | using namespace Settings::NativeButton; | ||
| 109 | state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 110 | state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 111 | state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 112 | state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 113 | state.right.Assign(buttons[Right - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 114 | state.left.Assign(buttons[Left - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 115 | state.up.Assign(buttons[Up - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 116 | state.down.Assign(buttons[Down - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 117 | state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 118 | state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 119 | state.start.Assign(buttons[Start - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 120 | state.select.Assign(buttons[Select - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 81 | 121 | ||
| 82 | // Get current circle pad position and update circle pad direction | 122 | // Get current circle pad position and update circle pad direction |
| 83 | s16 circle_pad_x, circle_pad_y; | 123 | float circle_pad_x_f, circle_pad_y_f; |
| 84 | std::tie(circle_pad_x, circle_pad_y) = VideoCore::g_emu_window->GetCirclePadState(); | 124 | std::tie(circle_pad_x_f, circle_pad_y_f) = circle_pad->GetStatus(); |
| 125 | constexpr int MAX_CIRCLEPAD_POS = 0x9C; // Max value for a circle pad position | ||
| 126 | s16 circle_pad_x = static_cast<s16>(circle_pad_x_f * MAX_CIRCLEPAD_POS); | ||
| 127 | s16 circle_pad_y = static_cast<s16>(circle_pad_y_f * MAX_CIRCLEPAD_POS); | ||
| 85 | state.hex |= GetCirclePadDirectionState(circle_pad_x, circle_pad_y).hex; | 128 | state.hex |= GetCirclePadDirectionState(circle_pad_x, circle_pad_y).hex; |
| 86 | 129 | ||
| 87 | mem->pad.current_state.hex = state.hex; | 130 | mem->pad.current_state.hex = state.hex; |
| @@ -313,6 +356,8 @@ void Init() { | |||
| 313 | AddService(new HID_U_Interface); | 356 | AddService(new HID_U_Interface); |
| 314 | AddService(new HID_SPVR_Interface); | 357 | AddService(new HID_SPVR_Interface); |
| 315 | 358 | ||
| 359 | is_device_reload_pending.store(true); | ||
| 360 | |||
| 316 | using Kernel::MemoryPermission; | 361 | using Kernel::MemoryPermission; |
| 317 | shared_mem = | 362 | shared_mem = |
| 318 | SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read, | 363 | SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read, |
| @@ -350,6 +395,11 @@ void Shutdown() { | |||
| 350 | event_accelerometer = nullptr; | 395 | event_accelerometer = nullptr; |
| 351 | event_gyroscope = nullptr; | 396 | event_gyroscope = nullptr; |
| 352 | event_debug_pad = nullptr; | 397 | event_debug_pad = nullptr; |
| 398 | UnloadInputDevices(); | ||
| 399 | } | ||
| 400 | |||
| 401 | void ReloadInputDevices() { | ||
| 402 | is_device_reload_pending.store(true); | ||
| 353 | } | 403 | } |
| 354 | 404 | ||
| 355 | } // namespace HID | 405 | } // namespace HID |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index c7f4ee138..b505cdcd5 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -39,13 +39,6 @@ struct PadState { | |||
| 39 | BitField<10, 1, u32> x; | 39 | BitField<10, 1, u32> x; |
| 40 | BitField<11, 1, u32> y; | 40 | BitField<11, 1, u32> y; |
| 41 | 41 | ||
| 42 | BitField<14, 1, u32> zl; | ||
| 43 | BitField<15, 1, u32> zr; | ||
| 44 | |||
| 45 | BitField<24, 1, u32> c_right; | ||
| 46 | BitField<25, 1, u32> c_left; | ||
| 47 | BitField<26, 1, u32> c_up; | ||
| 48 | BitField<27, 1, u32> c_down; | ||
| 49 | BitField<28, 1, u32> circle_right; | 42 | BitField<28, 1, u32> circle_right; |
| 50 | BitField<29, 1, u32> circle_left; | 43 | BitField<29, 1, u32> circle_left; |
| 51 | BitField<30, 1, u32> circle_up; | 44 | BitField<30, 1, u32> circle_up; |
| @@ -183,33 +176,6 @@ ASSERT_REG_POSITION(touch.index_reset_ticks, 0x2A); | |||
| 183 | #undef ASSERT_REG_POSITION | 176 | #undef ASSERT_REG_POSITION |
| 184 | #endif // !defined(_MSC_VER) | 177 | #endif // !defined(_MSC_VER) |
| 185 | 178 | ||
| 186 | // Pre-defined PadStates for single button presses | ||
| 187 | const PadState PAD_NONE = {{0}}; | ||
| 188 | const PadState PAD_A = {{1u << 0}}; | ||
| 189 | const PadState PAD_B = {{1u << 1}}; | ||
| 190 | const PadState PAD_SELECT = {{1u << 2}}; | ||
| 191 | const PadState PAD_START = {{1u << 3}}; | ||
| 192 | const PadState PAD_RIGHT = {{1u << 4}}; | ||
| 193 | const PadState PAD_LEFT = {{1u << 5}}; | ||
| 194 | const PadState PAD_UP = {{1u << 6}}; | ||
| 195 | const PadState PAD_DOWN = {{1u << 7}}; | ||
| 196 | const PadState PAD_R = {{1u << 8}}; | ||
| 197 | const PadState PAD_L = {{1u << 9}}; | ||
| 198 | const PadState PAD_X = {{1u << 10}}; | ||
| 199 | const PadState PAD_Y = {{1u << 11}}; | ||
| 200 | |||
| 201 | const PadState PAD_ZL = {{1u << 14}}; | ||
| 202 | const PadState PAD_ZR = {{1u << 15}}; | ||
| 203 | |||
| 204 | const PadState PAD_C_RIGHT = {{1u << 24}}; | ||
| 205 | const PadState PAD_C_LEFT = {{1u << 25}}; | ||
| 206 | const PadState PAD_C_UP = {{1u << 26}}; | ||
| 207 | const PadState PAD_C_DOWN = {{1u << 27}}; | ||
| 208 | const PadState PAD_CIRCLE_RIGHT = {{1u << 28}}; | ||
| 209 | const PadState PAD_CIRCLE_LEFT = {{1u << 29}}; | ||
| 210 | const PadState PAD_CIRCLE_UP = {{1u << 30}}; | ||
| 211 | const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; | ||
| 212 | |||
| 213 | /** | 179 | /** |
| 214 | * HID::GetIPCHandles service function | 180 | * HID::GetIPCHandles service function |
| 215 | * Inputs: | 181 | * Inputs: |
| @@ -297,5 +263,8 @@ void Init(); | |||
| 297 | 263 | ||
| 298 | /// Shutdown HID service | 264 | /// Shutdown HID service |
| 299 | void Shutdown(); | 265 | void Shutdown(); |
| 266 | |||
| 267 | /// Reload input devices. Used when input configuration changed | ||
| 268 | void ReloadInputDevices(); | ||
| 300 | } | 269 | } |
| 301 | } | 270 | } |
diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 3a32b70aa..a598f9f2f 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "audio_core/audio_core.h" | 5 | #include "audio_core/audio_core.h" |
| 6 | #include "core/gdbstub/gdbstub.h" | 6 | #include "core/gdbstub/gdbstub.h" |
| 7 | #include "core/hle/service/hid/hid.h" | ||
| 7 | #include "settings.h" | 8 | #include "settings.h" |
| 8 | #include "video_core/video_core.h" | 9 | #include "video_core/video_core.h" |
| 9 | 10 | ||
| @@ -29,6 +30,8 @@ void Apply() { | |||
| 29 | 30 | ||
| 30 | AudioCore::SelectSink(values.sink_id); | 31 | AudioCore::SelectSink(values.sink_id); |
| 31 | AudioCore::EnableStretching(values.enable_audio_stretching); | 32 | AudioCore::EnableStretching(values.enable_audio_stretching); |
| 33 | |||
| 34 | Service::HID::ReloadInputDevices(); | ||
| 32 | } | 35 | } |
| 33 | 36 | ||
| 34 | } // namespace | 37 | } // namespace |
diff --git a/src/core/settings.h b/src/core/settings.h index b6c75531f..d1a9f0da8 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -18,64 +18,68 @@ enum class LayoutOption { | |||
| 18 | Custom, | 18 | Custom, |
| 19 | }; | 19 | }; |
| 20 | 20 | ||
| 21 | namespace NativeInput { | 21 | namespace NativeButton { |
| 22 | |||
| 23 | enum Values { | 22 | enum Values { |
| 24 | // directly mapped keys | ||
| 25 | A, | 23 | A, |
| 26 | B, | 24 | B, |
| 27 | X, | 25 | X, |
| 28 | Y, | 26 | Y, |
| 27 | Up, | ||
| 28 | Down, | ||
| 29 | Left, | ||
| 30 | Right, | ||
| 29 | L, | 31 | L, |
| 30 | R, | 32 | R, |
| 33 | Start, | ||
| 34 | Select, | ||
| 35 | |||
| 31 | ZL, | 36 | ZL, |
| 32 | ZR, | 37 | ZR, |
| 33 | START, | 38 | |
| 34 | SELECT, | 39 | Home, |
| 35 | HOME, | 40 | |
| 36 | DUP, | 41 | NumButtons, |
| 37 | DDOWN, | ||
| 38 | DLEFT, | ||
| 39 | DRIGHT, | ||
| 40 | CUP, | ||
| 41 | CDOWN, | ||
| 42 | CLEFT, | ||
| 43 | CRIGHT, | ||
| 44 | |||
| 45 | // indirectly mapped keys | ||
| 46 | CIRCLE_UP, | ||
| 47 | CIRCLE_DOWN, | ||
| 48 | CIRCLE_LEFT, | ||
| 49 | CIRCLE_RIGHT, | ||
| 50 | CIRCLE_MODIFIER, | ||
| 51 | |||
| 52 | NUM_INPUTS | ||
| 53 | }; | 42 | }; |
| 54 | 43 | ||
| 55 | static const std::array<const char*, NUM_INPUTS> Mapping = {{ | 44 | constexpr int BUTTON_HID_BEGIN = A; |
| 56 | // directly mapped keys | 45 | constexpr int BUTTON_IR_BEGIN = ZL; |
| 57 | "pad_a", "pad_b", "pad_x", "pad_y", "pad_l", "pad_r", "pad_zl", "pad_zr", "pad_start", | 46 | constexpr int BUTTON_NS_BEGIN = Home; |
| 58 | "pad_select", "pad_home", "pad_dup", "pad_ddown", "pad_dleft", "pad_dright", "pad_cup", | 47 | |
| 59 | "pad_cdown", "pad_cleft", "pad_cright", | 48 | constexpr int BUTTON_HID_END = BUTTON_IR_BEGIN; |
| 49 | constexpr int BUTTON_IR_END = BUTTON_NS_BEGIN; | ||
| 50 | constexpr int BUTTON_NS_END = NumButtons; | ||
| 51 | |||
| 52 | constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN; | ||
| 53 | constexpr int NUM_BUTTONS_IR = BUTTON_IR_END - BUTTON_IR_BEGIN; | ||
| 54 | constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN; | ||
| 60 | 55 | ||
| 61 | // indirectly mapped keys | 56 | static const std::array<const char*, NumButtons> mapping = {{ |
| 62 | "pad_circle_up", "pad_circle_down", "pad_circle_left", "pad_circle_right", | 57 | "button_a", "button_b", "button_x", "button_y", "button_up", "button_down", "button_left", |
| 63 | "pad_circle_modifier", | 58 | "button_right", "button_l", "button_r", "button_start", "button_select", "button_zl", |
| 59 | "button_zr", "button_home", | ||
| 64 | }}; | 60 | }}; |
| 65 | static const std::array<Values, NUM_INPUTS> All = {{ | 61 | } // namespace NativeButton |
| 66 | A, B, X, Y, L, R, ZL, ZR, | 62 | |
| 67 | START, SELECT, HOME, DUP, DDOWN, DLEFT, DRIGHT, CUP, | 63 | namespace NativeAnalog { |
| 68 | CDOWN, CLEFT, CRIGHT, CIRCLE_UP, CIRCLE_DOWN, CIRCLE_LEFT, CIRCLE_RIGHT, CIRCLE_MODIFIER, | 64 | enum Values { |
| 65 | CirclePad, | ||
| 66 | CStick, | ||
| 67 | |||
| 68 | NumAnalogs, | ||
| 69 | }; | ||
| 70 | |||
| 71 | static const std::array<const char*, NumAnalogs> mapping = {{ | ||
| 72 | "circle_pad", "c_stick", | ||
| 69 | }}; | 73 | }}; |
| 70 | } | 74 | } // namespace NumAnalog |
| 71 | 75 | ||
| 72 | struct Values { | 76 | struct Values { |
| 73 | // CheckNew3DS | 77 | // CheckNew3DS |
| 74 | bool is_new_3ds; | 78 | bool is_new_3ds; |
| 75 | 79 | ||
| 76 | // Controls | 80 | // Controls |
| 77 | std::array<int, NativeInput::NUM_INPUTS> input_mappings; | 81 | std::array<std::string, NativeButton::NumButtons> buttons; |
| 78 | float pad_circle_modifier_scale; | 82 | std::array<std::string, NativeAnalog::NumAnalogs> analogs; |
| 79 | 83 | ||
| 80 | // Core | 84 | // Core |
| 81 | bool use_cpu_jit; | 85 | bool use_cpu_jit; |