summaryrefslogtreecommitdiff
path: root/src/input_common
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common')
-rw-r--r--src/input_common/CMakeLists.txt2
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp18
-rw-r--r--src/input_common/main.cpp201
-rw-r--r--src/input_common/main.h129
-rw-r--r--src/input_common/sdl/sdl.h19
-rw-r--r--src/input_common/sdl/sdl_impl.cpp438
-rw-r--r--src/input_common/sdl/sdl_impl.h8
-rw-r--r--src/input_common/settings.cpp33
-rw-r--r--src/input_common/settings.h335
-rw-r--r--src/input_common/udp/client.cpp6
-rw-r--r--src/input_common/udp/udp.cpp14
-rw-r--r--src/input_common/udp/udp.h7
12 files changed, 991 insertions, 219 deletions
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index 317c25bad..56267c8a8 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -7,6 +7,8 @@ add_library(input_common STATIC
7 main.h 7 main.h
8 motion_emu.cpp 8 motion_emu.cpp
9 motion_emu.h 9 motion_emu.h
10 settings.cpp
11 settings.h
10 gcadapter/gc_adapter.cpp 12 gcadapter/gc_adapter.cpp
11 gcadapter/gc_adapter.h 13 gcadapter/gc_adapter.h
12 gcadapter/gc_poller.cpp 14 gcadapter/gc_poller.cpp
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp
index f45983f3f..71cd85eeb 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -148,19 +148,17 @@ void GCButtonFactory::EndConfiguration() {
148 148
149class GCAnalog final : public Input::AnalogDevice { 149class GCAnalog final : public Input::AnalogDevice {
150public: 150public:
151 GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter) 151 GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter,
152 float range_)
152 : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), 153 : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter),
153 origin_value_x(adapter->GetOriginValue(port_, axis_x_)), 154 origin_value_x(adapter->GetOriginValue(port_, axis_x_)),
154 origin_value_y(adapter->GetOriginValue(port_, axis_y_)) {} 155 origin_value_y(adapter->GetOriginValue(port_, axis_y_)), range(range_) {}
155 156
156 float GetAxis(int axis) const { 157 float GetAxis(int axis) const {
157 if (gcadapter->DeviceConnected(port)) { 158 if (gcadapter->DeviceConnected(port)) {
158 std::lock_guard lock{mutex}; 159 std::lock_guard lock{mutex};
159 const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y; 160 const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y;
160 // division is not by a perfect 128 to account for some variance in center location 161 return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / (100.0f * range);
161 // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range
162 // [20-230]
163 return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f;
164 } 162 }
165 return 0.0f; 163 return 0.0f;
166 } 164 }
@@ -193,7 +191,7 @@ public:
193 191
194 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { 192 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
195 const auto [x, y] = GetStatus(); 193 const auto [x, y] = GetStatus();
196 const float directional_deadzone = 0.4f; 194 const float directional_deadzone = 0.5f;
197 switch (direction) { 195 switch (direction) {
198 case Input::AnalogDirection::RIGHT: 196 case Input::AnalogDirection::RIGHT:
199 return x > directional_deadzone; 197 return x > directional_deadzone;
@@ -215,6 +213,7 @@ private:
215 GCAdapter::Adapter* gcadapter; 213 GCAdapter::Adapter* gcadapter;
216 const float origin_value_x; 214 const float origin_value_x;
217 const float origin_value_y; 215 const float origin_value_y;
216 const float range;
218 mutable std::mutex mutex; 217 mutable std::mutex mutex;
219}; 218};
220 219
@@ -233,9 +232,10 @@ std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::Param
233 const int port = params.Get("port", 0); 232 const int port = params.Get("port", 0);
234 const int axis_x = params.Get("axis_x", 0); 233 const int axis_x = params.Get("axis_x", 0);
235 const int axis_y = params.Get("axis_y", 1); 234 const int axis_y = params.Get("axis_y", 1);
236 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); 235 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
236 const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
237 237
238 return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get()); 238 return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get(), range);
239} 239}
240 240
241void GCAnalogFactory::BeginConfiguration() { 241void GCAnalogFactory::BeginConfiguration() {
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index b9d5d0ec3..57e7a25fe 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -18,67 +18,166 @@
18 18
19namespace InputCommon { 19namespace InputCommon {
20 20
21static std::shared_ptr<Keyboard> keyboard; 21struct InputSubsystem::Impl {
22static std::shared_ptr<MotionEmu> motion_emu; 22 void Initialize() {
23 auto gcadapter = std::make_shared<GCAdapter::Adapter>();
24 gcbuttons = std::make_shared<GCButtonFactory>(gcadapter);
25 Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons);
26 gcanalog = std::make_shared<GCAnalogFactory>(gcadapter);
27 Input::RegisterFactory<Input::AnalogDevice>("gcpad", gcanalog);
28
29 keyboard = std::make_shared<Keyboard>();
30 Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard);
31 Input::RegisterFactory<Input::AnalogDevice>("analog_from_button",
32 std::make_shared<AnalogFromButton>());
33 motion_emu = std::make_shared<MotionEmu>();
34 Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu);
35
23#ifdef HAVE_SDL2 36#ifdef HAVE_SDL2
24static std::unique_ptr<SDL::State> sdl; 37 sdl = SDL::Init();
25#endif 38#endif
26static std::unique_ptr<CemuhookUDP::State> udp;
27static std::shared_ptr<GCButtonFactory> gcbuttons;
28static std::shared_ptr<GCAnalogFactory> gcanalog;
29
30void Init() {
31 auto gcadapter = std::make_shared<GCAdapter::Adapter>();
32 gcbuttons = std::make_shared<GCButtonFactory>(gcadapter);
33 Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons);
34 gcanalog = std::make_shared<GCAnalogFactory>(gcadapter);
35 Input::RegisterFactory<Input::AnalogDevice>("gcpad", gcanalog);
36
37 keyboard = std::make_shared<Keyboard>();
38 Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard);
39 Input::RegisterFactory<Input::AnalogDevice>("analog_from_button",
40 std::make_shared<AnalogFromButton>());
41 motion_emu = std::make_shared<MotionEmu>();
42 Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu);
43 39
40 udp = CemuhookUDP::Init();
41 }
42
43 void Shutdown() {
44 Input::UnregisterFactory<Input::ButtonDevice>("keyboard");
45 keyboard.reset();
46 Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
47 Input::UnregisterFactory<Input::MotionDevice>("motion_emu");
48 motion_emu.reset();
44#ifdef HAVE_SDL2 49#ifdef HAVE_SDL2
45 sdl = SDL::Init(); 50 sdl.reset();
46#endif 51#endif
52 udp.reset();
53 Input::UnregisterFactory<Input::ButtonDevice>("gcpad");
54 Input::UnregisterFactory<Input::AnalogDevice>("gcpad");
55
56 gcbuttons.reset();
57 gcanalog.reset();
58 }
59
60 [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const {
61 std::vector<Common::ParamPackage> devices = {
62 Common::ParamPackage{{"display", "Any"}, {"class", "any"}},
63 Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "key"}},
64 };
65#ifdef HAVE_SDL2
66 auto sdl_devices = sdl->GetInputDevices();
67 devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end());
68#endif
69 auto udp_devices = udp->GetInputDevices();
70 devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
71 return devices;
72 }
73
74 [[nodiscard]] AnalogMapping GetAnalogMappingForDevice(
75 const Common::ParamPackage& params) const {
76 if (!params.Has("class") || params.Get("class", "") == "any") {
77 return {};
78 }
79 if (params.Get("class", "") == "key") {
80 // TODO consider returning the SDL key codes for the default keybindings
81 return {};
82 }
83#ifdef HAVE_SDL2
84 if (params.Get("class", "") == "sdl") {
85 return sdl->GetAnalogMappingForDevice(params);
86 }
87#endif
88 return {};
89 }
90
91 [[nodiscard]] ButtonMapping GetButtonMappingForDevice(
92 const Common::ParamPackage& params) const {
93 if (!params.Has("class") || params.Get("class", "") == "any") {
94 return {};
95 }
96 if (params.Get("class", "") == "key") {
97 // TODO consider returning the SDL key codes for the default keybindings
98 return {};
99 }
100#ifdef HAVE_SDL2
101 if (params.Get("class", "") == "sdl") {
102 return sdl->GetButtonMappingForDevice(params);
103 }
104#endif
105 return {};
106 }
47 107
48 udp = CemuhookUDP::Init(); 108 std::shared_ptr<Keyboard> keyboard;
49} 109 std::shared_ptr<MotionEmu> motion_emu;
50
51void Shutdown() {
52 Input::UnregisterFactory<Input::ButtonDevice>("keyboard");
53 keyboard.reset();
54 Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
55 Input::UnregisterFactory<Input::MotionDevice>("motion_emu");
56 motion_emu.reset();
57#ifdef HAVE_SDL2 110#ifdef HAVE_SDL2
58 sdl.reset(); 111 std::unique_ptr<SDL::State> sdl;
59#endif 112#endif
60 udp.reset(); 113 std::unique_ptr<CemuhookUDP::State> udp;
61 Input::UnregisterFactory<Input::ButtonDevice>("gcpad"); 114 std::shared_ptr<GCButtonFactory> gcbuttons;
62 Input::UnregisterFactory<Input::AnalogDevice>("gcpad"); 115 std::shared_ptr<GCAnalogFactory> gcanalog;
116};
117
118InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {}
119
120InputSubsystem::~InputSubsystem() = default;
121
122void InputSubsystem::Initialize() {
123 impl->Initialize();
124}
125
126void InputSubsystem::Shutdown() {
127 impl->Shutdown();
128}
129
130Keyboard* InputSubsystem::GetKeyboard() {
131 return impl->keyboard.get();
132}
133
134const Keyboard* InputSubsystem::GetKeyboard() const {
135 return impl->keyboard.get();
136}
63 137
64 gcbuttons.reset(); 138MotionEmu* InputSubsystem::GetMotionEmu() {
65 gcanalog.reset(); 139 return impl->motion_emu.get();
66} 140}
67 141
68Keyboard* GetKeyboard() { 142const MotionEmu* InputSubsystem::GetMotionEmu() const {
69 return keyboard.get(); 143 return impl->motion_emu.get();
70} 144}
71 145
72MotionEmu* GetMotionEmu() { 146std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const {
73 return motion_emu.get(); 147 return impl->GetInputDevices();
74} 148}
75 149
76GCButtonFactory* GetGCButtons() { 150AnalogMapping InputSubsystem::GetAnalogMappingForDevice(const Common::ParamPackage& device) const {
77 return gcbuttons.get(); 151 return impl->GetAnalogMappingForDevice(device);
78} 152}
79 153
80GCAnalogFactory* GetGCAnalogs() { 154ButtonMapping InputSubsystem::GetButtonMappingForDevice(const Common::ParamPackage& device) const {
81 return gcanalog.get(); 155 return impl->GetButtonMappingForDevice(device);
156}
157
158GCAnalogFactory* InputSubsystem::GetGCAnalogs() {
159 return impl->gcanalog.get();
160}
161
162const GCAnalogFactory* InputSubsystem::GetGCAnalogs() const {
163 return impl->gcanalog.get();
164}
165
166GCButtonFactory* InputSubsystem::GetGCButtons() {
167 return impl->gcbuttons.get();
168}
169
170const GCButtonFactory* InputSubsystem::GetGCButtons() const {
171 return impl->gcbuttons.get();
172}
173
174std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers(
175 Polling::DeviceType type) const {
176#ifdef HAVE_SDL2
177 return impl->sdl->GetPollers(type);
178#else
179 return {};
180#endif
82} 181}
83 182
84std::string GenerateKeyboardParam(int key_code) { 183std::string GenerateKeyboardParam(int key_code) {
@@ -102,18 +201,4 @@ std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left,
102 }; 201 };
103 return circle_pad_param.Serialize(); 202 return circle_pad_param.Serialize();
104} 203}
105
106namespace Polling {
107
108std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) {
109 std::vector<std::unique_ptr<DevicePoller>> pollers;
110
111#ifdef HAVE_SDL2
112 pollers = sdl->GetPollers(type);
113#endif
114
115 return pollers;
116}
117
118} // namespace Polling
119} // namespace InputCommon 204} // namespace InputCommon
diff --git a/src/input_common/main.h b/src/input_common/main.h
index 0e32856f6..58e5dc250 100644
--- a/src/input_common/main.h
+++ b/src/input_common/main.h
@@ -6,45 +6,25 @@
6 6
7#include <memory> 7#include <memory>
8#include <string> 8#include <string>
9#include <unordered_map>
9#include <vector> 10#include <vector>
10#include "input_common/gcadapter/gc_poller.h"
11 11
12namespace Common { 12namespace Common {
13class ParamPackage; 13class ParamPackage;
14} 14}
15 15
16namespace InputCommon { 16namespace Settings::NativeAnalog {
17 17enum Values : int;
18/// Initializes and registers all built-in input device factories. 18}
19void Init();
20
21/// Deregisters all built-in input device factories and shuts them down.
22void Shutdown();
23
24class Keyboard;
25
26/// Gets the keyboard button device factory.
27Keyboard* GetKeyboard();
28
29class MotionEmu;
30
31/// Gets the motion emulation factory.
32MotionEmu* GetMotionEmu();
33
34GCButtonFactory* GetGCButtons();
35
36GCAnalogFactory* GetGCAnalogs();
37
38/// Generates a serialized param package for creating a keyboard button device
39std::string GenerateKeyboardParam(int key_code);
40 19
41/// Generates a serialized param package for creating an analog device taking input from keyboard 20namespace Settings::NativeButton {
42std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, 21enum Values : int;
43 int key_modifier, float modifier_scale); 22}
44 23
24namespace InputCommon {
45namespace Polling { 25namespace Polling {
46 26
47enum class DeviceType { Button, Analog }; 27enum class DeviceType { Button, AnalogPreferred };
48 28
49/** 29/**
50 * A class that can be used to get inputs from an input device like controllers without having to 30 * A class that can be used to get inputs from an input device like controllers without having to
@@ -54,7 +34,9 @@ class DevicePoller {
54public: 34public:
55 virtual ~DevicePoller() = default; 35 virtual ~DevicePoller() = default;
56 /// Setup and start polling for inputs, should be called before GetNextInput 36 /// Setup and start polling for inputs, should be called before GetNextInput
57 virtual void Start() = 0; 37 /// If a device_id is provided, events should be filtered to only include events from this
38 /// device id
39 virtual void Start(const std::string& device_id = "") = 0;
58 /// Stop polling 40 /// Stop polling
59 virtual void Stop() = 0; 41 virtual void Stop() = 0;
60 /** 42 /**
@@ -64,8 +46,89 @@ public:
64 */ 46 */
65 virtual Common::ParamPackage GetNextInput() = 0; 47 virtual Common::ParamPackage GetNextInput() = 0;
66}; 48};
67
68// Get all DevicePoller from all backends for a specific device type
69std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type);
70} // namespace Polling 49} // namespace Polling
50
51class GCAnalogFactory;
52class GCButtonFactory;
53class Keyboard;
54class MotionEmu;
55
56/**
57 * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default
58 * mapping for the device. This is currently only implemented for the SDL backend devices.
59 */
60using AnalogMapping = std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage>;
61using ButtonMapping = std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage>;
62
63class InputSubsystem {
64public:
65 explicit InputSubsystem();
66 ~InputSubsystem();
67
68 InputSubsystem(const InputSubsystem&) = delete;
69 InputSubsystem& operator=(const InputSubsystem&) = delete;
70
71 InputSubsystem(InputSubsystem&&) = delete;
72 InputSubsystem& operator=(InputSubsystem&&) = delete;
73
74 /// Initializes and registers all built-in input device factories.
75 void Initialize();
76
77 /// Unregisters all built-in input device factories and shuts them down.
78 void Shutdown();
79
80 /// Retrieves the underlying keyboard device.
81 [[nodiscard]] Keyboard* GetKeyboard();
82
83 /// Retrieves the underlying keyboard device.
84 [[nodiscard]] const Keyboard* GetKeyboard() const;
85
86 /// Retrieves the underlying motion emulation factory.
87 [[nodiscard]] MotionEmu* GetMotionEmu();
88
89 /// Retrieves the underlying motion emulation factory.
90 [[nodiscard]] const MotionEmu* GetMotionEmu() const;
91
92 /**
93 * Returns all available input devices that this Factory can create a new device with.
94 * Each returned ParamPackage should have a `display` field used for display, a class field for
95 * backends to determine if this backend is meant to service the request and any other
96 * information needed to identify this in the backend later.
97 */
98 [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const;
99
100 /// Retrieves the analog mappings for the given device.
101 [[nodiscard]] AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& device) const;
102
103 /// Retrieves the button mappings for the given device.
104 [[nodiscard]] ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& device) const;
105
106 /// Retrieves the underlying GameCube analog handler.
107 [[nodiscard]] GCAnalogFactory* GetGCAnalogs();
108
109 /// Retrieves the underlying GameCube analog handler.
110 [[nodiscard]] const GCAnalogFactory* GetGCAnalogs() const;
111
112 /// Retrieves the underlying GameCube button handler.
113 [[nodiscard]] GCButtonFactory* GetGCButtons();
114
115 /// Retrieves the underlying GameCube button handler.
116 [[nodiscard]] const GCButtonFactory* GetGCButtons() const;
117
118 /// Get all DevicePoller from all backends for a specific device type
119 [[nodiscard]] std::vector<std::unique_ptr<Polling::DevicePoller>> GetPollers(
120 Polling::DeviceType type) const;
121
122private:
123 struct Impl;
124 std::unique_ptr<Impl> impl;
125};
126
127/// Generates a serialized param package for creating a keyboard button device
128std::string GenerateKeyboardParam(int key_code);
129
130/// Generates a serialized param package for creating an analog device taking input from keyboard
131std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
132 int key_modifier, float modifier_scale);
133
71} // namespace InputCommon 134} // namespace InputCommon
diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h
index 5306daa70..f3554be9a 100644
--- a/src/input_common/sdl/sdl.h
+++ b/src/input_common/sdl/sdl.h
@@ -6,6 +6,7 @@
6 6
7#include <memory> 7#include <memory>
8#include <vector> 8#include <vector>
9#include "common/param_package.h"
9#include "input_common/main.h" 10#include "input_common/main.h"
10 11
11namespace InputCommon::Polling { 12namespace InputCommon::Polling {
@@ -22,14 +23,24 @@ public:
22 /// Unregisters SDL device factories and shut them down. 23 /// Unregisters SDL device factories and shut them down.
23 virtual ~State() = default; 24 virtual ~State() = default;
24 25
25 virtual Pollers GetPollers(Polling::DeviceType type) = 0; 26 virtual Pollers GetPollers(Polling::DeviceType type) {
27 return {};
28 }
29
30 virtual std::vector<Common::ParamPackage> GetInputDevices() {
31 return {};
32 }
33
34 virtual ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage&) {
35 return {};
36 }
37 virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) {
38 return {};
39 }
26}; 40};
27 41
28class NullState : public State { 42class NullState : public State {
29public: 43public:
30 Pollers GetPollers(Polling::DeviceType type) override {
31 return {};
32 }
33}; 44};
34 45
35std::unique_ptr<State> Init(); 46std::unique_ptr<State> Init();
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 675b477fa..a9e676f4b 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -3,10 +3,13 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <array>
6#include <atomic> 7#include <atomic>
7#include <cmath> 8#include <cmath>
8#include <functional> 9#include <functional>
9#include <mutex> 10#include <mutex>
11#include <optional>
12#include <sstream>
10#include <string> 13#include <string>
11#include <thread> 14#include <thread>
12#include <tuple> 15#include <tuple>
@@ -15,15 +18,16 @@
15#include <vector> 18#include <vector>
16#include <SDL.h> 19#include <SDL.h>
17#include "common/logging/log.h" 20#include "common/logging/log.h"
18#include "common/math_util.h"
19#include "common/param_package.h" 21#include "common/param_package.h"
20#include "common/threadsafe_queue.h" 22#include "common/threadsafe_queue.h"
21#include "core/frontend/input.h" 23#include "core/frontend/input.h"
22#include "input_common/sdl/sdl_impl.h" 24#include "input_common/sdl/sdl_impl.h"
25#include "input_common/settings.h"
23 26
24namespace InputCommon::SDL { 27namespace InputCommon::SDL {
25 28
26static std::string GetGUID(SDL_Joystick* joystick) { 29namespace {
30std::string GetGUID(SDL_Joystick* joystick) {
27 const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); 31 const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
28 char guid_str[33]; 32 char guid_str[33];
29 SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); 33 SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
@@ -31,7 +35,8 @@ static std::string GetGUID(SDL_Joystick* joystick) {
31} 35}
32 36
33/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice 37/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice
34static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event); 38Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event);
39} // Anonymous namespace
35 40
36static int SDLEventWatcher(void* user_data, SDL_Event* event) { 41static int SDLEventWatcher(void* user_data, SDL_Event* event) {
37 auto* const sdl_state = static_cast<SDLState*>(user_data); 42 auto* const sdl_state = static_cast<SDLState*>(user_data);
@@ -48,8 +53,10 @@ static int SDLEventWatcher(void* user_data, SDL_Event* event) {
48 53
49class SDLJoystick { 54class SDLJoystick {
50public: 55public:
51 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick) 56 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
52 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose} {} 57 SDL_GameController* gamecontroller)
58 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
59 sdl_controller{gamecontroller, &SDL_GameControllerClose} {}
53 60
54 void SetButton(int button, bool value) { 61 void SetButton(int button, bool value) {
55 std::lock_guard lock{mutex}; 62 std::lock_guard lock{mutex};
@@ -66,14 +73,14 @@ public:
66 state.axes.insert_or_assign(axis, value); 73 state.axes.insert_or_assign(axis, value);
67 } 74 }
68 75
69 float GetAxis(int axis) const { 76 float GetAxis(int axis, float range) const {
70 std::lock_guard lock{mutex}; 77 std::lock_guard lock{mutex};
71 return state.axes.at(axis) / 32767.0f; 78 return state.axes.at(axis) / (32767.0f * range);
72 } 79 }
73 80
74 std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const { 81 std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const {
75 float x = GetAxis(axis_x); 82 float x = GetAxis(axis_x, range);
76 float y = GetAxis(axis_y); 83 float y = GetAxis(axis_y, range);
77 y = -y; // 3DS uses an y-axis inverse from SDL 84 y = -y; // 3DS uses an y-axis inverse from SDL
78 85
79 // Make sure the coordinates are in the unit circle, 86 // Make sure the coordinates are in the unit circle,
@@ -115,10 +122,15 @@ public:
115 return sdl_joystick.get(); 122 return sdl_joystick.get();
116 } 123 }
117 124
118 void SetSDLJoystick(SDL_Joystick* joystick) { 125 void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
126 sdl_controller.reset(controller);
119 sdl_joystick.reset(joystick); 127 sdl_joystick.reset(joystick);
120 } 128 }
121 129
130 SDL_GameController* GetSDLGameController() const {
131 return sdl_controller.get();
132 }
133
122private: 134private:
123 struct State { 135 struct State {
124 std::unordered_map<int, bool> buttons; 136 std::unordered_map<int, bool> buttons;
@@ -128,6 +140,7 @@ private:
128 std::string guid; 140 std::string guid;
129 int port; 141 int port;
130 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; 142 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
143 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
131 mutable std::mutex mutex; 144 mutable std::mutex mutex;
132}; 145};
133 146
@@ -136,18 +149,19 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& g
136 const auto it = joystick_map.find(guid); 149 const auto it = joystick_map.find(guid);
137 if (it != joystick_map.end()) { 150 if (it != joystick_map.end()) {
138 while (it->second.size() <= static_cast<std::size_t>(port)) { 151 while (it->second.size() <= static_cast<std::size_t>(port)) {
139 auto joystick = 152 auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
140 std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()), nullptr); 153 nullptr, nullptr);
141 it->second.emplace_back(std::move(joystick)); 154 it->second.emplace_back(std::move(joystick));
142 } 155 }
143 return it->second[port]; 156 return it->second[port];
144 } 157 }
145 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr); 158 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
146 return joystick_map[guid].emplace_back(std::move(joystick)); 159 return joystick_map[guid].emplace_back(std::move(joystick));
147} 160}
148 161
149std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { 162std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
150 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); 163 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
164 auto sdl_controller = SDL_GameControllerFromInstanceID(sdl_id);
151 const std::string guid = GetGUID(sdl_joystick); 165 const std::string guid = GetGUID(sdl_joystick);
152 166
153 std::lock_guard lock{joystick_map_mutex}; 167 std::lock_guard lock{joystick_map_mutex};
@@ -171,23 +185,27 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_
171 }); 185 });
172 if (nullptr_it != map_it->second.end()) { 186 if (nullptr_it != map_it->second.end()) {
173 // ... and map it 187 // ... and map it
174 (*nullptr_it)->SetSDLJoystick(sdl_joystick); 188 (*nullptr_it)->SetSDLJoystick(sdl_joystick, sdl_controller);
175 return *nullptr_it; 189 return *nullptr_it;
176 } 190 }
177 191
178 // There is no SDLJoystick without a mapped SDL_Joystick 192 // There is no SDLJoystick without a mapped SDL_Joystick
179 // Create a new SDLJoystick 193 // Create a new SDLJoystick
180 const int port = static_cast<int>(map_it->second.size()); 194 const int port = static_cast<int>(map_it->second.size());
181 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick); 195 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_controller);
182 return map_it->second.emplace_back(std::move(joystick)); 196 return map_it->second.emplace_back(std::move(joystick));
183 } 197 }
184 198
185 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); 199 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_controller);
186 return joystick_map[guid].emplace_back(std::move(joystick)); 200 return joystick_map[guid].emplace_back(std::move(joystick));
187} 201}
188 202
189void SDLState::InitJoystick(int joystick_index) { 203void SDLState::InitJoystick(int joystick_index) {
190 SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index); 204 SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
205 SDL_GameController* sdl_gamecontroller = nullptr;
206 if (SDL_IsGameController(joystick_index)) {
207 sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
208 }
191 if (!sdl_joystick) { 209 if (!sdl_joystick) {
192 LOG_ERROR(Input, "failed to open joystick {}", joystick_index); 210 LOG_ERROR(Input, "failed to open joystick {}", joystick_index);
193 return; 211 return;
@@ -196,7 +214,7 @@ void SDLState::InitJoystick(int joystick_index) {
196 214
197 std::lock_guard lock{joystick_map_mutex}; 215 std::lock_guard lock{joystick_map_mutex};
198 if (joystick_map.find(guid) == joystick_map.end()) { 216 if (joystick_map.find(guid) == joystick_map.end()) {
199 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); 217 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
200 joystick_map[guid].emplace_back(std::move(joystick)); 218 joystick_map[guid].emplace_back(std::move(joystick));
201 return; 219 return;
202 } 220 }
@@ -205,11 +223,11 @@ void SDLState::InitJoystick(int joystick_index) {
205 joystick_guid_list.begin(), joystick_guid_list.end(), 223 joystick_guid_list.begin(), joystick_guid_list.end(),
206 [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); }); 224 [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); });
207 if (it != joystick_guid_list.end()) { 225 if (it != joystick_guid_list.end()) {
208 (*it)->SetSDLJoystick(sdl_joystick); 226 (*it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
209 return; 227 return;
210 } 228 }
211 const int port = static_cast<int>(joystick_guid_list.size()); 229 const int port = static_cast<int>(joystick_guid_list.size());
212 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick); 230 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
213 joystick_guid_list.emplace_back(std::move(joystick)); 231 joystick_guid_list.emplace_back(std::move(joystick));
214} 232}
215 233
@@ -231,7 +249,7 @@ void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
231 249
232 // Destruct SDL_Joystick outside the lock guard because SDL can internally call the 250 // Destruct SDL_Joystick outside the lock guard because SDL can internally call the
233 // event callback which locks the mutex again. 251 // event callback which locks the mutex again.
234 joystick->SetSDLJoystick(nullptr); 252 joystick->SetSDLJoystick(nullptr, nullptr);
235} 253}
236 254
237void SDLState::HandleGameControllerEvent(const SDL_Event& event) { 255void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
@@ -313,7 +331,7 @@ public:
313 trigger_if_greater(trigger_if_greater_) {} 331 trigger_if_greater(trigger_if_greater_) {}
314 332
315 bool GetStatus() const override { 333 bool GetStatus() const override {
316 const float axis_value = joystick->GetAxis(axis); 334 const float axis_value = joystick->GetAxis(axis, 1.0f);
317 if (trigger_if_greater) { 335 if (trigger_if_greater) {
318 return axis_value > threshold; 336 return axis_value > threshold;
319 } 337 }
@@ -329,22 +347,24 @@ private:
329 347
330class SDLAnalog final : public Input::AnalogDevice { 348class SDLAnalog final : public Input::AnalogDevice {
331public: 349public:
332 SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_) 350 SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_,
333 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_) {} 351 float range_)
352 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_),
353 range(range_) {}
334 354
335 std::tuple<float, float> GetStatus() const override { 355 std::tuple<float, float> GetStatus() const override {
336 const auto [x, y] = joystick->GetAnalog(axis_x, axis_y); 356 const auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range);
337 const float r = std::sqrt((x * x) + (y * y)); 357 const float r = std::sqrt((x * x) + (y * y));
338 if (r > deadzone) { 358 if (r > deadzone) {
339 return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone), 359 return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone),
340 y / r * (r - deadzone) / (1 - deadzone)); 360 y / r * (r - deadzone) / (1 - deadzone));
341 } 361 }
342 return std::make_tuple<float, float>(0.0f, 0.0f); 362 return {};
343 } 363 }
344 364
345 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { 365 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
346 const auto [x, y] = GetStatus(); 366 const auto [x, y] = GetStatus();
347 const float directional_deadzone = 0.4f; 367 const float directional_deadzone = 0.5f;
348 switch (direction) { 368 switch (direction) {
349 case Input::AnalogDirection::RIGHT: 369 case Input::AnalogDirection::RIGHT:
350 return x > directional_deadzone; 370 return x > directional_deadzone;
@@ -363,6 +383,7 @@ private:
363 const int axis_x; 383 const int axis_x;
364 const int axis_y; 384 const int axis_y;
365 const float deadzone; 385 const float deadzone;
386 const float range;
366}; 387};
367 388
368/// A button device factory that creates button devices from SDL joystick 389/// A button device factory that creates button devices from SDL joystick
@@ -457,14 +478,14 @@ public:
457 const int port = params.Get("port", 0); 478 const int port = params.Get("port", 0);
458 const int axis_x = params.Get("axis_x", 0); 479 const int axis_x = params.Get("axis_x", 0);
459 const int axis_y = params.Get("axis_y", 1); 480 const int axis_y = params.Get("axis_y", 1);
460 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); 481 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
461 482 const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
462 auto joystick = state.GetSDLJoystickByGUID(guid, port); 483 auto joystick = state.GetSDLJoystickByGUID(guid, port);
463 484
464 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash 485 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash
465 joystick->SetAxis(axis_x, 0); 486 joystick->SetAxis(axis_x, 0);
466 joystick->SetAxis(axis_y, 0); 487 joystick->SetAxis(axis_y, 0);
467 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone); 488 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone, range);
468 } 489 }
469 490
470private: 491private:
@@ -473,8 +494,10 @@ private:
473 494
474SDLState::SDLState() { 495SDLState::SDLState() {
475 using namespace Input; 496 using namespace Input;
476 RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>(*this)); 497 analog_factory = std::make_shared<SDLAnalogFactory>(*this);
477 RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>(*this)); 498 button_factory = std::make_shared<SDLButtonFactory>(*this);
499 RegisterFactory<AnalogDevice>("sdl", analog_factory);
500 RegisterFactory<ButtonDevice>("sdl", button_factory);
478 501
479 // If the frontend is going to manage the event loop, then we dont start one here 502 // If the frontend is going to manage the event loop, then we dont start one here
480 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK); 503 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK);
@@ -482,6 +505,7 @@ SDLState::SDLState() {
482 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); 505 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
483 return; 506 return;
484 } 507 }
508 has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
485 if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) { 509 if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
486 LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError()); 510 LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
487 } 511 }
@@ -494,7 +518,7 @@ SDLState::SDLState() {
494 using namespace std::chrono_literals; 518 using namespace std::chrono_literals;
495 while (initialized) { 519 while (initialized) {
496 SDL_PumpEvents(); 520 SDL_PumpEvents();
497 std::this_thread::sleep_for(10ms); 521 std::this_thread::sleep_for(5ms);
498 } 522 }
499 }); 523 });
500 } 524 }
@@ -520,65 +544,230 @@ SDLState::~SDLState() {
520 } 544 }
521} 545}
522 546
523static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { 547std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
548 std::scoped_lock lock(joystick_map_mutex);
549 std::vector<Common::ParamPackage> devices;
550 for (const auto& [key, value] : joystick_map) {
551 for (const auto& joystick : value) {
552 auto joy = joystick->GetSDLJoystick();
553 if (auto controller = joystick->GetSDLGameController()) {
554 std::string name =
555 fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
556 devices.emplace_back(Common::ParamPackage{
557 {"class", "sdl"},
558 {"display", std::move(name)},
559 {"guid", joystick->GetGUID()},
560 {"port", std::to_string(joystick->GetPort())},
561 });
562 } else if (joy) {
563 std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort());
564 devices.emplace_back(Common::ParamPackage{
565 {"class", "sdl"},
566 {"display", std::move(name)},
567 {"guid", joystick->GetGUID()},
568 {"port", std::to_string(joystick->GetPort())},
569 });
570 }
571 }
572 }
573 return devices;
574}
575
576namespace {
577Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, u8 axis,
578 float value = 0.1f) {
579 Common::ParamPackage params({{"engine", "sdl"}});
580 params.Set("port", port);
581 params.Set("guid", std::move(guid));
582 params.Set("axis", axis);
583 if (value > 0) {
584 params.Set("direction", "+");
585 params.Set("threshold", "0.5");
586 } else {
587 params.Set("direction", "-");
588 params.Set("threshold", "-0.5");
589 }
590 return params;
591}
592
593Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, u8 button) {
524 Common::ParamPackage params({{"engine", "sdl"}}); 594 Common::ParamPackage params({{"engine", "sdl"}});
595 params.Set("port", port);
596 params.Set("guid", std::move(guid));
597 params.Set("button", button);
598 return params;
599}
600
601Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, u8 hat, u8 value) {
602 Common::ParamPackage params({{"engine", "sdl"}});
603
604 params.Set("port", port);
605 params.Set("guid", std::move(guid));
606 params.Set("hat", hat);
607 switch (value) {
608 case SDL_HAT_UP:
609 params.Set("direction", "up");
610 break;
611 case SDL_HAT_DOWN:
612 params.Set("direction", "down");
613 break;
614 case SDL_HAT_LEFT:
615 params.Set("direction", "left");
616 break;
617 case SDL_HAT_RIGHT:
618 params.Set("direction", "right");
619 break;
620 default:
621 return {};
622 }
623 return params;
624}
525 625
626Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
526 switch (event.type) { 627 switch (event.type) {
527 case SDL_JOYAXISMOTION: { 628 case SDL_JOYAXISMOTION: {
528 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 629 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
529 params.Set("port", joystick->GetPort()); 630 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
530 params.Set("guid", joystick->GetGUID()); 631 event.jaxis.axis, event.jaxis.value);
531 params.Set("axis", event.jaxis.axis);
532 if (event.jaxis.value > 0) {
533 params.Set("direction", "+");
534 params.Set("threshold", "0.5");
535 } else {
536 params.Set("direction", "-");
537 params.Set("threshold", "-0.5");
538 }
539 break;
540 } 632 }
541 case SDL_JOYBUTTONUP: { 633 case SDL_JOYBUTTONUP: {
542 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); 634 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
543 params.Set("port", joystick->GetPort()); 635 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
544 params.Set("guid", joystick->GetGUID()); 636 event.jbutton.button);
545 params.Set("button", event.jbutton.button);
546 break;
547 } 637 }
548 case SDL_JOYHATMOTION: { 638 case SDL_JOYHATMOTION: {
549 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); 639 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
550 params.Set("port", joystick->GetPort()); 640 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
551 params.Set("guid", joystick->GetGUID()); 641 event.jhat.hat, event.jhat.value);
552 params.Set("hat", event.jhat.hat);
553 switch (event.jhat.value) {
554 case SDL_HAT_UP:
555 params.Set("direction", "up");
556 break;
557 case SDL_HAT_DOWN:
558 params.Set("direction", "down");
559 break;
560 case SDL_HAT_LEFT:
561 params.Set("direction", "left");
562 break;
563 case SDL_HAT_RIGHT:
564 params.Set("direction", "right");
565 break;
566 default:
567 return {};
568 }
569 break;
570 } 642 }
571 } 643 }
644 return {};
645}
646
647Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
648 const SDL_GameControllerButtonBind& binding) {
649 switch (binding.bindType) {
650 case SDL_CONTROLLER_BINDTYPE_AXIS:
651 return BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
652 case SDL_CONTROLLER_BINDTYPE_BUTTON:
653 return BuildButtonParamPackageForButton(port, guid, binding.value.button);
654 case SDL_CONTROLLER_BINDTYPE_HAT:
655 return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat,
656 binding.value.hat.hat_mask);
657 }
658 return {};
659}
660
661Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x,
662 int axis_y) {
663 Common::ParamPackage params;
664 params.Set("engine", "sdl");
665 params.Set("port", port);
666 params.Set("guid", guid);
667 params.Set("axis_x", axis_x);
668 params.Set("axis_y", axis_y);
572 return params; 669 return params;
573} 670}
671} // Anonymous namespace
574 672
575namespace Polling { 673ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) {
674 if (!params.Has("guid") || !params.Has("port")) {
675 return {};
676 }
677 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
678 auto* controller = joystick->GetSDLGameController();
679 if (controller == nullptr) {
680 return {};
681 }
682
683 // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
684 // We will add those afterwards
685 // This list also excludes Screenshot since theres not really a mapping for that
686 using ButtonBindings =
687 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
688 static constexpr ButtonBindings switch_to_sdl_button{{
689 {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
690 {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
691 {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
692 {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
693 {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
694 {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
695 {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
696 {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
697 {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
698 {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
699 {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
700 {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
701 {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
702 {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
703 {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
704 {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
705 {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
706 }};
707
708 // Add the missing bindings for ZL/ZR
709 using ZBindings =
710 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
711 static constexpr ZBindings switch_to_sdl_axis{{
712 {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
713 {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
714 }};
715
716 ButtonMapping mapping;
717 mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
718
719 for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
720 const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
721 mapping.insert_or_assign(
722 switch_button,
723 BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
724 }
725 for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
726 const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
727 mapping.insert_or_assign(
728 switch_button,
729 BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
730 }
731
732 return mapping;
733}
576 734
735AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
736 if (!params.Has("guid") || !params.Has("port")) {
737 return {};
738 }
739 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
740 auto* controller = joystick->GetSDLGameController();
741 if (controller == nullptr) {
742 return {};
743 }
744
745 AnalogMapping mapping = {};
746 const auto& binding_left_x =
747 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
748 const auto& binding_left_y =
749 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
750 mapping.insert_or_assign(Settings::NativeAnalog::LStick,
751 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
752 binding_left_x.value.axis,
753 binding_left_y.value.axis));
754 const auto& binding_right_x =
755 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
756 const auto& binding_right_y =
757 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
758 mapping.insert_or_assign(Settings::NativeAnalog::RStick,
759 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
760 binding_right_x.value.axis,
761 binding_right_y.value.axis));
762 return mapping;
763}
764
765namespace Polling {
577class SDLPoller : public InputCommon::Polling::DevicePoller { 766class SDLPoller : public InputCommon::Polling::DevicePoller {
578public: 767public:
579 explicit SDLPoller(SDLState& state_) : state(state_) {} 768 explicit SDLPoller(SDLState& state_) : state(state_) {}
580 769
581 void Start() override { 770 void Start(const std::string& device_id) override {
582 state.event_queue.Clear(); 771 state.event_queue.Clear();
583 state.polling = true; 772 state.polling = true;
584 } 773 }
@@ -598,71 +787,106 @@ public:
598 Common::ParamPackage GetNextInput() override { 787 Common::ParamPackage GetNextInput() override {
599 SDL_Event event; 788 SDL_Event event;
600 while (state.event_queue.Pop(event)) { 789 while (state.event_queue.Pop(event)) {
601 switch (event.type) { 790 const auto package = FromEvent(event);
602 case SDL_JOYAXISMOTION: 791 if (package) {
603 if (std::abs(event.jaxis.value / 32767.0) < 0.5) { 792 return *package;
604 break;
605 }
606 [[fallthrough]];
607 case SDL_JOYBUTTONUP:
608 case SDL_JOYHATMOTION:
609 return SDLEventToButtonParamPackage(state, event);
610 } 793 }
611 } 794 }
612 return {}; 795 return {};
613 } 796 }
797 [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
798 switch (event.type) {
799 case SDL_JOYAXISMOTION:
800 if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
801 break;
802 }
803 [[fallthrough]];
804 case SDL_JOYBUTTONUP:
805 case SDL_JOYHATMOTION:
806 return {SDLEventToButtonParamPackage(state, event)};
807 }
808 return std::nullopt;
809 }
614}; 810};
615 811
616class SDLAnalogPoller final : public SDLPoller { 812/**
813 * Attempts to match the press to a controller joy axis (left/right stick) and if a match
814 * isn't found, checks if the event matches anything from SDLButtonPoller and uses that
815 * instead
816 */
817class SDLAnalogPreferredPoller final : public SDLPoller {
617public: 818public:
618 explicit SDLAnalogPoller(SDLState& state_) : SDLPoller(state_) {} 819 explicit SDLAnalogPreferredPoller(SDLState& state_)
619 820 : SDLPoller(state_), button_poller(state_) {}
620 void Start() override {
621 SDLPoller::Start();
622 821
822 void Start(const std::string& device_id) override {
823 SDLPoller::Start(device_id);
824 // Load the game controller
623 // Reset stored axes 825 // Reset stored axes
624 analog_x_axis = -1; 826 analog_x_axis = -1;
625 analog_y_axis = -1; 827 analog_y_axis = -1;
626 analog_axes_joystick = -1;
627 } 828 }
628 829
629 Common::ParamPackage GetNextInput() override { 830 Common::ParamPackage GetNextInput() override {
630 SDL_Event event; 831 SDL_Event event;
631 while (state.event_queue.Pop(event)) { 832 while (state.event_queue.Pop(event)) {
632 if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) { 833 // Filter out axis events that are below a threshold
834 if (event.type == SDL_JOYAXISMOTION && std::abs(event.jaxis.value / 32767.0) < 0.5) {
633 continue; 835 continue;
634 } 836 }
635 // An analog device needs two axes, so we need to store the axis for later and wait for 837 // Simplify controller config by testing if game controller support is enabled.
636 // a second SDL event. The axes also must be from the same joystick. 838 if (event.type == SDL_JOYAXISMOTION) {
637 const int axis = event.jaxis.axis; 839 const auto axis = event.jaxis.axis;
638 if (analog_x_axis == -1) { 840 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
639 analog_x_axis = axis; 841 const auto controller = joystick->GetSDLGameController();
640 analog_axes_joystick = event.jaxis.which; 842 if (controller) {
641 } else if (analog_y_axis == -1 && analog_x_axis != axis && 843 const auto axis_left_x =
642 analog_axes_joystick == event.jaxis.which) { 844 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)
643 analog_y_axis = axis; 845 .value.axis;
846 const auto axis_left_y =
847 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY)
848 .value.axis;
849 const auto axis_right_x =
850 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX)
851 .value.axis;
852 const auto axis_right_y =
853 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY)
854 .value.axis;
855
856 if (axis == axis_left_x || axis == axis_left_y) {
857 analog_x_axis = axis_left_x;
858 analog_y_axis = axis_left_y;
859 break;
860 } else if (axis == axis_right_x || axis == axis_right_y) {
861 analog_x_axis = axis_right_x;
862 analog_y_axis = axis_right_y;
863 break;
864 }
865 }
866 }
867
868 // If the press wasn't accepted as a joy axis, check for a button press
869 auto button_press = button_poller.FromEvent(event);
870 if (button_press) {
871 return *button_press;
644 } 872 }
645 } 873 }
646 Common::ParamPackage params; 874
647 if (analog_x_axis != -1 && analog_y_axis != -1) { 875 if (analog_x_axis != -1 && analog_y_axis != -1) {
648 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 876 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
649 params.Set("engine", "sdl"); 877 auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
650 params.Set("port", joystick->GetPort()); 878 analog_x_axis, analog_y_axis);
651 params.Set("guid", joystick->GetGUID());
652 params.Set("axis_x", analog_x_axis);
653 params.Set("axis_y", analog_y_axis);
654 analog_x_axis = -1; 879 analog_x_axis = -1;
655 analog_y_axis = -1; 880 analog_y_axis = -1;
656 analog_axes_joystick = -1;
657 return params; 881 return params;
658 } 882 }
659 return params; 883 return {};
660 } 884 }
661 885
662private: 886private:
663 int analog_x_axis = -1; 887 int analog_x_axis = -1;
664 int analog_y_axis = -1; 888 int analog_y_axis = -1;
665 SDL_JoystickID analog_axes_joystick = -1; 889 SDLButtonPoller button_poller;
666}; 890};
667} // namespace Polling 891} // namespace Polling
668 892
@@ -670,8 +894,8 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
670 Pollers pollers; 894 Pollers pollers;
671 895
672 switch (type) { 896 switch (type) {
673 case InputCommon::Polling::DeviceType::Analog: 897 case InputCommon::Polling::DeviceType::AnalogPreferred:
674 pollers.emplace_back(std::make_unique<Polling::SDLAnalogPoller>(*this)); 898 pollers.emplace_back(std::make_unique<Polling::SDLAnalogPreferredPoller>(*this));
675 break; 899 break;
676 case InputCommon::Polling::DeviceType::Button: 900 case InputCommon::Polling::DeviceType::Button:
677 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this)); 901 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h
index 606a32c5b..bd19ba61d 100644
--- a/src/input_common/sdl/sdl_impl.h
+++ b/src/input_common/sdl/sdl_impl.h
@@ -50,6 +50,11 @@ public:
50 std::atomic<bool> polling = false; 50 std::atomic<bool> polling = false;
51 Common::SPSCQueue<SDL_Event> event_queue; 51 Common::SPSCQueue<SDL_Event> event_queue;
52 52
53 std::vector<Common::ParamPackage> GetInputDevices() override;
54
55 ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;
56 AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override;
57
53private: 58private:
54 void InitJoystick(int joystick_index); 59 void InitJoystick(int joystick_index);
55 void CloseJoystick(SDL_Joystick* sdl_joystick); 60 void CloseJoystick(SDL_Joystick* sdl_joystick);
@@ -57,6 +62,9 @@ private:
57 /// Needs to be called before SDL_QuitSubSystem. 62 /// Needs to be called before SDL_QuitSubSystem.
58 void CloseJoysticks(); 63 void CloseJoysticks();
59 64
65 // Set to true if SDL supports game controller subsystem
66 bool has_gamecontroller = false;
67
60 /// Map of GUID of a list of corresponding virtual Joysticks 68 /// Map of GUID of a list of corresponding virtual Joysticks
61 std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map; 69 std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
62 std::mutex joystick_map_mutex; 70 std::mutex joystick_map_mutex;
diff --git a/src/input_common/settings.cpp b/src/input_common/settings.cpp
new file mode 100644
index 000000000..80c719cf4
--- /dev/null
+++ b/src/input_common/settings.cpp
@@ -0,0 +1,33 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "input_common/settings.h"
6
7namespace Settings {
8namespace NativeButton {
9const std::array<const char*, NumButtons> mapping = {{
10 "button_a", "button_b", "button_x", "button_y", "button_lstick",
11 "button_rstick", "button_l", "button_r", "button_zl", "button_zr",
12 "button_plus", "button_minus", "button_dleft", "button_dup", "button_dright",
13 "button_ddown", "button_sl", "button_sr", "button_home", "button_screenshot",
14}};
15}
16
17namespace NativeAnalog {
18const std::array<const char*, NumAnalogs> mapping = {{
19 "lstick",
20 "rstick",
21}};
22}
23
24namespace NativeMouseButton {
25const std::array<const char*, NumMouseButtons> mapping = {{
26 "left",
27 "right",
28 "middle",
29 "forward",
30 "back",
31}};
32}
33} // namespace Settings
diff --git a/src/input_common/settings.h b/src/input_common/settings.h
new file mode 100644
index 000000000..2d258960b
--- /dev/null
+++ b/src/input_common/settings.h
@@ -0,0 +1,335 @@
1// Copyright 2020 yuzu 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 <string>
9#include "common/common_types.h"
10
11namespace Settings {
12namespace NativeButton {
13enum Values : int {
14 A,
15 B,
16 X,
17 Y,
18 LStick,
19 RStick,
20 L,
21 R,
22 ZL,
23 ZR,
24 Plus,
25 Minus,
26
27 DLeft,
28 DUp,
29 DRight,
30 DDown,
31
32 SL,
33 SR,
34
35 Home,
36 Screenshot,
37
38 NumButtons,
39};
40
41constexpr int BUTTON_HID_BEGIN = A;
42constexpr int BUTTON_NS_BEGIN = Home;
43
44constexpr int BUTTON_HID_END = BUTTON_NS_BEGIN;
45constexpr int BUTTON_NS_END = NumButtons;
46
47constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN;
48constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN;
49
50extern const std::array<const char*, NumButtons> mapping;
51
52} // namespace NativeButton
53
54namespace NativeAnalog {
55enum Values : int {
56 LStick,
57 RStick,
58
59 NumAnalogs,
60};
61
62constexpr int STICK_HID_BEGIN = LStick;
63constexpr int STICK_HID_END = NumAnalogs;
64constexpr int NUM_STICKS_HID = NumAnalogs;
65
66extern const std::array<const char*, NumAnalogs> mapping;
67} // namespace NativeAnalog
68
69namespace NativeMouseButton {
70enum Values {
71 Left,
72 Right,
73 Middle,
74 Forward,
75 Back,
76
77 NumMouseButtons,
78};
79
80constexpr int MOUSE_HID_BEGIN = Left;
81constexpr int MOUSE_HID_END = NumMouseButtons;
82constexpr int NUM_MOUSE_HID = NumMouseButtons;
83
84extern const std::array<const char*, NumMouseButtons> mapping;
85} // namespace NativeMouseButton
86
87namespace NativeKeyboard {
88enum Keys {
89 None,
90 Error,
91
92 A = 4,
93 B,
94 C,
95 D,
96 E,
97 F,
98 G,
99 H,
100 I,
101 J,
102 K,
103 L,
104 M,
105 N,
106 O,
107 P,
108 Q,
109 R,
110 S,
111 T,
112 U,
113 V,
114 W,
115 X,
116 Y,
117 Z,
118 N1,
119 N2,
120 N3,
121 N4,
122 N5,
123 N6,
124 N7,
125 N8,
126 N9,
127 N0,
128 Enter,
129 Escape,
130 Backspace,
131 Tab,
132 Space,
133 Minus,
134 Equal,
135 LeftBrace,
136 RightBrace,
137 Backslash,
138 Tilde,
139 Semicolon,
140 Apostrophe,
141 Grave,
142 Comma,
143 Dot,
144 Slash,
145 CapsLockKey,
146
147 F1,
148 F2,
149 F3,
150 F4,
151 F5,
152 F6,
153 F7,
154 F8,
155 F9,
156 F10,
157 F11,
158 F12,
159
160 SystemRequest,
161 ScrollLockKey,
162 Pause,
163 Insert,
164 Home,
165 PageUp,
166 Delete,
167 End,
168 PageDown,
169 Right,
170 Left,
171 Down,
172 Up,
173
174 NumLockKey,
175 KPSlash,
176 KPAsterisk,
177 KPMinus,
178 KPPlus,
179 KPEnter,
180 KP1,
181 KP2,
182 KP3,
183 KP4,
184 KP5,
185 KP6,
186 KP7,
187 KP8,
188 KP9,
189 KP0,
190 KPDot,
191
192 Key102,
193 Compose,
194 Power,
195 KPEqual,
196
197 F13,
198 F14,
199 F15,
200 F16,
201 F17,
202 F18,
203 F19,
204 F20,
205 F21,
206 F22,
207 F23,
208 F24,
209
210 Open,
211 Help,
212 Properties,
213 Front,
214 Stop,
215 Repeat,
216 Undo,
217 Cut,
218 Copy,
219 Paste,
220 Find,
221 Mute,
222 VolumeUp,
223 VolumeDown,
224 CapsLockActive,
225 NumLockActive,
226 ScrollLockActive,
227 KPComma,
228
229 KPLeftParenthesis,
230 KPRightParenthesis,
231
232 LeftControlKey = 0xE0,
233 LeftShiftKey,
234 LeftAltKey,
235 LeftMetaKey,
236 RightControlKey,
237 RightShiftKey,
238 RightAltKey,
239 RightMetaKey,
240
241 MediaPlayPause,
242 MediaStopCD,
243 MediaPrevious,
244 MediaNext,
245 MediaEject,
246 MediaVolumeUp,
247 MediaVolumeDown,
248 MediaMute,
249 MediaWebsite,
250 MediaBack,
251 MediaForward,
252 MediaStop,
253 MediaFind,
254 MediaScrollUp,
255 MediaScrollDown,
256 MediaEdit,
257 MediaSleep,
258 MediaCoffee,
259 MediaRefresh,
260 MediaCalculator,
261
262 NumKeyboardKeys,
263};
264
265static_assert(NumKeyboardKeys == 0xFC, "Incorrect number of keyboard keys.");
266
267enum Modifiers {
268 LeftControl,
269 LeftShift,
270 LeftAlt,
271 LeftMeta,
272 RightControl,
273 RightShift,
274 RightAlt,
275 RightMeta,
276 CapsLock,
277 ScrollLock,
278 NumLock,
279
280 NumKeyboardMods,
281};
282
283constexpr int KEYBOARD_KEYS_HID_BEGIN = None;
284constexpr int KEYBOARD_KEYS_HID_END = NumKeyboardKeys;
285constexpr int NUM_KEYBOARD_KEYS_HID = NumKeyboardKeys;
286
287constexpr int KEYBOARD_MODS_HID_BEGIN = LeftControl;
288constexpr int KEYBOARD_MODS_HID_END = NumKeyboardMods;
289constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;
290
291} // namespace NativeKeyboard
292
293using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
294using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;
295using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>;
296using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>;
297using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;
298
299constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
300constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
301constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
302constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
303
304enum class ControllerType {
305 ProController,
306 DualJoyconDetached,
307 LeftJoycon,
308 RightJoycon,
309 Handheld,
310};
311
312struct PlayerInput {
313 bool connected;
314 ControllerType controller_type;
315 ButtonsRaw buttons;
316 AnalogsRaw analogs;
317 std::string lstick_mod;
318 std::string rstick_mod;
319
320 u32 body_color_left;
321 u32 body_color_right;
322 u32 button_color_left;
323 u32 button_color_right;
324};
325
326struct TouchscreenInput {
327 bool enabled;
328 std::string device;
329
330 u32 finger;
331 u32 diameter_x;
332 u32 diameter_y;
333 u32 rotation_angle;
334};
335} // namespace Settings
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index 6c95a8b42..3f4eaf448 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -224,8 +224,7 @@ void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 clie
224 } else { 224 } else {
225 failure_callback(); 225 failure_callback();
226 } 226 }
227 }) 227 }).detach();
228 .detach();
229} 228}
230 229
231CalibrationConfigurationJob::CalibrationConfigurationJob( 230CalibrationConfigurationJob::CalibrationConfigurationJob(
@@ -279,8 +278,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
279 complete_event.Wait(); 278 complete_event.Wait();
280 socket.Stop(); 279 socket.Stop();
281 worker_thread.join(); 280 worker_thread.join();
282 }) 281 }).detach();
283 .detach();
284} 282}
285 283
286CalibrationConfigurationJob::~CalibrationConfigurationJob() { 284CalibrationConfigurationJob::~CalibrationConfigurationJob() {
diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp
index 8c6ef1394..4b347e47e 100644
--- a/src/input_common/udp/udp.cpp
+++ b/src/input_common/udp/udp.cpp
@@ -77,10 +77,11 @@ State::State() {
77 std::make_unique<Client>(status, Settings::values.udp_input_address, 77 std::make_unique<Client>(status, Settings::values.udp_input_address,
78 Settings::values.udp_input_port, Settings::values.udp_pad_index); 78 Settings::values.udp_input_port, Settings::values.udp_pad_index);
79 79
80 Input::RegisterFactory<Input::TouchDevice>("cemuhookudp", 80 motion_factory = std::make_shared<UDPMotionFactory>(status);
81 std::make_shared<UDPTouchFactory>(status)); 81 touch_factory = std::make_shared<UDPTouchFactory>(status);
82 Input::RegisterFactory<Input::MotionDevice>("cemuhookudp", 82
83 std::make_shared<UDPMotionFactory>(status)); 83 Input::RegisterFactory<Input::MotionDevice>("cemuhookudp", motion_factory);
84 Input::RegisterFactory<Input::TouchDevice>("cemuhookudp", touch_factory);
84} 85}
85 86
86State::~State() { 87State::~State() {
@@ -88,6 +89,11 @@ State::~State() {
88 Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp"); 89 Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp");
89} 90}
90 91
92std::vector<Common::ParamPackage> State::GetInputDevices() const {
93 // TODO support binding udp devices
94 return {};
95}
96
91void State::ReloadUDPClient() { 97void State::ReloadUDPClient() {
92 client->ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port, 98 client->ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port,
93 Settings::values.udp_pad_index); 99 Settings::values.udp_pad_index);
diff --git a/src/input_common/udp/udp.h b/src/input_common/udp/udp.h
index 4f83f0441..672a5c812 100644
--- a/src/input_common/udp/udp.h
+++ b/src/input_common/udp/udp.h
@@ -5,19 +5,26 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <vector>
9#include "common/param_package.h"
8 10
9namespace InputCommon::CemuhookUDP { 11namespace InputCommon::CemuhookUDP {
10 12
11class Client; 13class Client;
14class UDPMotionFactory;
15class UDPTouchFactory;
12 16
13class State { 17class State {
14public: 18public:
15 State(); 19 State();
16 ~State(); 20 ~State();
17 void ReloadUDPClient(); 21 void ReloadUDPClient();
22 std::vector<Common::ParamPackage> GetInputDevices() const;
18 23
19private: 24private:
20 std::unique_ptr<Client> client; 25 std::unique_ptr<Client> client;
26 std::shared_ptr<UDPMotionFactory> motion_factory;
27 std::shared_ptr<UDPTouchFactory> touch_factory;
21}; 28};
22 29
23std::unique_ptr<State> Init(); 30std::unique_ptr<State> Init();