summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Narr the Reg2021-11-26 15:45:37 -0600
committerGravatar Narr the Reg2021-11-26 15:46:36 -0600
commit639402850ac65c694967ef6519becb65abe89b39 (patch)
tree55ab559c417a519ac8b93a746428842e53c19a31 /src
parentservice/hid: Finish converting LIFO objects and address some nits (diff)
downloadyuzu-639402850ac65c694967ef6519becb65abe89b39.tar.gz
yuzu-639402850ac65c694967ef6519becb65abe89b39.tar.xz
yuzu-639402850ac65c694967ef6519becb65abe89b39.zip
input_common: Fully implement UDP controllers
Diffstat (limited to '')
-rw-r--r--src/common/input.h14
-rw-r--r--src/common/settings.h1
-rw-r--r--src/core/hid/emulated_console.cpp6
-rw-r--r--src/input_common/drivers/udp_client.cpp206
-rw-r--r--src/input_common/drivers/udp_client.h56
-rw-r--r--src/input_common/helpers/udp_protocol.h75
-rw-r--r--src/input_common/input_mapping.cpp6
-rw-r--r--src/input_common/main.cpp26
-rw-r--r--src/yuzu/configuration/config.cpp2
-rw-r--r--src/yuzu/configuration/configure_input_advanced.cpp2
-rw-r--r--src/yuzu/configuration/configure_input_advanced.ui19
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp24
12 files changed, 397 insertions, 40 deletions
diff --git a/src/common/input.h b/src/common/input.h
index cc0cbd9b8..eaee0bdea 100644
--- a/src/common/input.h
+++ b/src/common/input.h
@@ -195,6 +195,20 @@ enum class ButtonNames {
195 ButtonX, 195 ButtonX,
196 ButtonY, 196 ButtonY,
197 ButtonStart, 197 ButtonStart,
198
199 // DS4 button names
200 L1,
201 L2,
202 L3,
203 R1,
204 R2,
205 R3,
206 Circle,
207 Cross,
208 Square,
209 Triangle,
210 Share,
211 Options,
198}; 212};
199 213
200// Callback data consisting of an input type and the equivalent data status 214// Callback data consisting of an input type and the equivalent data status
diff --git a/src/common/settings.h b/src/common/settings.h
index d7410fa9b..e4e049f67 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -560,6 +560,7 @@ struct Values {
560 560
561 Setting<bool> motion_enabled{true, "motion_enabled"}; 561 Setting<bool> motion_enabled{true, "motion_enabled"};
562 BasicSetting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"}; 562 BasicSetting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"};
563 BasicSetting<bool> enable_udp_controller{false, "enable_udp_controller"};
563 564
564 BasicSetting<bool> pause_tas_on_load{true, "pause_tas_on_load"}; 565 BasicSetting<bool> pause_tas_on_load{true, "pause_tas_on_load"};
565 BasicSetting<bool> tas_enable{false, "tas_enable"}; 566 BasicSetting<bool> tas_enable{false, "tas_enable"};
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp
index b224932dc..80db8e9c6 100644
--- a/src/core/hid/emulated_console.cpp
+++ b/src/core/hid/emulated_console.cpp
@@ -30,8 +30,10 @@ void EmulatedConsole::SetTouchParams() {
30 } 30 }
31 touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"}; 31 touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"};
32 touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"}; 32 touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"};
33 touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:0,axis_y:1,button:0"}; 33 touch_params[index++] =
34 touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:2,axis_y:3,button:1"}; 34 Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"};
35 touch_params[index++] =
36 Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"};
35 37
36 const auto button_index = 38 const auto button_index =
37 static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue()); 39 static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp
index 7cab707da..fdee0f2d5 100644
--- a/src/input_common/drivers/udp_client.cpp
+++ b/src/input_common/drivers/udp_client.cpp
@@ -103,7 +103,7 @@ private:
103 103
104 // Send a request for getting pad data for the pad 104 // Send a request for getting pad data for the pad
105 const Request::PadData pad_data{ 105 const Request::PadData pad_data{
106 Request::PadData::Flags::AllPorts, 106 Request::RegisterFlags::AllPads,
107 0, 107 0,
108 EMPTY_MAC_ADDRESS, 108 EMPTY_MAC_ADDRESS,
109 }; 109 };
@@ -247,7 +247,12 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) {
247 247
248 for (std::size_t id = 0; id < data.touch.size(); ++id) { 248 for (std::size_t id = 0; id < data.touch.size(); ++id) {
249 const auto touch_pad = data.touch[id]; 249 const auto touch_pad = data.touch[id];
250 const int touch_id = static_cast<int>(client * 2 + id); 250 const auto touch_axis_x_id =
251 static_cast<int>(id == 0 ? PadAxes::Touch1X : PadAxes::Touch2X);
252 const auto touch_axis_y_id =
253 static_cast<int>(id == 0 ? PadAxes::Touch1Y : PadAxes::Touch2Y);
254 const auto touch_button_id =
255 static_cast<int>(id == 0 ? PadButton::Touch1 : PadButton::touch2);
251 256
252 // TODO: Use custom calibration per device 257 // TODO: Use custom calibration per device
253 const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue()); 258 const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
@@ -264,14 +269,35 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) {
264 static_cast<f32>(max_y - min_y); 269 static_cast<f32>(max_y - min_y);
265 270
266 if (touch_pad.is_active) { 271 if (touch_pad.is_active) {
267 SetAxis(identifier, touch_id * 2, x); 272 SetAxis(identifier, touch_axis_x_id, x);
268 SetAxis(identifier, touch_id * 2 + 1, y); 273 SetAxis(identifier, touch_axis_y_id, y);
269 SetButton(identifier, touch_id, true); 274 SetButton(identifier, touch_button_id, true);
270 continue; 275 continue;
271 } 276 }
272 SetAxis(identifier, touch_id * 2, 0); 277 SetAxis(identifier, touch_axis_x_id, 0);
273 SetAxis(identifier, touch_id * 2 + 1, 0); 278 SetAxis(identifier, touch_axis_y_id, 0);
274 SetButton(identifier, touch_id, false); 279 SetButton(identifier, touch_button_id, false);
280 }
281
282 SetAxis(identifier, static_cast<int>(PadAxes::LeftStickX),
283 (data.left_stick_x - 127.0f) / 127.0f);
284 SetAxis(identifier, static_cast<int>(PadAxes::LeftStickY),
285 (data.left_stick_y - 127.0f) / 127.0f);
286 SetAxis(identifier, static_cast<int>(PadAxes::RightStickX),
287 (data.right_stick_x - 127.0f) / 127.0f);
288 SetAxis(identifier, static_cast<int>(PadAxes::RightStickY),
289 (data.right_stick_y - 127.0f) / 127.0f);
290
291 static constexpr std::array<PadButton, 16> buttons{
292 PadButton::Share, PadButton::L3, PadButton::R3, PadButton::Options,
293 PadButton::Up, PadButton::Right, PadButton::Down, PadButton::Left,
294 PadButton::L2, PadButton::R2, PadButton::L1, PadButton::R1,
295 PadButton::Triangle, PadButton::Circle, PadButton::Cross, PadButton::Square};
296
297 for (std::size_t i = 0; i < buttons.size(); ++i) {
298 const bool button_status = (data.digital_button & (1U << i)) != 0;
299 const int button = static_cast<int>(buttons[i]);
300 SetButton(identifier, button, button_status);
275 } 301 }
276} 302}
277 303
@@ -317,6 +343,170 @@ void UDPClient::Reset() {
317 } 343 }
318} 344}
319 345
346std::vector<Common::ParamPackage> UDPClient::GetInputDevices() const {
347 std::vector<Common::ParamPackage> devices;
348 if (!Settings::values.enable_udp_controller) {
349 return devices;
350 }
351 for (std::size_t client = 0; client < clients.size(); client++) {
352 if (clients[client].active != 1) {
353 continue;
354 }
355 for (std::size_t index = 0; index < PADS_PER_CLIENT; ++index) {
356 const std::size_t pad_index = client * PADS_PER_CLIENT + index;
357 if (!pads[pad_index].connected) {
358 continue;
359 }
360 const auto pad_identifier = GetPadIdentifier(pad_index);
361 Common::ParamPackage identifier{};
362 identifier.Set("engine", GetEngineName());
363 identifier.Set("display", fmt::format("UDP Controller {}", pad_identifier.pad));
364 identifier.Set("guid", pad_identifier.guid.Format());
365 identifier.Set("port", static_cast<int>(pad_identifier.port));
366 identifier.Set("pad", static_cast<int>(pad_identifier.pad));
367 devices.emplace_back(identifier);
368 }
369 }
370 return devices;
371}
372
373ButtonMapping UDPClient::GetButtonMappingForDevice(const Common::ParamPackage& params) {
374 // This list excludes any button that can't be really mapped
375 static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 18>
376 switch_to_dsu_button = {
377 std::pair{Settings::NativeButton::A, PadButton::Circle},
378 {Settings::NativeButton::B, PadButton::Cross},
379 {Settings::NativeButton::X, PadButton::Triangle},
380 {Settings::NativeButton::Y, PadButton::Square},
381 {Settings::NativeButton::Plus, PadButton::Options},
382 {Settings::NativeButton::Minus, PadButton::Share},
383 {Settings::NativeButton::DLeft, PadButton::Left},
384 {Settings::NativeButton::DUp, PadButton::Up},
385 {Settings::NativeButton::DRight, PadButton::Right},
386 {Settings::NativeButton::DDown, PadButton::Down},
387 {Settings::NativeButton::L, PadButton::L1},
388 {Settings::NativeButton::R, PadButton::R1},
389 {Settings::NativeButton::ZL, PadButton::L2},
390 {Settings::NativeButton::ZR, PadButton::R2},
391 {Settings::NativeButton::SL, PadButton::L2},
392 {Settings::NativeButton::SR, PadButton::R2},
393 {Settings::NativeButton::LStick, PadButton::L3},
394 {Settings::NativeButton::RStick, PadButton::R3},
395 };
396 if (!params.Has("guid") || !params.Has("port") || !params.Has("pad")) {
397 return {};
398 }
399
400 ButtonMapping mapping{};
401 for (const auto& [switch_button, dsu_button] : switch_to_dsu_button) {
402 Common::ParamPackage button_params{};
403 button_params.Set("engine", GetEngineName());
404 button_params.Set("guid", params.Get("guid", ""));
405 button_params.Set("port", params.Get("port", 0));
406 button_params.Set("pad", params.Get("pad", 0));
407 button_params.Set("button", static_cast<int>(dsu_button));
408 mapping.insert_or_assign(switch_button, std::move(button_params));
409 }
410
411 return mapping;
412}
413
414AnalogMapping UDPClient::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
415 if (!params.Has("guid") || !params.Has("port") || !params.Has("pad")) {
416 return {};
417 }
418
419 AnalogMapping mapping = {};
420 Common::ParamPackage left_analog_params;
421 left_analog_params.Set("engine", GetEngineName());
422 left_analog_params.Set("guid", params.Get("guid", ""));
423 left_analog_params.Set("port", params.Get("port", 0));
424 left_analog_params.Set("pad", params.Get("pad", 0));
425 left_analog_params.Set("axis_x", static_cast<int>(PadAxes::LeftStickX));
426 left_analog_params.Set("axis_y", static_cast<int>(PadAxes::LeftStickY));
427 mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params));
428 Common::ParamPackage right_analog_params;
429 right_analog_params.Set("engine", GetEngineName());
430 right_analog_params.Set("guid", params.Get("guid", ""));
431 right_analog_params.Set("port", params.Get("port", 0));
432 right_analog_params.Set("pad", params.Get("pad", 0));
433 right_analog_params.Set("axis_x", static_cast<int>(PadAxes::RightStickX));
434 right_analog_params.Set("axis_y", static_cast<int>(PadAxes::RightStickY));
435 mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params));
436 return mapping;
437}
438
439MotionMapping UDPClient::GetMotionMappingForDevice(const Common::ParamPackage& params) {
440 if (!params.Has("guid") || !params.Has("port") || !params.Has("pad")) {
441 return {};
442 }
443
444 MotionMapping mapping = {};
445 Common::ParamPackage motion_params;
446 motion_params.Set("engine", GetEngineName());
447 motion_params.Set("guid", params.Get("guid", ""));
448 motion_params.Set("port", params.Get("port", 0));
449 motion_params.Set("pad", params.Get("pad", 0));
450 motion_params.Set("motion", 0);
451 mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, std::move(motion_params));
452 mapping.insert_or_assign(Settings::NativeMotion::MotionRight, std::move(motion_params));
453 return mapping;
454}
455
456Common::Input::ButtonNames UDPClient::GetUIButtonName(const Common::ParamPackage& params) const {
457 PadButton button = static_cast<PadButton>(params.Get("button", 0));
458 switch (button) {
459 case PadButton::Left:
460 return Common::Input::ButtonNames::ButtonLeft;
461 case PadButton::Right:
462 return Common::Input::ButtonNames::ButtonRight;
463 case PadButton::Down:
464 return Common::Input::ButtonNames::ButtonDown;
465 case PadButton::Up:
466 return Common::Input::ButtonNames::ButtonUp;
467 case PadButton::L1:
468 return Common::Input::ButtonNames::L1;
469 case PadButton::L2:
470 return Common::Input::ButtonNames::L2;
471 case PadButton::L3:
472 return Common::Input::ButtonNames::L3;
473 case PadButton::R1:
474 return Common::Input::ButtonNames::R1;
475 case PadButton::R2:
476 return Common::Input::ButtonNames::R2;
477 case PadButton::R3:
478 return Common::Input::ButtonNames::R3;
479 case PadButton::Circle:
480 return Common::Input::ButtonNames::Circle;
481 case PadButton::Cross:
482 return Common::Input::ButtonNames::Cross;
483 case PadButton::Square:
484 return Common::Input::ButtonNames::Square;
485 case PadButton::Triangle:
486 return Common::Input::ButtonNames::Triangle;
487 case PadButton::Share:
488 return Common::Input::ButtonNames::Share;
489 case PadButton::Options:
490 return Common::Input::ButtonNames::Options;
491 default:
492 return Common::Input::ButtonNames::Undefined;
493 }
494}
495
496Common::Input::ButtonNames UDPClient::GetUIName(const Common::ParamPackage& params) const {
497 if (params.Has("button")) {
498 return GetUIButtonName(params);
499 }
500 if (params.Has("axis")) {
501 return Common::Input::ButtonNames::Value;
502 }
503 if (params.Has("motion")) {
504 return Common::Input::ButtonNames::Engine;
505 }
506
507 return Common::Input::ButtonNames::Invalid;
508}
509
320void TestCommunication(const std::string& host, u16 port, 510void TestCommunication(const std::string& host, u16 port,
321 const std::function<void()>& success_callback, 511 const std::function<void()>& success_callback,
322 const std::function<void()>& failure_callback) { 512 const std::function<void()>& failure_callback) {
diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h
index 1f02adba5..5d483f26b 100644
--- a/src/input_common/drivers/udp_client.h
+++ b/src/input_common/drivers/udp_client.h
@@ -56,7 +56,61 @@ public:
56 56
57 void ReloadSockets(); 57 void ReloadSockets();
58 58
59 /// Used for automapping features
60 std::vector<Common::ParamPackage> GetInputDevices() const override;
61 ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;
62 AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override;
63 MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override;
64 Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override;
65
59private: 66private:
67 enum class PadButton {
68 Undefined = 0x0000,
69 Share = 0x0001,
70 L3 = 0x0002,
71 R3 = 0x0004,
72 Options = 0x0008,
73 Up = 0x0010,
74 Right = 0x0020,
75 Down = 0x0040,
76 Left = 0x0080,
77 L2 = 0x0100,
78 R2 = 0x0200,
79 L1 = 0x0400,
80 R1 = 0x0800,
81 Triangle = 0x1000,
82 Circle = 0x2000,
83 Cross = 0x4000,
84 Square = 0x8000,
85 Touch1 = 0x10000,
86 touch2 = 0x20000,
87 };
88
89 enum class PadAxes : u8 {
90 LeftStickX,
91 LeftStickY,
92 RightStickX,
93 RightStickY,
94 AnalogLeft,
95 AnalogDown,
96 AnalogRight,
97 AnalogUp,
98 AnalogSquare,
99 AnalogCross,
100 AnalogCircle,
101 AnalogTriangle,
102 AnalogR1,
103 AnalogL1,
104 AnalogR2,
105 AnalogL3,
106 AnalogR3,
107 Touch1X,
108 Touch1Y,
109 Touch2X,
110 Touch2Y,
111 Undefined,
112 };
113
60 struct PadData { 114 struct PadData {
61 std::size_t pad_index{}; 115 std::size_t pad_index{};
62 bool connected{}; 116 bool connected{};
@@ -90,6 +144,8 @@ private:
90 const PadIdentifier GetPadIdentifier(std::size_t pad_index) const; 144 const PadIdentifier GetPadIdentifier(std::size_t pad_index) const;
91 const Common::UUID GetHostUUID(const std::string host) const; 145 const Common::UUID GetHostUUID(const std::string host) const;
92 146
147 Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const;
148
93 // Allocate clients for 8 udp servers 149 // Allocate clients for 8 udp servers
94 static constexpr std::size_t MAX_UDP_CLIENTS = 8; 150 static constexpr std::size_t MAX_UDP_CLIENTS = 8;
95 static constexpr std::size_t PADS_PER_CLIENT = 4; 151 static constexpr std::size_t PADS_PER_CLIENT = 4;
diff --git a/src/input_common/helpers/udp_protocol.h b/src/input_common/helpers/udp_protocol.h
index 1bdc9209e..bcba12c58 100644
--- a/src/input_common/helpers/udp_protocol.h
+++ b/src/input_common/helpers/udp_protocol.h
@@ -56,6 +56,12 @@ constexpr Type GetMessageType();
56 56
57namespace Request { 57namespace Request {
58 58
59enum RegisterFlags : u8 {
60 AllPads,
61 PadID,
62 PadMACAdddress,
63};
64
59struct Version {}; 65struct Version {};
60/** 66/**
61 * Requests the server to send information about what controllers are plugged into the ports 67 * Requests the server to send information about what controllers are plugged into the ports
@@ -77,13 +83,8 @@ static_assert(std::is_trivially_copyable_v<PortInfo>,
77 * timeout seems to be 5 seconds. 83 * timeout seems to be 5 seconds.
78 */ 84 */
79struct PadData { 85struct PadData {
80 enum class Flags : u8 {
81 AllPorts,
82 Id,
83 Mac,
84 };
85 /// Determines which method will be used as a look up for the controller 86 /// Determines which method will be used as a look up for the controller
86 Flags flags{}; 87 RegisterFlags flags{};
87 /// Index of the port of the controller to retrieve data about 88 /// Index of the port of the controller to retrieve data about
88 u8 port_id{}; 89 u8 port_id{};
89 /// Mac address of the controller to retrieve data about 90 /// Mac address of the controller to retrieve data about
@@ -113,6 +114,36 @@ Message<T> Create(const T data, const u32 client_id = 0) {
113 114
114namespace Response { 115namespace Response {
115 116
117enum class ConnectionType : u8 {
118 None,
119 Usb,
120 Bluetooth,
121};
122
123enum class State : u8 {
124 Disconnected,
125 Reserved,
126 Connected,
127};
128
129enum class Model : u8 {
130 None,
131 PartialGyro,
132 FullGyro,
133 Generic,
134};
135
136enum class Battery : u8 {
137 None = 0x00,
138 Dying = 0x01,
139 Low = 0x02,
140 Medium = 0x03,
141 High = 0x04,
142 Full = 0x05,
143 Charging = 0xEE,
144 Charged = 0xEF,
145};
146
116struct Version { 147struct Version {
117 u16_le version{}; 148 u16_le version{};
118}; 149};
@@ -122,11 +153,11 @@ static_assert(std::is_trivially_copyable_v<Version>,
122 153
123struct PortInfo { 154struct PortInfo {
124 u8 id{}; 155 u8 id{};
125 u8 state{}; 156 State state{};
126 u8 model{}; 157 Model model{};
127 u8 connection_type{}; 158 ConnectionType connection_type{};
128 MacAddress mac; 159 MacAddress mac;
129 u8 battery{}; 160 Battery battery{};
130 u8 is_pad_active{}; 161 u8 is_pad_active{};
131}; 162};
132static_assert(sizeof(PortInfo) == 12, "UDP Response PortInfo struct has wrong size"); 163static_assert(sizeof(PortInfo) == 12, "UDP Response PortInfo struct has wrong size");
@@ -177,18 +208,18 @@ struct PadData {
177 u8 right_stick_y{}; 208 u8 right_stick_y{};
178 209
179 struct AnalogButton { 210 struct AnalogButton {
180 u8 button_8{}; 211 u8 button_dpad_left_analog{};
181 u8 button_7{}; 212 u8 button_dpad_down_analog{};
182 u8 button_6{}; 213 u8 button_dpad_right_analog{};
183 u8 button_5{}; 214 u8 button_dpad_up_analog{};
184 u8 button_12{}; 215 u8 button_square_analog{};
185 u8 button_11{}; 216 u8 button_cross_analog{};
186 u8 button_10{}; 217 u8 button_circle_analog{};
187 u8 button_9{}; 218 u8 button_triangle_analog{};
188 u8 button_16{}; 219 u8 button_r1_analog{};
189 u8 button_15{}; 220 u8 button_l1_analog{};
190 u8 button_14{}; 221 u8 trigger_r2{};
191 u8 button_13{}; 222 u8 trigger_l2{};
192 } analog_button; 223 } analog_button;
193 224
194 std::array<TouchPad, 2> touch; 225 std::array<TouchPad, 2> touch;
diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp
index c5218f2cb..6e0024b2d 100644
--- a/src/input_common/input_mapping.cpp
+++ b/src/input_common/input_mapping.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included 3// Refer to the license.txt file included
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
6#include "common/settings.h"
6#include "input_common/input_engine.h" 7#include "input_common/input_engine.h"
7#include "input_common/input_mapping.h" 8#include "input_common/input_mapping.h"
8 9
@@ -182,6 +183,11 @@ bool MappingFactory::IsDriverValid(const MappingData& data) const {
182 if (data.engine == "keyboard" && data.pad.port != 0) { 183 if (data.engine == "keyboard" && data.pad.port != 0) {
183 return false; 184 return false;
184 } 185 }
186 // To prevent mapping with two devices we disable any UDP except motion
187 if (!Settings::values.enable_udp_controller && data.engine == "cemuhookudp" &&
188 data.type != EngineInputType::Motion) {
189 return false;
190 }
185 // The following drivers don't need to be mapped 191 // The following drivers don't need to be mapped
186 if (data.engine == "tas") { 192 if (data.engine == "tas") {
187 return false; 193 return false;
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 39e4935dc..940744c5f 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -63,9 +63,12 @@ struct InputSubsystem::Impl {
63 63
64 udp_client = std::make_shared<CemuhookUDP::UDPClient>("cemuhookudp"); 64 udp_client = std::make_shared<CemuhookUDP::UDPClient>("cemuhookudp");
65 udp_client->SetMappingCallback(mapping_callback); 65 udp_client->SetMappingCallback(mapping_callback);
66 udp_client_factory = std::make_shared<InputFactory>(udp_client); 66 udp_client_input_factory = std::make_shared<InputFactory>(udp_client);
67 udp_client_output_factory = std::make_shared<OutputFactory>(udp_client);
67 Common::Input::RegisterFactory<Common::Input::InputDevice>(udp_client->GetEngineName(), 68 Common::Input::RegisterFactory<Common::Input::InputDevice>(udp_client->GetEngineName(),
68 udp_client_factory); 69 udp_client_input_factory);
70 Common::Input::RegisterFactory<Common::Input::OutputDevice>(udp_client->GetEngineName(),
71 udp_client_output_factory);
69 72
70 tas_input = std::make_shared<TasInput::Tas>("tas"); 73 tas_input = std::make_shared<TasInput::Tas>("tas");
71 tas_input->SetMappingCallback(mapping_callback); 74 tas_input->SetMappingCallback(mapping_callback);
@@ -110,6 +113,7 @@ struct InputSubsystem::Impl {
110 gcadapter.reset(); 113 gcadapter.reset();
111 114
112 Common::Input::UnregisterFactory<Common::Input::InputDevice>(udp_client->GetEngineName()); 115 Common::Input::UnregisterFactory<Common::Input::InputDevice>(udp_client->GetEngineName());
116 Common::Input::UnregisterFactory<Common::Input::OutputDevice>(udp_client->GetEngineName());
113 udp_client.reset(); 117 udp_client.reset();
114 118
115 Common::Input::UnregisterFactory<Common::Input::InputDevice>(tas_input->GetEngineName()); 119 Common::Input::UnregisterFactory<Common::Input::InputDevice>(tas_input->GetEngineName());
@@ -137,6 +141,8 @@ struct InputSubsystem::Impl {
137 devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end()); 141 devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end());
138 auto gcadapter_devices = gcadapter->GetInputDevices(); 142 auto gcadapter_devices = gcadapter->GetInputDevices();
139 devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end()); 143 devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end());
144 auto udp_devices = udp_client->GetInputDevices();
145 devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
140#ifdef HAVE_SDL2 146#ifdef HAVE_SDL2
141 auto sdl_devices = sdl->GetInputDevices(); 147 auto sdl_devices = sdl->GetInputDevices();
142 devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end()); 148 devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end());
@@ -157,6 +163,9 @@ struct InputSubsystem::Impl {
157 if (engine == gcadapter->GetEngineName()) { 163 if (engine == gcadapter->GetEngineName()) {
158 return gcadapter->GetAnalogMappingForDevice(params); 164 return gcadapter->GetAnalogMappingForDevice(params);
159 } 165 }
166 if (engine == udp_client->GetEngineName()) {
167 return udp_client->GetAnalogMappingForDevice(params);
168 }
160 if (engine == tas_input->GetEngineName()) { 169 if (engine == tas_input->GetEngineName()) {
161 return tas_input->GetAnalogMappingForDevice(params); 170 return tas_input->GetAnalogMappingForDevice(params);
162 } 171 }
@@ -177,6 +186,9 @@ struct InputSubsystem::Impl {
177 if (engine == gcadapter->GetEngineName()) { 186 if (engine == gcadapter->GetEngineName()) {
178 return gcadapter->GetButtonMappingForDevice(params); 187 return gcadapter->GetButtonMappingForDevice(params);
179 } 188 }
189 if (engine == udp_client->GetEngineName()) {
190 return udp_client->GetButtonMappingForDevice(params);
191 }
180 if (engine == tas_input->GetEngineName()) { 192 if (engine == tas_input->GetEngineName()) {
181 return tas_input->GetButtonMappingForDevice(params); 193 return tas_input->GetButtonMappingForDevice(params);
182 } 194 }
@@ -194,8 +206,8 @@ struct InputSubsystem::Impl {
194 return {}; 206 return {};
195 } 207 }
196 const std::string engine = params.Get("engine", ""); 208 const std::string engine = params.Get("engine", "");
197 if (engine == gcadapter->GetEngineName()) { 209 if (engine == udp_client->GetEngineName()) {
198 return gcadapter->GetMotionMappingForDevice(params); 210 return udp_client->GetMotionMappingForDevice(params);
199 } 211 }
200#ifdef HAVE_SDL2 212#ifdef HAVE_SDL2
201 if (engine == sdl->GetEngineName()) { 213 if (engine == sdl->GetEngineName()) {
@@ -238,6 +250,9 @@ struct InputSubsystem::Impl {
238 if (engine == gcadapter->GetEngineName()) { 250 if (engine == gcadapter->GetEngineName()) {
239 return true; 251 return true;
240 } 252 }
253 if (engine == udp_client->GetEngineName()) {
254 return true;
255 }
241 if (engine == tas_input->GetEngineName()) { 256 if (engine == tas_input->GetEngineName()) {
242 return true; 257 return true;
243 } 258 }
@@ -286,12 +301,13 @@ struct InputSubsystem::Impl {
286 std::shared_ptr<InputFactory> mouse_factory; 301 std::shared_ptr<InputFactory> mouse_factory;
287 std::shared_ptr<InputFactory> gcadapter_input_factory; 302 std::shared_ptr<InputFactory> gcadapter_input_factory;
288 std::shared_ptr<InputFactory> touch_screen_factory; 303 std::shared_ptr<InputFactory> touch_screen_factory;
289 std::shared_ptr<InputFactory> udp_client_factory; 304 std::shared_ptr<InputFactory> udp_client_input_factory;
290 std::shared_ptr<InputFactory> tas_input_factory; 305 std::shared_ptr<InputFactory> tas_input_factory;
291 306
292 std::shared_ptr<OutputFactory> keyboard_output_factory; 307 std::shared_ptr<OutputFactory> keyboard_output_factory;
293 std::shared_ptr<OutputFactory> mouse_output_factory; 308 std::shared_ptr<OutputFactory> mouse_output_factory;
294 std::shared_ptr<OutputFactory> gcadapter_output_factory; 309 std::shared_ptr<OutputFactory> gcadapter_output_factory;
310 std::shared_ptr<OutputFactory> udp_client_output_factory;
295 std::shared_ptr<OutputFactory> tas_output_factory; 311 std::shared_ptr<OutputFactory> tas_output_factory;
296 312
297#ifdef HAVE_SDL2 313#ifdef HAVE_SDL2
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index ae1684dd4..38fd6e93b 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -447,6 +447,7 @@ void Config::ReadMotionTouchValues() {
447 Settings::values.touch_from_button_map_index = std::clamp( 447 Settings::values.touch_from_button_map_index = std::clamp(
448 Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); 448 Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
449 ReadBasicSetting(Settings::values.udp_input_servers); 449 ReadBasicSetting(Settings::values.udp_input_servers);
450 ReadBasicSetting(Settings::values.enable_udp_controller);
450} 451}
451 452
452void Config::ReadCoreValues() { 453void Config::ReadCoreValues() {
@@ -942,6 +943,7 @@ void Config::SaveMotionTouchValues() {
942 WriteBasicSetting(Settings::values.touch_device); 943 WriteBasicSetting(Settings::values.touch_device);
943 WriteBasicSetting(Settings::values.touch_from_button_map_index); 944 WriteBasicSetting(Settings::values.touch_from_button_map_index);
944 WriteBasicSetting(Settings::values.udp_input_servers); 945 WriteBasicSetting(Settings::values.udp_input_servers);
946 WriteBasicSetting(Settings::values.enable_udp_controller);
945 947
946 qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps")); 948 qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps"));
947 for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { 949 for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index e6127f9e6..65c8e59ac 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -130,6 +130,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() {
130 static_cast<float>(ui->mouse_panning_sensitivity->value()); 130 static_cast<float>(ui->mouse_panning_sensitivity->value());
131 Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked(); 131 Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
132 Settings::values.enable_raw_input = ui->enable_raw_input->isChecked(); 132 Settings::values.enable_raw_input = ui->enable_raw_input->isChecked();
133 Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked();
133} 134}
134 135
135void ConfigureInputAdvanced::LoadConfiguration() { 136void ConfigureInputAdvanced::LoadConfiguration() {
@@ -160,6 +161,7 @@ void ConfigureInputAdvanced::LoadConfiguration() {
160 ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity.GetValue()); 161 ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity.GetValue());
161 ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled); 162 ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
162 ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue()); 163 ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue());
164 ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue());
163 165
164 UpdateUIEnabled(); 166 UpdateUIEnabled();
165} 167}
diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui
index 75487a5d0..df0e4d602 100644
--- a/src/yuzu/configuration/configure_input_advanced.ui
+++ b/src/yuzu/configuration/configure_input_advanced.ui
@@ -2642,6 +2642,19 @@
2642 </widget> 2642 </widget>
2643 </item> 2643 </item>
2644 <item row="3" column="0"> 2644 <item row="3" column="0">
2645 <widget class="QCheckBox" name="enable_udp_controller">
2646 <property name="minimumSize">
2647 <size>
2648 <width>0</width>
2649 <height>23</height>
2650 </size>
2651 </property>
2652 <property name="text">
2653 <string>Enable UDP controllers (not needed for motion)</string>
2654 </property>
2655 </widget>
2656 </item>
2657 <item row="4" column="0">
2645 <widget class="QCheckBox" name="mouse_panning"> 2658 <widget class="QCheckBox" name="mouse_panning">
2646 <property name="minimumSize"> 2659 <property name="minimumSize">
2647 <size> 2660 <size>
@@ -2654,7 +2667,7 @@
2654 </property> 2667 </property>
2655 </widget> 2668 </widget>
2656 </item> 2669 </item>
2657 <item row="3" column="2"> 2670 <item row="4" column="2">
2658 <widget class="QSpinBox" name="mouse_panning_sensitivity"> 2671 <widget class="QSpinBox" name="mouse_panning_sensitivity">
2659 <property name="toolTip"> 2672 <property name="toolTip">
2660 <string>Mouse sensitivity</string> 2673 <string>Mouse sensitivity</string>
@@ -2676,14 +2689,14 @@
2676 </property> 2689 </property>
2677 </widget> 2690 </widget>
2678 </item> 2691 </item>
2679 <item row="4" column="0"> 2692 <item row="5" column="0">
2680 <widget class="QLabel" name="motion_touch"> 2693 <widget class="QLabel" name="motion_touch">
2681 <property name="text"> 2694 <property name="text">
2682 <string>Motion / Touch</string> 2695 <string>Motion / Touch</string>
2683 </property> 2696 </property>
2684 </widget> 2697 </widget>
2685 </item> 2698 </item>
2686 <item row="4" column="2"> 2699 <item row="5" column="2">
2687 <widget class="QPushButton" name="buttonMotionTouch"> 2700 <widget class="QPushButton" name="buttonMotionTouch">
2688 <property name="text"> 2701 <property name="text">
2689 <string>Configure</string> 2702 <string>Configure</string>
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 6219a09a8..ec071d6ec 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -78,6 +78,30 @@ QString GetButtonName(Common::Input::ButtonNames button_name) {
78 return QObject::tr("Y"); 78 return QObject::tr("Y");
79 case Common::Input::ButtonNames::ButtonStart: 79 case Common::Input::ButtonNames::ButtonStart:
80 return QObject::tr("Start"); 80 return QObject::tr("Start");
81 case Common::Input::ButtonNames::L1:
82 return QObject::tr("L1");
83 case Common::Input::ButtonNames::L2:
84 return QObject::tr("L2");
85 case Common::Input::ButtonNames::L3:
86 return QObject::tr("L3");
87 case Common::Input::ButtonNames::R1:
88 return QObject::tr("R1");
89 case Common::Input::ButtonNames::R2:
90 return QObject::tr("R2");
91 case Common::Input::ButtonNames::R3:
92 return QObject::tr("R3");
93 case Common::Input::ButtonNames::Circle:
94 return QObject::tr("Circle");
95 case Common::Input::ButtonNames::Cross:
96 return QObject::tr("Cross");
97 case Common::Input::ButtonNames::Square:
98 return QObject::tr("Square");
99 case Common::Input::ButtonNames::Triangle:
100 return QObject::tr("Triangle");
101 case Common::Input::ButtonNames::Share:
102 return QObject::tr("Share");
103 case Common::Input::ButtonNames::Options:
104 return QObject::tr("Options");
81 default: 105 default:
82 return QObject::tr("[undefined]"); 106 return QObject::tr("[undefined]");
83 } 107 }