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.cpp4
-rw-r--r--src/input_common/main.cpp51
-rw-r--r--src/input_common/main.h26
-rw-r--r--src/input_common/sdl/sdl.h19
-rw-r--r--src/input_common/sdl/sdl_impl.cpp399
-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/udp.cpp14
-rw-r--r--src/input_common/udp/udp.h7
11 files changed, 791 insertions, 107 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 b346fdf8e..71cd85eeb 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -191,7 +191,7 @@ public:
191 191
192 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { 192 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
193 const auto [x, y] = GetStatus(); 193 const auto [x, y] = GetStatus();
194 const float directional_deadzone = 0.4f; 194 const float directional_deadzone = 0.5f;
195 switch (direction) { 195 switch (direction) {
196 case Input::AnalogDirection::RIGHT: 196 case Input::AnalogDirection::RIGHT:
197 return x > directional_deadzone; 197 return x > directional_deadzone;
@@ -232,7 +232,7 @@ std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::Param
232 const int port = params.Get("port", 0); 232 const int port = params.Get("port", 0);
233 const int axis_x = params.Get("axis_x", 0); 233 const int axis_x = params.Get("axis_x", 0);
234 const int axis_y = params.Get("axis_y", 1); 234 const int axis_y = params.Get("axis_y", 1);
235 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); 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(), range); 238 return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get(), range);
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index b9d5d0ec3..8e67a7437 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -44,7 +44,6 @@ void Init() {
44#ifdef HAVE_SDL2 44#ifdef HAVE_SDL2
45 sdl = SDL::Init(); 45 sdl = SDL::Init();
46#endif 46#endif
47
48 udp = CemuhookUDP::Init(); 47 udp = CemuhookUDP::Init();
49} 48}
50 49
@@ -103,6 +102,56 @@ std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left,
103 return circle_pad_param.Serialize(); 102 return circle_pad_param.Serialize();
104} 103}
105 104
105std::vector<Common::ParamPackage> GetInputDevices() {
106 std::vector<Common::ParamPackage> devices = {
107 Common::ParamPackage{{"display", "Any"}, {"class", "any"}},
108 Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "key"}},
109 };
110#ifdef HAVE_SDL2
111 auto sdl_devices = sdl->GetInputDevices();
112 devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end());
113#endif
114 auto udp_devices = udp->GetInputDevices();
115 devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
116 return devices;
117}
118
119std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage> GetButtonMappingForDevice(
120 const Common::ParamPackage& params) {
121 std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage> mappings;
122 if (!params.Has("class") || params.Get("class", "") == "any") {
123 return {};
124 }
125 if (params.Get("class", "") == "key") {
126 // TODO consider returning the SDL key codes for the default keybindings
127 return {};
128 }
129#ifdef HAVE_SDL2
130 if (params.Get("class", "") == "sdl") {
131 return sdl->GetButtonMappingForDevice(params);
132 }
133#endif
134 return {};
135}
136
137std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage> GetAnalogMappingForDevice(
138 const Common::ParamPackage& params) {
139 std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage> mappings;
140 if (!params.Has("class") || params.Get("class", "") == "any") {
141 return {};
142 }
143 if (params.Get("class", "") == "key") {
144 // TODO consider returning the SDL key codes for the default keybindings
145 return {};
146 }
147#ifdef HAVE_SDL2
148 if (params.Get("class", "") == "sdl") {
149 return sdl->GetAnalogMappingForDevice(params);
150 }
151#endif
152 return {};
153}
154
106namespace Polling { 155namespace Polling {
107 156
108std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) { 157std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) {
diff --git a/src/input_common/main.h b/src/input_common/main.h
index 0e32856f6..e706c3750 100644
--- a/src/input_common/main.h
+++ b/src/input_common/main.h
@@ -6,8 +6,10 @@
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#include "input_common/gcadapter/gc_poller.h"
12#include "input_common/settings.h"
11 13
12namespace Common { 14namespace Common {
13class ParamPackage; 15class ParamPackage;
@@ -42,9 +44,27 @@ std::string GenerateKeyboardParam(int key_code);
42std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, 44std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
43 int key_modifier, float modifier_scale); 45 int key_modifier, float modifier_scale);
44 46
47/**
48 * Return a list of available input devices that this Factory can create a new device with.
49 * Each returned Parampackage should have a `display` field used for display, a class field for
50 * backends to determine if this backend is meant to service the request and any other information
51 * needed to identify this in the backend later.
52 */
53std::vector<Common::ParamPackage> GetInputDevices();
54
55/**
56 * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default
57 * mapping for the device. This is currently only implemented for the sdl backend devices.
58 */
59using ButtonMapping = std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage>;
60using AnalogMapping = std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage>;
61
62ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage&);
63AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&);
64
45namespace Polling { 65namespace Polling {
46 66
47enum class DeviceType { Button, Analog }; 67enum class DeviceType { Button, AnalogPreferred };
48 68
49/** 69/**
50 * A class that can be used to get inputs from an input device like controllers without having to 70 * A class that can be used to get inputs from an input device like controllers without having to
@@ -54,7 +74,9 @@ class DevicePoller {
54public: 74public:
55 virtual ~DevicePoller() = default; 75 virtual ~DevicePoller() = default;
56 /// Setup and start polling for inputs, should be called before GetNextInput 76 /// Setup and start polling for inputs, should be called before GetNextInput
57 virtual void Start() = 0; 77 /// If a device_id is provided, events should be filtered to only include events from this
78 /// device id
79 virtual void Start(const std::string& device_id = "") = 0;
58 /// Stop polling 80 /// Stop polling
59 virtual void Stop() = 0; 81 virtual void Stop() = 0;
60 /** 82 /**
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 d76c279d3..7605c884d 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -7,6 +7,8 @@
7#include <cmath> 7#include <cmath>
8#include <functional> 8#include <functional>
9#include <mutex> 9#include <mutex>
10#include <optional>
11#include <sstream>
10#include <string> 12#include <string>
11#include <thread> 13#include <thread>
12#include <tuple> 14#include <tuple>
@@ -23,7 +25,8 @@
23 25
24namespace InputCommon::SDL { 26namespace InputCommon::SDL {
25 27
26static std::string GetGUID(SDL_Joystick* joystick) { 28namespace {
29std::string GetGUID(SDL_Joystick* joystick) {
27 const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); 30 const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
28 char guid_str[33]; 31 char guid_str[33];
29 SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); 32 SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
@@ -31,7 +34,8 @@ static std::string GetGUID(SDL_Joystick* joystick) {
31} 34}
32 35
33/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice 36/// 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); 37Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event);
38} // Anonymous namespace
35 39
36static int SDLEventWatcher(void* user_data, SDL_Event* event) { 40static int SDLEventWatcher(void* user_data, SDL_Event* event) {
37 auto* const sdl_state = static_cast<SDLState*>(user_data); 41 auto* const sdl_state = static_cast<SDLState*>(user_data);
@@ -48,8 +52,10 @@ static int SDLEventWatcher(void* user_data, SDL_Event* event) {
48 52
49class SDLJoystick { 53class SDLJoystick {
50public: 54public:
51 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick) 55 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
52 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose} {} 56 SDL_GameController* gamecontroller)
57 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
58 sdl_controller{gamecontroller, &SDL_GameControllerClose} {}
53 59
54 void SetButton(int button, bool value) { 60 void SetButton(int button, bool value) {
55 std::lock_guard lock{mutex}; 61 std::lock_guard lock{mutex};
@@ -115,10 +121,15 @@ public:
115 return sdl_joystick.get(); 121 return sdl_joystick.get();
116 } 122 }
117 123
118 void SetSDLJoystick(SDL_Joystick* joystick) { 124 void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
125 sdl_controller.reset(controller);
119 sdl_joystick.reset(joystick); 126 sdl_joystick.reset(joystick);
120 } 127 }
121 128
129 SDL_GameController* GetSDLGameController() const {
130 return sdl_controller.get();
131 }
132
122private: 133private:
123 struct State { 134 struct State {
124 std::unordered_map<int, bool> buttons; 135 std::unordered_map<int, bool> buttons;
@@ -128,6 +139,7 @@ private:
128 std::string guid; 139 std::string guid;
129 int port; 140 int port;
130 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; 141 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
142 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
131 mutable std::mutex mutex; 143 mutable std::mutex mutex;
132}; 144};
133 145
@@ -136,18 +148,19 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& g
136 const auto it = joystick_map.find(guid); 148 const auto it = joystick_map.find(guid);
137 if (it != joystick_map.end()) { 149 if (it != joystick_map.end()) {
138 while (it->second.size() <= static_cast<std::size_t>(port)) { 150 while (it->second.size() <= static_cast<std::size_t>(port)) {
139 auto joystick = 151 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); 152 nullptr, nullptr);
141 it->second.emplace_back(std::move(joystick)); 153 it->second.emplace_back(std::move(joystick));
142 } 154 }
143 return it->second[port]; 155 return it->second[port];
144 } 156 }
145 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr); 157 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
146 return joystick_map[guid].emplace_back(std::move(joystick)); 158 return joystick_map[guid].emplace_back(std::move(joystick));
147} 159}
148 160
149std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { 161std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
150 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); 162 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
163 auto sdl_controller = SDL_GameControllerFromInstanceID(sdl_id);
151 const std::string guid = GetGUID(sdl_joystick); 164 const std::string guid = GetGUID(sdl_joystick);
152 165
153 std::lock_guard lock{joystick_map_mutex}; 166 std::lock_guard lock{joystick_map_mutex};
@@ -171,23 +184,27 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_
171 }); 184 });
172 if (nullptr_it != map_it->second.end()) { 185 if (nullptr_it != map_it->second.end()) {
173 // ... and map it 186 // ... and map it
174 (*nullptr_it)->SetSDLJoystick(sdl_joystick); 187 (*nullptr_it)->SetSDLJoystick(sdl_joystick, sdl_controller);
175 return *nullptr_it; 188 return *nullptr_it;
176 } 189 }
177 190
178 // There is no SDLJoystick without a mapped SDL_Joystick 191 // There is no SDLJoystick without a mapped SDL_Joystick
179 // Create a new SDLJoystick 192 // Create a new SDLJoystick
180 const int port = static_cast<int>(map_it->second.size()); 193 const int port = static_cast<int>(map_it->second.size());
181 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick); 194 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_controller);
182 return map_it->second.emplace_back(std::move(joystick)); 195 return map_it->second.emplace_back(std::move(joystick));
183 } 196 }
184 197
185 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); 198 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_controller);
186 return joystick_map[guid].emplace_back(std::move(joystick)); 199 return joystick_map[guid].emplace_back(std::move(joystick));
187} 200}
188 201
189void SDLState::InitJoystick(int joystick_index) { 202void SDLState::InitJoystick(int joystick_index) {
190 SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index); 203 SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
204 SDL_GameController* sdl_gamecontroller = nullptr;
205 if (SDL_IsGameController(joystick_index)) {
206 sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
207 }
191 if (!sdl_joystick) { 208 if (!sdl_joystick) {
192 LOG_ERROR(Input, "failed to open joystick {}", joystick_index); 209 LOG_ERROR(Input, "failed to open joystick {}", joystick_index);
193 return; 210 return;
@@ -196,7 +213,7 @@ void SDLState::InitJoystick(int joystick_index) {
196 213
197 std::lock_guard lock{joystick_map_mutex}; 214 std::lock_guard lock{joystick_map_mutex};
198 if (joystick_map.find(guid) == joystick_map.end()) { 215 if (joystick_map.find(guid) == joystick_map.end()) {
199 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); 216 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
200 joystick_map[guid].emplace_back(std::move(joystick)); 217 joystick_map[guid].emplace_back(std::move(joystick));
201 return; 218 return;
202 } 219 }
@@ -205,11 +222,11 @@ void SDLState::InitJoystick(int joystick_index) {
205 joystick_guid_list.begin(), joystick_guid_list.end(), 222 joystick_guid_list.begin(), joystick_guid_list.end(),
206 [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); }); 223 [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); });
207 if (it != joystick_guid_list.end()) { 224 if (it != joystick_guid_list.end()) {
208 (*it)->SetSDLJoystick(sdl_joystick); 225 (*it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
209 return; 226 return;
210 } 227 }
211 const int port = static_cast<int>(joystick_guid_list.size()); 228 const int port = static_cast<int>(joystick_guid_list.size());
212 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick); 229 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
213 joystick_guid_list.emplace_back(std::move(joystick)); 230 joystick_guid_list.emplace_back(std::move(joystick));
214} 231}
215 232
@@ -231,7 +248,7 @@ void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
231 248
232 // Destruct SDL_Joystick outside the lock guard because SDL can internally call the 249 // Destruct SDL_Joystick outside the lock guard because SDL can internally call the
233 // event callback which locks the mutex again. 250 // event callback which locks the mutex again.
234 joystick->SetSDLJoystick(nullptr); 251 joystick->SetSDLJoystick(nullptr, nullptr);
235} 252}
236 253
237void SDLState::HandleGameControllerEvent(const SDL_Event& event) { 254void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
@@ -346,7 +363,7 @@ public:
346 363
347 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { 364 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
348 const auto [x, y] = GetStatus(); 365 const auto [x, y] = GetStatus();
349 const float directional_deadzone = 0.4f; 366 const float directional_deadzone = 0.5f;
350 switch (direction) { 367 switch (direction) {
351 case Input::AnalogDirection::RIGHT: 368 case Input::AnalogDirection::RIGHT:
352 return x > directional_deadzone; 369 return x > directional_deadzone;
@@ -460,7 +477,7 @@ public:
460 const int port = params.Get("port", 0); 477 const int port = params.Get("port", 0);
461 const int axis_x = params.Get("axis_x", 0); 478 const int axis_x = params.Get("axis_x", 0);
462 const int axis_y = params.Get("axis_y", 1); 479 const int axis_y = params.Get("axis_y", 1);
463 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); 480 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
464 const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f); 481 const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
465 auto joystick = state.GetSDLJoystickByGUID(guid, port); 482 auto joystick = state.GetSDLJoystickByGUID(guid, port);
466 483
@@ -476,8 +493,10 @@ private:
476 493
477SDLState::SDLState() { 494SDLState::SDLState() {
478 using namespace Input; 495 using namespace Input;
479 RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>(*this)); 496 analog_factory = std::make_shared<SDLAnalogFactory>(*this);
480 RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>(*this)); 497 button_factory = std::make_shared<SDLButtonFactory>(*this);
498 RegisterFactory<AnalogDevice>("sdl", analog_factory);
499 RegisterFactory<ButtonDevice>("sdl", button_factory);
481 500
482 // If the frontend is going to manage the event loop, then we dont start one here 501 // If the frontend is going to manage the event loop, then we dont start one here
483 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK); 502 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK);
@@ -485,6 +504,7 @@ SDLState::SDLState() {
485 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); 504 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
486 return; 505 return;
487 } 506 }
507 has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
488 if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) { 508 if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
489 LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError()); 509 LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
490 } 510 }
@@ -497,7 +517,7 @@ SDLState::SDLState() {
497 using namespace std::chrono_literals; 517 using namespace std::chrono_literals;
498 while (initialized) { 518 while (initialized) {
499 SDL_PumpEvents(); 519 SDL_PumpEvents();
500 std::this_thread::sleep_for(10ms); 520 std::this_thread::sleep_for(5ms);
501 } 521 }
502 }); 522 });
503 } 523 }
@@ -523,65 +543,221 @@ SDLState::~SDLState() {
523 } 543 }
524} 544}
525 545
526static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { 546std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
547 std::scoped_lock lock(joystick_map_mutex);
548 std::vector<Common::ParamPackage> devices;
549 for (const auto& [key, value] : joystick_map) {
550 for (const auto& joystick : value) {
551 auto joy = joystick->GetSDLJoystick();
552 if (auto controller = joystick->GetSDLGameController()) {
553 std::string name =
554 fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
555 devices.emplace_back(Common::ParamPackage{
556 {"class", "sdl"},
557 {"display", std::move(name)},
558 {"guid", joystick->GetGUID()},
559 {"port", std::to_string(joystick->GetPort())},
560 });
561 } else if (joy) {
562 std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort());
563 devices.emplace_back(Common::ParamPackage{
564 {"class", "sdl"},
565 {"display", std::move(name)},
566 {"guid", joystick->GetGUID()},
567 {"port", std::to_string(joystick->GetPort())},
568 });
569 }
570 }
571 }
572 return devices;
573}
574
575namespace {
576Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, u8 axis,
577 float value = 0.1) {
527 Common::ParamPackage params({{"engine", "sdl"}}); 578 Common::ParamPackage params({{"engine", "sdl"}});
579 params.Set("port", port);
580 params.Set("guid", guid);
581 params.Set("axis", axis);
582 if (value > 0) {
583 params.Set("direction", "+");
584 params.Set("threshold", "0.5");
585 } else {
586 params.Set("direction", "-");
587 params.Set("threshold", "-0.5");
588 }
589 return params;
590}
591
592Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, u8 button) {
593 Common::ParamPackage params({{"engine", "sdl"}});
594 params.Set("port", port);
595 params.Set("guid", guid);
596 params.Set("button", button);
597 return params;
598}
528 599
600Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, u8 hat, u8 value) {
601 Common::ParamPackage params({{"engine", "sdl"}});
602
603 params.Set("port", port);
604 params.Set("guid", guid);
605 params.Set("hat", hat);
606 switch (value) {
607 case SDL_HAT_UP:
608 params.Set("direction", "up");
609 break;
610 case SDL_HAT_DOWN:
611 params.Set("direction", "down");
612 break;
613 case SDL_HAT_LEFT:
614 params.Set("direction", "left");
615 break;
616 case SDL_HAT_RIGHT:
617 params.Set("direction", "right");
618 break;
619 default:
620 return {};
621 }
622 return params;
623}
624
625Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
529 switch (event.type) { 626 switch (event.type) {
530 case SDL_JOYAXISMOTION: { 627 case SDL_JOYAXISMOTION: {
531 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 628 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
532 params.Set("port", joystick->GetPort()); 629 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
533 params.Set("guid", joystick->GetGUID()); 630 event.jaxis.axis, event.jaxis.value);
534 params.Set("axis", event.jaxis.axis);
535 if (event.jaxis.value > 0) {
536 params.Set("direction", "+");
537 params.Set("threshold", "0.5");
538 } else {
539 params.Set("direction", "-");
540 params.Set("threshold", "-0.5");
541 }
542 break;
543 } 631 }
544 case SDL_JOYBUTTONUP: { 632 case SDL_JOYBUTTONUP: {
545 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); 633 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
546 params.Set("port", joystick->GetPort()); 634 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
547 params.Set("guid", joystick->GetGUID()); 635 event.jbutton.button);
548 params.Set("button", event.jbutton.button);
549 break;
550 } 636 }
551 case SDL_JOYHATMOTION: { 637 case SDL_JOYHATMOTION: {
552 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); 638 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
553 params.Set("port", joystick->GetPort()); 639 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
554 params.Set("guid", joystick->GetGUID()); 640 event.jhat.hat, event.jhat.value);
555 params.Set("hat", event.jhat.hat);
556 switch (event.jhat.value) {
557 case SDL_HAT_UP:
558 params.Set("direction", "up");
559 break;
560 case SDL_HAT_DOWN:
561 params.Set("direction", "down");
562 break;
563 case SDL_HAT_LEFT:
564 params.Set("direction", "left");
565 break;
566 case SDL_HAT_RIGHT:
567 params.Set("direction", "right");
568 break;
569 default:
570 return {};
571 }
572 break;
573 } 641 }
574 } 642 }
643 return {};
644}
645
646Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
647 const SDL_GameControllerButtonBind& binding) {
648 switch (binding.bindType) {
649 case SDL_CONTROLLER_BINDTYPE_AXIS:
650 return BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
651 case SDL_CONTROLLER_BINDTYPE_BUTTON:
652 return BuildButtonParamPackageForButton(port, guid, binding.value.button);
653 case SDL_CONTROLLER_BINDTYPE_HAT:
654 return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat,
655 binding.value.hat.hat_mask);
656 }
657 return {};
658}
659
660Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x,
661 int axis_y) {
662 Common::ParamPackage params;
663 params.Set("engine", "sdl");
664 params.Set("port", port);
665 params.Set("guid", guid);
666 params.Set("axis_x", axis_x);
667 params.Set("axis_y", axis_y);
575 return params; 668 return params;
576} 669}
670} // Anonymous namespace
671
672ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) {
673 // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
674 // We will add those afterwards
675 // This list also excludes Screenshot since theres not really a mapping for that
676 std::unordered_map<Settings::NativeButton::Values, SDL_GameControllerButton>
677 switch_to_sdl_button = {
678 {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
679 {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
680 {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
681 {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
682 {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
683 {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
684 {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
685 {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
686 {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
687 {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
688 {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
689 {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
690 {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
691 {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
692 {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
693 {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
694 {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
695 };
696 if (!params.Has("guid") || !params.Has("port")) {
697 return {};
698 }
699 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
700 auto controller = joystick->GetSDLGameController();
701 if (!controller) {
702 return {};
703 }
577 704
578namespace Polling { 705 ButtonMapping mapping{};
706 for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
707 const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
708 mapping[switch_button] =
709 BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding);
710 }
711
712 // Add the missing bindings for ZL/ZR
713 std::unordered_map<Settings::NativeButton::Values, SDL_GameControllerAxis> switch_to_sdl_axis =
714 {
715 {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
716 {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
717 };
718 for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
719 const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
720 mapping[switch_button] =
721 BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding);
722 }
723
724 return mapping;
725}
726
727AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
728 if (!params.Has("guid") || !params.Has("port")) {
729 return {};
730 }
731 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
732 auto controller = joystick->GetSDLGameController();
733 if (!controller) {
734 return {};
735 }
736
737 AnalogMapping mapping = {};
738 const auto& binding_left_x =
739 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
740 const auto& binding_left_y =
741 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
742 mapping[Settings::NativeAnalog::LStick] =
743 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
744 binding_left_x.value.axis, binding_left_y.value.axis);
745 const auto& binding_right_x =
746 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
747 const auto& binding_right_y =
748 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
749 mapping[Settings::NativeAnalog::RStick] =
750 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
751 binding_right_x.value.axis, binding_right_y.value.axis);
752 return mapping;
753}
579 754
755namespace Polling {
580class SDLPoller : public InputCommon::Polling::DevicePoller { 756class SDLPoller : public InputCommon::Polling::DevicePoller {
581public: 757public:
582 explicit SDLPoller(SDLState& state_) : state(state_) {} 758 explicit SDLPoller(SDLState& state_) : state(state_) {}
583 759
584 void Start() override { 760 void Start(const std::string& device_id) override {
585 state.event_queue.Clear(); 761 state.event_queue.Clear();
586 state.polling = true; 762 state.polling = true;
587 } 763 }
@@ -601,71 +777,106 @@ public:
601 Common::ParamPackage GetNextInput() override { 777 Common::ParamPackage GetNextInput() override {
602 SDL_Event event; 778 SDL_Event event;
603 while (state.event_queue.Pop(event)) { 779 while (state.event_queue.Pop(event)) {
604 switch (event.type) { 780 const auto package = FromEvent(event);
605 case SDL_JOYAXISMOTION: 781 if (package) {
606 if (std::abs(event.jaxis.value / 32767.0) < 0.5) { 782 return *package;
607 break; 783 }
608 } 784 }
609 [[fallthrough]]; 785 return {};
610 case SDL_JOYBUTTONUP: 786 }
611 case SDL_JOYHATMOTION: 787 std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) {
612 return SDLEventToButtonParamPackage(state, event); 788 switch (event.type) {
789 case SDL_JOYAXISMOTION:
790 if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
791 break;
613 } 792 }
793 [[fallthrough]];
794 case SDL_JOYBUTTONUP:
795 case SDL_JOYHATMOTION:
796 return {SDLEventToButtonParamPackage(state, event)};
614 } 797 }
615 return {}; 798 return {};
616 } 799 }
617}; 800};
618 801
619class SDLAnalogPoller final : public SDLPoller { 802/**
803 * Attempts to match the press to a controller joy axis (left/right stick) and if a match
804 * isn't found, checks if the event matches anything from SDLButtonPoller and uses that
805 * instead
806 */
807class SDLAnalogPreferredPoller final : public SDLPoller {
620public: 808public:
621 explicit SDLAnalogPoller(SDLState& state_) : SDLPoller(state_) {} 809 explicit SDLAnalogPreferredPoller(SDLState& state_)
622 810 : SDLPoller(state_), button_poller(state_) {}
623 void Start() override {
624 SDLPoller::Start();
625 811
812 void Start(const std::string& device_id) override {
813 SDLPoller::Start(device_id);
814 // Load the game controller
626 // Reset stored axes 815 // Reset stored axes
627 analog_x_axis = -1; 816 analog_x_axis = -1;
628 analog_y_axis = -1; 817 analog_y_axis = -1;
629 analog_axes_joystick = -1;
630 } 818 }
631 819
632 Common::ParamPackage GetNextInput() override { 820 Common::ParamPackage GetNextInput() override {
633 SDL_Event event; 821 SDL_Event event;
634 while (state.event_queue.Pop(event)) { 822 while (state.event_queue.Pop(event)) {
635 if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) { 823 // Filter out axis events that are below a threshold
824 if (event.type == SDL_JOYAXISMOTION && std::abs(event.jaxis.value / 32767.0) < 0.5) {
636 continue; 825 continue;
637 } 826 }
638 // An analog device needs two axes, so we need to store the axis for later and wait for 827 // Simplify controller config by testing if game controller support is enabled.
639 // a second SDL event. The axes also must be from the same joystick. 828 if (event.type == SDL_JOYAXISMOTION) {
640 const int axis = event.jaxis.axis; 829 const auto axis = event.jaxis.axis;
641 if (analog_x_axis == -1) { 830 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
642 analog_x_axis = axis; 831 const auto controller = joystick->GetSDLGameController();
643 analog_axes_joystick = event.jaxis.which; 832 if (controller) {
644 } else if (analog_y_axis == -1 && analog_x_axis != axis && 833 const auto axis_left_x =
645 analog_axes_joystick == event.jaxis.which) { 834 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)
646 analog_y_axis = axis; 835 .value.axis;
836 const auto axis_left_y =
837 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY)
838 .value.axis;
839 const auto axis_right_x =
840 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX)
841 .value.axis;
842 const auto axis_right_y =
843 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY)
844 .value.axis;
845
846 if (axis == axis_left_x || axis == axis_left_y) {
847 analog_x_axis = axis_left_x;
848 analog_y_axis = axis_left_y;
849 break;
850 } else if (axis == axis_right_x || axis == axis_right_y) {
851 analog_x_axis = axis_right_x;
852 analog_y_axis = axis_right_y;
853 break;
854 }
855 }
856 }
857
858 // If the press wasn't accepted as a joy axis, check for a button press
859 auto button_press = button_poller.FromEvent(event);
860 if (button_press) {
861 return *button_press;
647 } 862 }
648 } 863 }
649 Common::ParamPackage params; 864
650 if (analog_x_axis != -1 && analog_y_axis != -1) { 865 if (analog_x_axis != -1 && analog_y_axis != -1) {
651 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 866 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
652 params.Set("engine", "sdl"); 867 auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
653 params.Set("port", joystick->GetPort()); 868 analog_x_axis, analog_y_axis);
654 params.Set("guid", joystick->GetGUID());
655 params.Set("axis_x", analog_x_axis);
656 params.Set("axis_y", analog_y_axis);
657 analog_x_axis = -1; 869 analog_x_axis = -1;
658 analog_y_axis = -1; 870 analog_y_axis = -1;
659 analog_axes_joystick = -1;
660 return params; 871 return params;
661 } 872 }
662 return params; 873 return {};
663 } 874 }
664 875
665private: 876private:
666 int analog_x_axis = -1; 877 int analog_x_axis = -1;
667 int analog_y_axis = -1; 878 int analog_y_axis = -1;
668 SDL_JoystickID analog_axes_joystick = -1; 879 SDLButtonPoller button_poller;
669}; 880};
670} // namespace Polling 881} // namespace Polling
671 882
@@ -673,8 +884,8 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
673 Pollers pollers; 884 Pollers pollers;
674 885
675 switch (type) { 886 switch (type) {
676 case InputCommon::Polling::DeviceType::Analog: 887 case InputCommon::Polling::DeviceType::AnalogPreferred:
677 pollers.emplace_back(std::make_unique<Polling::SDLAnalogPoller>(*this)); 888 pollers.emplace_back(std::make_unique<Polling::SDLAnalogPreferredPoller>(*this));
678 break; 889 break;
679 case InputCommon::Polling::DeviceType::Button: 890 case InputCommon::Polling::DeviceType::Button:
680 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this)); 891 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..8e481a7fe
--- /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 {
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 {
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/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();