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.cpp2
-rw-r--r--src/input_common/main.cpp50
-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.cpp403
-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.cpp15
-rw-r--r--src/input_common/udp/udp.h7
11 files changed, 798 insertions, 102 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..85342bbe7 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -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..b8725e9af 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,55 @@ 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"}, {"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 mappings;
124 }
125 if (params.Get("class", "") == "key") {
126 // TODO consider returning the SDL key codes for the default keybindings
127 }
128#ifdef HAVE_SDL2
129 if (params.Get("class", "") == "sdl") {
130 return sdl->GetButtonMappingForDevice(params);
131 }
132#endif
133 return mappings;
134}
135
136std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage> GetAnalogMappingForDevice(
137 const Common::ParamPackage& params) {
138 std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage> mappings{};
139 if (!params.Has("class") || params.Get("class", "") == "any") {
140 return mappings;
141 }
142 if (params.Get("class", "") == "key") {
143 // TODO consider returning the SDL key codes for the default keybindings
144 return mappings;
145 }
146#ifdef HAVE_SDL2
147 if (params.Get("class", "") == "sdl") {
148 return sdl->GetAnalogMappingForDevice(params);
149 }
150#endif
151 return mappings;
152}
153
106namespace Polling { 154namespace Polling {
107 155
108std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) { 156std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) {
diff --git a/src/input_common/main.h b/src/input_common/main.h
index 0e32856f6..ebc7f9533 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(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..35a9d45ec 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) {
@@ -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,233 @@ 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 controller = joystick->GetSDLGameController();
552 auto joy = joystick->GetSDLJoystick();
553 if (controller) {
554 std::string name =
555 fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
556 devices.emplace_back(Common::ParamPackage{
557 {"class", "sdl"},
558 {"display", 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", 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.1) {
579 Common::ParamPackage params({{"engine", "sdl"}});
580 params.Set("port", port);
581 params.Set("guid", 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) {
594 Common::ParamPackage params({{"engine", "sdl"}});
595 params.Set("port", port);
596 params.Set("guid", guid);
597 params.Set("button", button);
598 return params;
599}
600
601Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, u8 hat, u8 value) {
527 Common::ParamPackage params({{"engine", "sdl"}}); 602 Common::ParamPackage params({{"engine", "sdl"}});
528 603
604 params.Set("port", port);
605 params.Set("guid", 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}
625
626Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
627 Common::ParamPackage params{};
628
529 switch (event.type) { 629 switch (event.type) {
530 case SDL_JOYAXISMOTION: { 630 case SDL_JOYAXISMOTION: {
531 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 631 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
532 params.Set("port", joystick->GetPort()); 632 params = BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
533 params.Set("guid", joystick->GetGUID()); 633 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; 634 break;
543 } 635 }
544 case SDL_JOYBUTTONUP: { 636 case SDL_JOYBUTTONUP: {
545 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); 637 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
546 params.Set("port", joystick->GetPort()); 638 params = BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
547 params.Set("guid", joystick->GetGUID()); 639 event.jbutton.button);
548 params.Set("button", event.jbutton.button);
549 break; 640 break;
550 } 641 }
551 case SDL_JOYHATMOTION: { 642 case SDL_JOYHATMOTION: {
552 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); 643 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
553 params.Set("port", joystick->GetPort()); 644 params = BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
554 params.Set("guid", joystick->GetGUID()); 645 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; 646 break;
573 } 647 }
574 } 648 }
575 return params; 649 return params;
576} 650}
577 651
578namespace Polling { 652Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
653 const SDL_GameControllerButtonBind& binding) {
654 Common::ParamPackage out{};
655 switch (binding.bindType) {
656 case SDL_CONTROLLER_BINDTYPE_AXIS:
657 out = BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
658 break;
659 case SDL_CONTROLLER_BINDTYPE_BUTTON:
660 out = BuildButtonParamPackageForButton(port, guid, binding.value.button);
661 break;
662 case SDL_CONTROLLER_BINDTYPE_HAT:
663 out = BuildHatParamPackageForButton(port, guid, binding.value.hat.hat,
664 binding.value.hat.hat_mask);
665 break;
666 default:
667 break;
668 }
669 return out;
670};
671
672Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x,
673 int axis_y) {
674 Common::ParamPackage params{};
675 params.Set("engine", "sdl");
676 params.Set("port", port);
677 params.Set("guid", guid);
678 params.Set("axis_x", axis_x);
679 params.Set("axis_y", axis_y);
680 return params;
681}
682} // Anonymous namespace
683
684ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) {
685 // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
686 // We will add those afterwards
687 // This list also excludes Screenshot since theres not really a mapping for that
688 std::unordered_map<Settings::NativeButton::Values, SDL_GameControllerButton>
689 switch_to_sdl_button = {
690 {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
691 {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
692 {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
693 {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
694 {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
695 {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
696 {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
697 {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
698 {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
699 {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
700 {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
701 {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
702 {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
703 {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
704 {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
705 {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
706 {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
707 };
708 if (!params.Has("guid") || !params.Has("port")) {
709 return {};
710 }
711 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
712 auto controller = joystick->GetSDLGameController();
713 if (!controller) {
714 return {};
715 }
716
717 ButtonMapping mapping{};
718 for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
719 const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
720 mapping[switch_button] =
721 BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding);
722 }
723
724 // Add the missing bindings for ZL/ZR
725 std::unordered_map<Settings::NativeButton::Values, SDL_GameControllerAxis> switch_to_sdl_axis =
726 {
727 {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
728 {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
729 };
730 for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
731 const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
732 mapping[switch_button] =
733 BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding);
734 }
735
736 return mapping;
737}
738
739AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
740 if (!params.Has("guid") || !params.Has("port")) {
741 return {};
742 }
743 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
744 auto controller = joystick->GetSDLGameController();
745 if (!controller) {
746 return {};
747 }
748
749 AnalogMapping mapping = {};
750 const auto& binding_left_x =
751 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
752 const auto& binding_left_y =
753 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
754 mapping[Settings::NativeAnalog::LStick] =
755 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
756 binding_left_x.value.axis, binding_left_y.value.axis);
757 const auto& binding_right_x =
758 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
759 const auto& binding_right_y =
760 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
761 mapping[Settings::NativeAnalog::RStick] =
762 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
763 binding_right_x.value.axis, binding_right_y.value.axis);
764 return mapping;
765}
579 766
767namespace Polling {
580class SDLPoller : public InputCommon::Polling::DevicePoller { 768class SDLPoller : public InputCommon::Polling::DevicePoller {
581public: 769public:
582 explicit SDLPoller(SDLState& state_) : state(state_) {} 770 explicit SDLPoller(SDLState& state_) : state(state_) {}
583 771
584 void Start() override { 772 void Start(std::string device_id) override {
585 state.event_queue.Clear(); 773 state.event_queue.Clear();
586 state.polling = true; 774 state.polling = true;
587 } 775 }
@@ -601,71 +789,106 @@ public:
601 Common::ParamPackage GetNextInput() override { 789 Common::ParamPackage GetNextInput() override {
602 SDL_Event event; 790 SDL_Event event;
603 while (state.event_queue.Pop(event)) { 791 while (state.event_queue.Pop(event)) {
604 switch (event.type) { 792 const auto package = FromEvent(event);
605 case SDL_JOYAXISMOTION: 793 if (package) {
606 if (std::abs(event.jaxis.value / 32767.0) < 0.5) { 794 return *package;
607 break;
608 }
609 [[fallthrough]];
610 case SDL_JOYBUTTONUP:
611 case SDL_JOYHATMOTION:
612 return SDLEventToButtonParamPackage(state, event);
613 } 795 }
614 } 796 }
615 return {}; 797 return {};
616 } 798 }
799 std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) {
800 switch (event.type) {
801 case SDL_JOYAXISMOTION:
802 if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
803 break;
804 }
805 [[fallthrough]];
806 case SDL_JOYBUTTONUP:
807 case SDL_JOYHATMOTION:
808 return {SDLEventToButtonParamPackage(state, event)};
809 }
810 return {};
811 }
617}; 812};
618 813
619class SDLAnalogPoller final : public SDLPoller { 814/**
815 * Attempts to match the press to a controller joy axis (left/right stick) and if a match
816 * isn't found, checks if the event matches anything from SDLButtonPoller and uses that
817 * instead
818 */
819class SDLAnalogPreferredPoller final : public SDLPoller {
620public: 820public:
621 explicit SDLAnalogPoller(SDLState& state_) : SDLPoller(state_) {} 821 explicit SDLAnalogPreferredPoller(SDLState& state_)
622 822 : SDLPoller(state_), button_poller(state_) {}
623 void Start() override {
624 SDLPoller::Start();
625 823
824 void Start(std::string device_id) override {
825 SDLPoller::Start(device_id);
826 // Load the game controller
626 // Reset stored axes 827 // Reset stored axes
627 analog_x_axis = -1; 828 analog_x_axis = -1;
628 analog_y_axis = -1; 829 analog_y_axis = -1;
629 analog_axes_joystick = -1;
630 } 830 }
631 831
632 Common::ParamPackage GetNextInput() override { 832 Common::ParamPackage GetNextInput() override {
633 SDL_Event event; 833 SDL_Event event;
634 while (state.event_queue.Pop(event)) { 834 while (state.event_queue.Pop(event)) {
635 if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) { 835 // Filter out axis events that are below a threshold
836 if (event.type == SDL_JOYAXISMOTION && std::abs(event.jaxis.value / 32767.0) < 0.5) {
636 continue; 837 continue;
637 } 838 }
638 // An analog device needs two axes, so we need to store the axis for later and wait for 839 // 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. 840 if (event.type == SDL_JOYAXISMOTION) {
640 const int axis = event.jaxis.axis; 841 const auto axis = event.jaxis.axis;
641 if (analog_x_axis == -1) { 842 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
642 analog_x_axis = axis; 843 const auto controller = joystick->GetSDLGameController();
643 analog_axes_joystick = event.jaxis.which; 844 if (controller) {
644 } else if (analog_y_axis == -1 && analog_x_axis != axis && 845 const auto axis_left_x =
645 analog_axes_joystick == event.jaxis.which) { 846 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)
646 analog_y_axis = axis; 847 .value.axis;
848 const auto axis_left_y =
849 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY)
850 .value.axis;
851 const auto axis_right_x =
852 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX)
853 .value.axis;
854 const auto axis_right_y =
855 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY)
856 .value.axis;
857
858 if (axis == axis_left_x || axis == axis_left_y) {
859 analog_x_axis = axis_left_x;
860 analog_y_axis = axis_left_y;
861 break;
862 } else if (axis == axis_right_x || axis == axis_right_y) {
863 analog_x_axis = axis_right_x;
864 analog_y_axis = axis_right_y;
865 break;
866 }
867 }
868 }
869
870 // If the press wasn't accepted as a joy axis, check for a button press
871 auto button_press = button_poller.FromEvent(event);
872 if (button_press) {
873 return *button_press;
647 } 874 }
648 } 875 }
649 Common::ParamPackage params; 876
650 if (analog_x_axis != -1 && analog_y_axis != -1) { 877 if (analog_x_axis != -1 && analog_y_axis != -1) {
651 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 878 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
652 params.Set("engine", "sdl"); 879 auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
653 params.Set("port", joystick->GetPort()); 880 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; 881 analog_x_axis = -1;
658 analog_y_axis = -1; 882 analog_y_axis = -1;
659 analog_axes_joystick = -1;
660 return params; 883 return params;
661 } 884 }
662 return params; 885 return {};
663 } 886 }
664 887
665private: 888private:
666 int analog_x_axis = -1; 889 int analog_x_axis = -1;
667 int analog_y_axis = -1; 890 int analog_y_axis = -1;
668 SDL_JoystickID analog_axes_joystick = -1; 891 SDLButtonPoller button_poller;
669}; 892};
670} // namespace Polling 893} // namespace Polling
671 894
@@ -673,8 +896,8 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
673 Pollers pollers; 896 Pollers pollers;
674 897
675 switch (type) { 898 switch (type) {
676 case InputCommon::Polling::DeviceType::Analog: 899 case InputCommon::Polling::DeviceType::AnalogPreferred:
677 pollers.emplace_back(std::make_unique<Polling::SDLAnalogPoller>(*this)); 900 pollers.emplace_back(std::make_unique<Polling::SDLAnalogPreferredPoller>(*this));
678 break; 901 break;
679 case InputCommon::Polling::DeviceType::Button: 902 case InputCommon::Polling::DeviceType::Button:
680 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this)); 903 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..60cf47123 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,12 @@ State::~State() {
88 Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp"); 89 Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp");
89} 90}
90 91
92std::vector<Common::ParamPackage> State::GetInputDevices() {
93 std::vector<Common::ParamPackage> devices = {};
94 // TODO support binding udp devices
95 return devices;
96}
97
91void State::ReloadUDPClient() { 98void State::ReloadUDPClient() {
92 client->ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port, 99 client->ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port,
93 Settings::values.udp_pad_index); 100 Settings::values.udp_pad_index);
diff --git a/src/input_common/udp/udp.h b/src/input_common/udp/udp.h
index 4f83f0441..24f6e0857 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();
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();