summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2020-12-01 11:47:37 -0800
committerGravatar GitHub2020-12-01 11:47:37 -0800
commit25f650e075c441798016d0e7a446a10ce82a2865 (patch)
tree940e2a4754d9edc508ac75b70903a475b44c7132 /src
parentMerge pull request #5047 from german77/MouseInput (diff)
parentAdd multiple udp server support (diff)
downloadyuzu-25f650e075c441798016d0e7a446a10ce82a2865.tar.gz
yuzu-25f650e075c441798016d0e7a446a10ce82a2865.tar.xz
yuzu-25f650e075c441798016d0e7a446a10ce82a2865.zip
Merge pull request #4937 from german77/multiUDP
InputCommon: Add multiple udp server support
Diffstat (limited to 'src')
-rw-r--r--src/core/settings.h4
-rw-r--r--src/input_common/main.cpp2
-rw-r--r--src/input_common/udp/client.cpp143
-rw-r--r--src/input_common/udp/client.h40
-rw-r--r--src/input_common/udp/udp.cpp64
-rw-r--r--src/yuzu/configuration/config.cpp20
-rw-r--r--src/yuzu/configuration/configure_motion_touch.cpp134
-rw-r--r--src/yuzu/configuration/configure_motion_touch.h5
-rw-r--r--src/yuzu/configuration/configure_motion_touch.ui269
-rw-r--r--src/yuzu_cmd/config.cpp6
10 files changed, 420 insertions, 267 deletions
diff --git a/src/core/settings.h b/src/core/settings.h
index 3df611d5b..8e076f7ef 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -178,9 +178,7 @@ struct Values {
178 178
179 Setting<bool> motion_enabled; 179 Setting<bool> motion_enabled;
180 std::string motion_device; 180 std::string motion_device;
181 std::string udp_input_address; 181 std::string udp_input_servers;
182 u16 udp_input_port;
183 u8 udp_pad_index;
184 182
185 bool mouse_enabled; 183 bool mouse_enabled;
186 std::string mouse_device; 184 std::string mouse_device;
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 880ea73b8..7c4e7dd3b 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -286,7 +286,7 @@ void InputSubsystem::ReloadInputDevices() {
286 if (!impl->udp) { 286 if (!impl->udp) {
287 return; 287 return;
288 } 288 }
289 impl->udp->ReloadUDPClient(); 289 impl->udp->ReloadSockets();
290} 290}
291 291
292std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers( 292std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers(
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index c0bb90048..17a9225d7 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -136,15 +136,7 @@ static void SocketLoop(Socket* socket) {
136 136
137Client::Client() { 137Client::Client() {
138 LOG_INFO(Input, "Udp Initialization started"); 138 LOG_INFO(Input, "Udp Initialization started");
139 for (std::size_t client = 0; client < clients.size(); client++) { 139 ReloadSockets();
140 const auto pad = client % 4;
141 StartCommunication(client, Settings::values.udp_input_address,
142 Settings::values.udp_input_port, pad, 24872);
143 // Set motion parameters
144 // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode
145 // Real HW values are unknown, 0.0001 is an approximate to Standard
146 clients[client].motion.SetGyroThreshold(0.0001f);
147 }
148} 140}
149 141
150Client::~Client() { 142Client::~Client() {
@@ -167,26 +159,61 @@ std::vector<Common::ParamPackage> Client::GetInputDevices() const {
167 return devices; 159 return devices;
168} 160}
169 161
170bool Client::DeviceConnected(std::size_t pad) const { 162bool Client::DeviceConnected(std::size_t client) const {
171 // Use last timestamp to detect if the socket has stopped sending data 163 // Use last timestamp to detect if the socket has stopped sending data
172 const auto now = std::chrono::system_clock::now(); 164 const auto now = std::chrono::steady_clock::now();
173 const auto time_difference = static_cast<u64>( 165 const auto time_difference =
174 std::chrono::duration_cast<std::chrono::milliseconds>(now - clients[pad].last_motion_update) 166 static_cast<u64>(std::chrono::duration_cast<std::chrono::milliseconds>(
175 .count()); 167 now - clients[client].last_motion_update)
176 return time_difference < 1000 && clients[pad].active == 1; 168 .count());
169 return time_difference < 1000 && clients[client].active == 1;
177} 170}
178 171
179void Client::ReloadUDPClient() { 172void Client::ReloadSockets() {
180 for (std::size_t client = 0; client < clients.size(); client++) { 173 Reset();
181 ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port, client); 174
175 std::stringstream servers_ss(Settings::values.udp_input_servers);
176 std::string server_token;
177 std::size_t client = 0;
178 while (std::getline(servers_ss, server_token, ',')) {
179 if (client == max_udp_clients) {
180 break;
181 }
182 std::stringstream server_ss(server_token);
183 std::string token;
184 std::getline(server_ss, token, ':');
185 std::string udp_input_address = token;
186 std::getline(server_ss, token, ':');
187 char* temp;
188 const u16 udp_input_port = static_cast<u16>(std::strtol(token.c_str(), &temp, 0));
189 if (*temp != '\0') {
190 LOG_ERROR(Input, "Port number is not valid {}", token);
191 continue;
192 }
193
194 for (std::size_t pad = 0; pad < 4; ++pad) {
195 const std::size_t client_number =
196 GetClientNumber(udp_input_address, udp_input_port, pad);
197 if (client_number != max_udp_clients) {
198 LOG_ERROR(Input, "Duplicated UDP servers found");
199 continue;
200 }
201 StartCommunication(client++, udp_input_address, udp_input_port, pad, 24872);
202 }
182 } 203 }
183} 204}
184void Client::ReloadSocket(const std::string& host, u16 port, std::size_t pad_index, u32 client_id) { 205
185 // client number must be determined from host / port and pad index 206std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t pad) const {
186 const std::size_t client = pad_index; 207 for (std::size_t client = 0; client < clients.size(); client++) {
187 clients[client].socket->Stop(); 208 if (clients[client].active == -1) {
188 clients[client].thread.join(); 209 continue;
189 StartCommunication(client, host, port, pad_index, client_id); 210 }
211 if (clients[client].host == host && clients[client].port == port &&
212 clients[client].pad_index == pad) {
213 return client;
214 }
215 }
216 return max_udp_clients;
190} 217}
191 218
192void Client::OnVersion([[maybe_unused]] Response::Version data) { 219void Client::OnVersion([[maybe_unused]] Response::Version data) {
@@ -197,9 +224,7 @@ void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) {
197 LOG_TRACE(Input, "PortInfo packet received: {}", data.model); 224 LOG_TRACE(Input, "PortInfo packet received: {}", data.model);
198} 225}
199 226
200void Client::OnPadData(Response::PadData data) { 227void Client::OnPadData(Response::PadData data, std::size_t client) {
201 // Client number must be determined from host / port and pad index
202 const std::size_t client = data.info.id;
203 LOG_TRACE(Input, "PadData packet received"); 228 LOG_TRACE(Input, "PadData packet received");
204 if (data.packet_counter == clients[client].packet_sequence) { 229 if (data.packet_counter == clients[client].packet_sequence) {
205 LOG_WARNING( 230 LOG_WARNING(
@@ -208,9 +233,9 @@ void Client::OnPadData(Response::PadData data) {
208 clients[client].packet_sequence, data.packet_counter); 233 clients[client].packet_sequence, data.packet_counter);
209 return; 234 return;
210 } 235 }
211 clients[client].active = data.info.is_pad_active; 236 clients[client].active = static_cast<s8>(data.info.is_pad_active);
212 clients[client].packet_sequence = data.packet_counter; 237 clients[client].packet_sequence = data.packet_counter;
213 const auto now = std::chrono::system_clock::now(); 238 const auto now = std::chrono::steady_clock::now();
214 const auto time_difference = 239 const auto time_difference =
215 static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>( 240 static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>(
216 now - clients[client].last_motion_update) 241 now - clients[client].last_motion_update)
@@ -264,16 +289,28 @@ void Client::StartCommunication(std::size_t client, const std::string& host, u16
264 std::size_t pad_index, u32 client_id) { 289 std::size_t pad_index, u32 client_id) {
265 SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, 290 SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
266 [this](Response::PortInfo info) { OnPortInfo(info); }, 291 [this](Response::PortInfo info) { OnPortInfo(info); },
267 [this](Response::PadData data) { OnPadData(data); }}; 292 [this, client](Response::PadData data) { OnPadData(data, client); }};
268 LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port); 293 LOG_INFO(Input, "Starting communication with UDP input server on {}:{}:{}", host, port,
294 pad_index);
295 clients[client].host = host;
296 clients[client].port = port;
297 clients[client].pad_index = pad_index;
298 clients[client].active = 0;
269 clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback); 299 clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback);
270 clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; 300 clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()};
301 // Set motion parameters
302 // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode
303 // Real HW values are unknown, 0.0001 is an approximate to Standard
304 clients[client].motion.SetGyroThreshold(0.0001f);
271} 305}
272 306
273void Client::Reset() { 307void Client::Reset() {
274 for (auto& client : clients) { 308 for (auto& client : clients) {
275 client.socket->Stop(); 309 if (client.thread.joinable()) {
276 client.thread.join(); 310 client.active = -1;
311 client.socket->Stop();
312 client.thread.join();
313 }
277 } 314 }
278} 315}
279 316
@@ -283,52 +320,60 @@ void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& a
283 LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}", 320 LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}",
284 client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch); 321 client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch);
285 } 322 }
286 UDPPadStatus pad; 323 UDPPadStatus pad{
324 .host = clients[client].host,
325 .port = clients[client].port,
326 .pad_index = clients[client].pad_index,
327 };
287 if (touch) { 328 if (touch) {
288 pad.touch = PadTouch::Click; 329 pad.touch = PadTouch::Click;
289 pad_queue[client].Push(pad); 330 pad_queue.Push(pad);
290 } 331 }
291 for (size_t i = 0; i < 3; ++i) { 332 for (size_t i = 0; i < 3; ++i) {
292 if (gyro[i] > 5.0f || gyro[i] < -5.0f) { 333 if (gyro[i] > 5.0f || gyro[i] < -5.0f) {
293 pad.motion = static_cast<PadMotion>(i); 334 pad.motion = static_cast<PadMotion>(i);
294 pad.motion_value = gyro[i]; 335 pad.motion_value = gyro[i];
295 pad_queue[client].Push(pad); 336 pad_queue.Push(pad);
296 } 337 }
297 if (acc[i] > 1.75f || acc[i] < -1.75f) { 338 if (acc[i] > 1.75f || acc[i] < -1.75f) {
298 pad.motion = static_cast<PadMotion>(i + 3); 339 pad.motion = static_cast<PadMotion>(i + 3);
299 pad.motion_value = acc[i]; 340 pad.motion_value = acc[i];
300 pad_queue[client].Push(pad); 341 pad_queue.Push(pad);
301 } 342 }
302 } 343 }
303} 344}
304 345
305void Client::BeginConfiguration() { 346void Client::BeginConfiguration() {
306 for (auto& pq : pad_queue) { 347 pad_queue.Clear();
307 pq.Clear();
308 }
309 configuring = true; 348 configuring = true;
310} 349}
311 350
312void Client::EndConfiguration() { 351void Client::EndConfiguration() {
313 for (auto& pq : pad_queue) { 352 pad_queue.Clear();
314 pq.Clear();
315 }
316 configuring = false; 353 configuring = false;
317} 354}
318 355
319DeviceStatus& Client::GetPadState(std::size_t pad) { 356DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) {
320 return clients[pad].status; 357 const std::size_t client_number = GetClientNumber(host, port, pad);
358 if (client_number == max_udp_clients) {
359 return clients[0].status;
360 }
361 return clients[client_number].status;
321} 362}
322 363
323const DeviceStatus& Client::GetPadState(std::size_t pad) const { 364const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const {
324 return clients[pad].status; 365 const std::size_t client_number = GetClientNumber(host, port, pad);
366 if (client_number == max_udp_clients) {
367 return clients[0].status;
368 }
369 return clients[client_number].status;
325} 370}
326 371
327std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() { 372Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() {
328 return pad_queue; 373 return pad_queue;
329} 374}
330 375
331const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() const { 376const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const {
332 return pad_queue; 377 return pad_queue;
333} 378}
334 379
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h
index 747e0c0a2..00c8b09f5 100644
--- a/src/input_common/udp/client.h
+++ b/src/input_common/udp/client.h
@@ -21,8 +21,7 @@
21 21
22namespace InputCommon::CemuhookUDP { 22namespace InputCommon::CemuhookUDP {
23 23
24constexpr u16 DEFAULT_PORT = 26760; 24constexpr char DEFAULT_SRV[] = "127.0.0.1:26760";
25constexpr char DEFAULT_ADDR[] = "127.0.0.1";
26 25
27class Socket; 26class Socket;
28 27
@@ -48,6 +47,9 @@ enum class PadTouch {
48}; 47};
49 48
50struct UDPPadStatus { 49struct UDPPadStatus {
50 std::string host{"127.0.0.1"};
51 u16 port{26760};
52 std::size_t pad_index{};
51 PadTouch touch{PadTouch::Undefined}; 53 PadTouch touch{PadTouch::Undefined};
52 PadMotion motion{PadMotion::Undefined}; 54 PadMotion motion{PadMotion::Undefined};
53 f32 motion_value{0.0f}; 55 f32 motion_value{0.0f};
@@ -82,37 +84,41 @@ public:
82 84
83 std::vector<Common::ParamPackage> GetInputDevices() const; 85 std::vector<Common::ParamPackage> GetInputDevices() const;
84 86
85 bool DeviceConnected(std::size_t pad) const; 87 bool DeviceConnected(std::size_t client) const;
86 void ReloadUDPClient(); 88 void ReloadSockets();
87 void ReloadSocket(const std::string& host = "127.0.0.1", u16 port = 26760,
88 std::size_t pad_index = 0, u32 client_id = 24872);
89 89
90 std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue(); 90 Common::SPSCQueue<UDPPadStatus>& GetPadQueue();
91 const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue() const; 91 const Common::SPSCQueue<UDPPadStatus>& GetPadQueue() const;
92 92
93 DeviceStatus& GetPadState(std::size_t pad); 93 DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad);
94 const DeviceStatus& GetPadState(std::size_t pad) const; 94 const DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad) const;
95 95
96private: 96private:
97 struct ClientData { 97 struct ClientData {
98 std::string host{"127.0.0.1"};
99 u16 port{26760};
100 std::size_t pad_index{};
98 std::unique_ptr<Socket> socket; 101 std::unique_ptr<Socket> socket;
99 DeviceStatus status; 102 DeviceStatus status;
100 std::thread thread; 103 std::thread thread;
101 u64 packet_sequence = 0; 104 u64 packet_sequence{};
102 u8 active = 0; 105 s8 active{-1};
103 106
104 // Realtime values 107 // Realtime values
105 // motion is initalized with PID values for drift correction on joycons 108 // motion is initalized with PID values for drift correction on joycons
106 InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f}; 109 InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f};
107 std::chrono::time_point<std::chrono::system_clock> last_motion_update; 110 std::chrono::time_point<std::chrono::steady_clock> last_motion_update;
108 }; 111 };
109 112
110 // For shutting down, clear all data, join all threads, release usb 113 // For shutting down, clear all data, join all threads, release usb
111 void Reset(); 114 void Reset();
112 115
116 // Translates configuration to client number
117 std::size_t GetClientNumber(std::string_view host, u16 port, std::size_t pad) const;
118
113 void OnVersion(Response::Version); 119 void OnVersion(Response::Version);
114 void OnPortInfo(Response::PortInfo); 120 void OnPortInfo(Response::PortInfo);
115 void OnPadData(Response::PadData); 121 void OnPadData(Response::PadData, std::size_t client);
116 void StartCommunication(std::size_t client, const std::string& host, u16 port, 122 void StartCommunication(std::size_t client, const std::string& host, u16 port,
117 std::size_t pad_index, u32 client_id); 123 std::size_t pad_index, u32 client_id);
118 void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, 124 void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
@@ -120,8 +126,10 @@ private:
120 126
121 bool configuring = false; 127 bool configuring = false;
122 128
123 std::array<ClientData, 4> clients; 129 // Allocate clients for 8 udp servers
124 std::array<Common::SPSCQueue<UDPPadStatus>, 4> pad_queue; 130 const std::size_t max_udp_clients = 32;
131 std::array<ClientData, 4 * 8> clients;
132 Common::SPSCQueue<UDPPadStatus> pad_queue;
125}; 133};
126 134
127/// An async job allowing configuration of the touchpad calibration. 135/// An async job allowing configuration of the touchpad calibration.
diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp
index 71a76a7aa..8686a059c 100644
--- a/src/input_common/udp/udp.cpp
+++ b/src/input_common/udp/udp.cpp
@@ -13,17 +13,17 @@ namespace InputCommon {
13 13
14class UDPMotion final : public Input::MotionDevice { 14class UDPMotion final : public Input::MotionDevice {
15public: 15public:
16 explicit UDPMotion(std::string ip_, int port_, u32 pad_, CemuhookUDP::Client* client_) 16 explicit UDPMotion(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_)
17 : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} 17 : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {}
18 18
19 Input::MotionStatus GetStatus() const override { 19 Input::MotionStatus GetStatus() const override {
20 return client->GetPadState(pad).motion_status; 20 return client->GetPadState(ip, port, pad).motion_status;
21 } 21 }
22 22
23private: 23private:
24 const std::string ip; 24 const std::string ip;
25 const int port; 25 const u16 port;
26 const u32 pad; 26 const u16 pad;
27 CemuhookUDP::Client* client; 27 CemuhookUDP::Client* client;
28 mutable std::mutex mutex; 28 mutable std::mutex mutex;
29}; 29};
@@ -39,8 +39,8 @@ UDPMotionFactory::UDPMotionFactory(std::shared_ptr<CemuhookUDP::Client> client_)
39 */ 39 */
40std::unique_ptr<Input::MotionDevice> UDPMotionFactory::Create(const Common::ParamPackage& params) { 40std::unique_ptr<Input::MotionDevice> UDPMotionFactory::Create(const Common::ParamPackage& params) {
41 auto ip = params.Get("ip", "127.0.0.1"); 41 auto ip = params.Get("ip", "127.0.0.1");
42 const auto port = params.Get("port", 26760); 42 const auto port = static_cast<u16>(params.Get("port", 26760));
43 const auto pad = static_cast<u32>(params.Get("pad_index", 0)); 43 const auto pad = static_cast<u16>(params.Get("pad_index", 0));
44 44
45 return std::make_unique<UDPMotion>(std::move(ip), port, pad, client.get()); 45 return std::make_unique<UDPMotion>(std::move(ip), port, pad, client.get());
46} 46}
@@ -59,35 +59,33 @@ Common::ParamPackage UDPMotionFactory::GetNextInput() {
59 Common::ParamPackage params; 59 Common::ParamPackage params;
60 CemuhookUDP::UDPPadStatus pad; 60 CemuhookUDP::UDPPadStatus pad;
61 auto& queue = client->GetPadQueue(); 61 auto& queue = client->GetPadQueue();
62 for (std::size_t pad_number = 0; pad_number < queue.size(); ++pad_number) { 62 while (queue.Pop(pad)) {
63 while (queue[pad_number].Pop(pad)) { 63 if (pad.motion == CemuhookUDP::PadMotion::Undefined || std::abs(pad.motion_value) < 1) {
64 if (pad.motion == CemuhookUDP::PadMotion::Undefined || std::abs(pad.motion_value) < 1) { 64 continue;
65 continue;
66 }
67 params.Set("engine", "cemuhookudp");
68 params.Set("ip", "127.0.0.1");
69 params.Set("port", 26760);
70 params.Set("pad_index", static_cast<int>(pad_number));
71 params.Set("motion", static_cast<u16>(pad.motion));
72 return params;
73 } 65 }
66 params.Set("engine", "cemuhookudp");
67 params.Set("ip", pad.host);
68 params.Set("port", static_cast<u16>(pad.port));
69 params.Set("pad_index", static_cast<u16>(pad.pad_index));
70 params.Set("motion", static_cast<u16>(pad.motion));
71 return params;
74 } 72 }
75 return params; 73 return params;
76} 74}
77 75
78class UDPTouch final : public Input::TouchDevice { 76class UDPTouch final : public Input::TouchDevice {
79public: 77public:
80 explicit UDPTouch(std::string ip_, int port_, u32 pad_, CemuhookUDP::Client* client_) 78 explicit UDPTouch(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_)
81 : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} 79 : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {}
82 80
83 std::tuple<float, float, bool> GetStatus() const override { 81 std::tuple<float, float, bool> GetStatus() const override {
84 return client->GetPadState(pad).touch_status; 82 return client->GetPadState(ip, port, pad).touch_status;
85 } 83 }
86 84
87private: 85private:
88 const std::string ip; 86 const std::string ip;
89 const int port; 87 const u16 port;
90 const u32 pad; 88 const u16 pad;
91 CemuhookUDP::Client* client; 89 CemuhookUDP::Client* client;
92 mutable std::mutex mutex; 90 mutable std::mutex mutex;
93}; 91};
@@ -103,8 +101,8 @@ UDPTouchFactory::UDPTouchFactory(std::shared_ptr<CemuhookUDP::Client> client_)
103 */ 101 */
104std::unique_ptr<Input::TouchDevice> UDPTouchFactory::Create(const Common::ParamPackage& params) { 102std::unique_ptr<Input::TouchDevice> UDPTouchFactory::Create(const Common::ParamPackage& params) {
105 auto ip = params.Get("ip", "127.0.0.1"); 103 auto ip = params.Get("ip", "127.0.0.1");
106 const auto port = params.Get("port", 26760); 104 const auto port = static_cast<u16>(params.Get("port", 26760));
107 const auto pad = static_cast<u32>(params.Get("pad_index", 0)); 105 const auto pad = static_cast<u16>(params.Get("pad_index", 0));
108 106
109 return std::make_unique<UDPTouch>(std::move(ip), port, pad, client.get()); 107 return std::make_unique<UDPTouch>(std::move(ip), port, pad, client.get());
110} 108}
@@ -123,18 +121,16 @@ Common::ParamPackage UDPTouchFactory::GetNextInput() {
123 Common::ParamPackage params; 121 Common::ParamPackage params;
124 CemuhookUDP::UDPPadStatus pad; 122 CemuhookUDP::UDPPadStatus pad;
125 auto& queue = client->GetPadQueue(); 123 auto& queue = client->GetPadQueue();
126 for (std::size_t pad_number = 0; pad_number < queue.size(); ++pad_number) { 124 while (queue.Pop(pad)) {
127 while (queue[pad_number].Pop(pad)) { 125 if (pad.touch == CemuhookUDP::PadTouch::Undefined) {
128 if (pad.touch == CemuhookUDP::PadTouch::Undefined) { 126 continue;
129 continue;
130 }
131 params.Set("engine", "cemuhookudp");
132 params.Set("ip", "127.0.0.1");
133 params.Set("port", 26760);
134 params.Set("pad_index", static_cast<int>(pad_number));
135 params.Set("touch", static_cast<u16>(pad.touch));
136 return params;
137 } 127 }
128 params.Set("engine", "cemuhookudp");
129 params.Set("ip", pad.host);
130 params.Set("port", static_cast<u16>(pad.port));
131 params.Set("pad_index", static_cast<u16>(pad.pad_index));
132 params.Set("touch", static_cast<u16>(pad.touch));
133 return params;
138 } 134 }
139 return params; 135 return params;
140} 136}
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 8be9e93c3..fcc38b3af 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -569,16 +569,11 @@ void Config::ReadMotionTouchValues() {
569 ReadSetting(QStringLiteral("touch_from_button_map"), 0).toInt(); 569 ReadSetting(QStringLiteral("touch_from_button_map"), 0).toInt();
570 Settings::values.touch_from_button_map_index = 570 Settings::values.touch_from_button_map_index =
571 std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1); 571 std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1);
572 Settings::values.udp_input_address = 572 Settings::values.udp_input_servers =
573 ReadSetting(QStringLiteral("udp_input_address"), 573 ReadSetting(QStringLiteral("udp_input_servers"),
574 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR)) 574 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_SRV))
575 .toString() 575 .toString()
576 .toStdString(); 576 .toStdString();
577 Settings::values.udp_input_port = static_cast<u16>(
578 ReadSetting(QStringLiteral("udp_input_port"), InputCommon::CemuhookUDP::DEFAULT_PORT)
579 .toInt());
580 Settings::values.udp_pad_index =
581 static_cast<u8>(ReadSetting(QStringLiteral("udp_pad_index"), 0).toUInt());
582} 577}
583 578
584void Config::ReadCoreValues() { 579void Config::ReadCoreValues() {
@@ -1109,12 +1104,9 @@ void Config::SaveMotionTouchValues() {
1109 false); 1104 false);
1110 WriteSetting(QStringLiteral("touch_from_button_map"), 1105 WriteSetting(QStringLiteral("touch_from_button_map"),
1111 Settings::values.touch_from_button_map_index, 0); 1106 Settings::values.touch_from_button_map_index, 0);
1112 WriteSetting(QStringLiteral("udp_input_address"), 1107 WriteSetting(QStringLiteral("udp_input_servers"),
1113 QString::fromStdString(Settings::values.udp_input_address), 1108 QString::fromStdString(Settings::values.udp_input_servers),
1114 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR)); 1109 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_SRV));
1115 WriteSetting(QStringLiteral("udp_input_port"), Settings::values.udp_input_port,
1116 InputCommon::CemuhookUDP::DEFAULT_PORT);
1117 WriteSetting(QStringLiteral("udp_pad_index"), Settings::values.udp_pad_index, 0);
1118 1110
1119 qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps")); 1111 qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps"));
1120 for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { 1112 for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp
index 170574d9b..2afac591a 100644
--- a/src/yuzu/configuration/configure_motion_touch.cpp
+++ b/src/yuzu/configuration/configure_motion_touch.cpp
@@ -3,10 +3,12 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array> 5#include <array>
6#include <sstream>
6#include <QCloseEvent> 7#include <QCloseEvent>
7#include <QLabel> 8#include <QLabel>
8#include <QMessageBox> 9#include <QMessageBox>
9#include <QPushButton> 10#include <QPushButton>
11#include <QStringListModel>
10#include <QVBoxLayout> 12#include <QVBoxLayout>
11#include "common/logging/log.h" 13#include "common/logging/log.h"
12#include "core/settings.h" 14#include "core/settings.h"
@@ -74,11 +76,6 @@ void CalibrationConfigurationDialog::UpdateButtonText(const QString& text) {
74 cancel_button->setText(text); 76 cancel_button->setText(text);
75} 77}
76 78
77constexpr std::array<std::pair<const char*, const char*>, 2> MotionProviders = {{
78 {"motion_emu", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Mouse (Right Click)")},
79 {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")},
80}};
81
82constexpr std::array<std::pair<const char*, const char*>, 2> TouchProviders = {{ 79constexpr std::array<std::pair<const char*, const char*>, 2> TouchProviders = {{
83 {"emu_window", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Emulator Window")}, 80 {"emu_window", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Emulator Window")},
84 {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")}, 81 {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")},
@@ -89,9 +86,6 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent,
89 : QDialog(parent), input_subsystem{input_subsystem_}, 86 : QDialog(parent), input_subsystem{input_subsystem_},
90 ui(std::make_unique<Ui::ConfigureMotionTouch>()) { 87 ui(std::make_unique<Ui::ConfigureMotionTouch>()) {
91 ui->setupUi(this); 88 ui->setupUi(this);
92 for (const auto& [provider, name] : MotionProviders) {
93 ui->motion_provider->addItem(tr(name), QString::fromUtf8(provider));
94 }
95 for (const auto& [provider, name] : TouchProviders) { 89 for (const auto& [provider, name] : TouchProviders) {
96 ui->touch_provider->addItem(tr(name), QString::fromUtf8(provider)); 90 ui->touch_provider->addItem(tr(name), QString::fromUtf8(provider));
97 } 91 }
@@ -116,8 +110,6 @@ void ConfigureMotionTouch::SetConfiguration() {
116 const std::string motion_engine = motion_param.Get("engine", "motion_emu"); 110 const std::string motion_engine = motion_param.Get("engine", "motion_emu");
117 const std::string touch_engine = touch_param.Get("engine", "emu_window"); 111 const std::string touch_engine = touch_param.Get("engine", "emu_window");
118 112
119 ui->motion_provider->setCurrentIndex(
120 ui->motion_provider->findData(QString::fromStdString(motion_engine)));
121 ui->touch_provider->setCurrentIndex( 113 ui->touch_provider->setCurrentIndex(
122 ui->touch_provider->findData(QString::fromStdString(touch_engine))); 114 ui->touch_provider->findData(QString::fromStdString(touch_engine)));
123 ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button); 115 ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button);
@@ -133,23 +125,30 @@ void ConfigureMotionTouch::SetConfiguration() {
133 max_x = touch_param.Get("max_x", 1800); 125 max_x = touch_param.Get("max_x", 1800);
134 max_y = touch_param.Get("max_y", 850); 126 max_y = touch_param.Get("max_y", 850);
135 127
136 ui->udp_server->setText(QString::fromStdString(Settings::values.udp_input_address)); 128 ui->udp_server->setText(QString::fromStdString("127.0.0.1"));
137 ui->udp_port->setText(QString::number(Settings::values.udp_input_port)); 129 ui->udp_port->setText(QString::number(26760));
138 ui->udp_pad_index->setCurrentIndex(Settings::values.udp_pad_index); 130
131 udp_server_list_model = new QStringListModel(this);
132 udp_server_list_model->setStringList({});
133 ui->udp_server_list->setModel(udp_server_list_model);
134
135 std::stringstream ss(Settings::values.udp_input_servers);
136 std::string token;
137
138 while (std::getline(ss, token, ',')) {
139 const int row = udp_server_list_model->rowCount();
140 udp_server_list_model->insertRows(row, 1);
141 const QModelIndex index = udp_server_list_model->index(row);
142 udp_server_list_model->setData(index, QString::fromStdString(token));
143 }
139} 144}
140 145
141void ConfigureMotionTouch::UpdateUiDisplay() { 146void ConfigureMotionTouch::UpdateUiDisplay() {
142 const QString motion_engine = ui->motion_provider->currentData().toString();
143 const QString touch_engine = ui->touch_provider->currentData().toString(); 147 const QString touch_engine = ui->touch_provider->currentData().toString();
144 const QString cemuhook_udp = QStringLiteral("cemuhookudp"); 148 const QString cemuhook_udp = QStringLiteral("cemuhookudp");
145 149
146 if (motion_engine == QStringLiteral("motion_emu")) { 150 ui->motion_sensitivity_label->setVisible(true);
147 ui->motion_sensitivity_label->setVisible(true); 151 ui->motion_sensitivity->setVisible(true);
148 ui->motion_sensitivity->setVisible(true);
149 } else {
150 ui->motion_sensitivity_label->setVisible(false);
151 ui->motion_sensitivity->setVisible(false);
152 }
153 152
154 if (touch_engine == cemuhook_udp) { 153 if (touch_engine == cemuhook_udp) {
155 ui->touch_calibration->setVisible(true); 154 ui->touch_calibration->setVisible(true);
@@ -163,19 +162,15 @@ void ConfigureMotionTouch::UpdateUiDisplay() {
163 ui->touch_calibration_label->setVisible(false); 162 ui->touch_calibration_label->setVisible(false);
164 } 163 }
165 164
166 if (motion_engine == cemuhook_udp || touch_engine == cemuhook_udp) { 165 ui->udp_config_group_box->setVisible(true);
167 ui->udp_config_group_box->setVisible(true);
168 } else {
169 ui->udp_config_group_box->setVisible(false);
170 }
171} 166}
172 167
173void ConfigureMotionTouch::ConnectEvents() { 168void ConfigureMotionTouch::ConnectEvents() {
174 connect(ui->motion_provider, qOverload<int>(&QComboBox::currentIndexChanged), this,
175 [this](int index) { UpdateUiDisplay(); });
176 connect(ui->touch_provider, qOverload<int>(&QComboBox::currentIndexChanged), this, 169 connect(ui->touch_provider, qOverload<int>(&QComboBox::currentIndexChanged), this,
177 [this](int index) { UpdateUiDisplay(); }); 170 [this](int index) { UpdateUiDisplay(); });
178 connect(ui->udp_test, &QPushButton::clicked, this, &ConfigureMotionTouch::OnCemuhookUDPTest); 171 connect(ui->udp_test, &QPushButton::clicked, this, &ConfigureMotionTouch::OnCemuhookUDPTest);
172 connect(ui->udp_add, &QPushButton::clicked, this, &ConfigureMotionTouch::OnUDPAddServer);
173 connect(ui->udp_remove, &QPushButton::clicked, this, &ConfigureMotionTouch::OnUDPDeleteServer);
179 connect(ui->touch_calibration_config, &QPushButton::clicked, this, 174 connect(ui->touch_calibration_config, &QPushButton::clicked, this,
180 &ConfigureMotionTouch::OnConfigureTouchCalibration); 175 &ConfigureMotionTouch::OnConfigureTouchCalibration);
181 connect(ui->touch_from_button_config_btn, &QPushButton::clicked, this, 176 connect(ui->touch_from_button_config_btn, &QPushButton::clicked, this,
@@ -187,13 +182,58 @@ void ConfigureMotionTouch::ConnectEvents() {
187 }); 182 });
188} 183}
189 184
185void ConfigureMotionTouch::OnUDPAddServer() {
186 QRegExp re(tr("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?["
187 "0-9][0-9]?)$")); // a valid ip address
188 bool ok;
189 QString port_text = ui->udp_port->text();
190 QString server_text = ui->udp_server->text();
191 const QString server_string = tr("%1:%2").arg(server_text, port_text);
192 int port_number = port_text.toInt(&ok, 10);
193 int row = udp_server_list_model->rowCount();
194
195 if (!ok) {
196 QMessageBox::warning(this, tr("yuzu"), tr("Port number has invalid characters"));
197 return;
198 }
199 if (port_number < 0 || port_number > 65353) {
200 QMessageBox::warning(this, tr("yuzu"), tr("Port has to be in range 0 and 65353"));
201 return;
202 }
203 if (!re.exactMatch(server_text)) {
204 QMessageBox::warning(this, tr("yuzu"), tr("IP address is not valid"));
205 return;
206 }
207 // Search for duplicates
208 for (const auto& item : udp_server_list_model->stringList()) {
209 if (item == server_string) {
210 QMessageBox::warning(this, tr("yuzu"), tr("This UDP server already exists"));
211 return;
212 }
213 }
214 // Limit server count to 8
215 if (row == 8) {
216 QMessageBox::warning(this, tr("yuzu"), tr("Unable to add more than 8 servers"));
217 return;
218 }
219
220 udp_server_list_model->insertRows(row, 1);
221 QModelIndex index = udp_server_list_model->index(row);
222 udp_server_list_model->setData(index, server_string);
223 ui->udp_server_list->setCurrentIndex(index);
224}
225
226void ConfigureMotionTouch::OnUDPDeleteServer() {
227 udp_server_list_model->removeRows(ui->udp_server_list->currentIndex().row(), 1);
228}
229
190void ConfigureMotionTouch::OnCemuhookUDPTest() { 230void ConfigureMotionTouch::OnCemuhookUDPTest() {
191 ui->udp_test->setEnabled(false); 231 ui->udp_test->setEnabled(false);
192 ui->udp_test->setText(tr("Testing")); 232 ui->udp_test->setText(tr("Testing"));
193 udp_test_in_progress = true; 233 udp_test_in_progress = true;
194 InputCommon::CemuhookUDP::TestCommunication( 234 InputCommon::CemuhookUDP::TestCommunication(
195 ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 235 ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 0,
196 static_cast<u32>(ui->udp_pad_index->currentIndex()), 24872, 236 24872,
197 [this] { 237 [this] {
198 LOG_INFO(Frontend, "UDP input test success"); 238 LOG_INFO(Frontend, "UDP input test success");
199 QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true)); 239 QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true));
@@ -207,9 +247,9 @@ void ConfigureMotionTouch::OnCemuhookUDPTest() {
207void ConfigureMotionTouch::OnConfigureTouchCalibration() { 247void ConfigureMotionTouch::OnConfigureTouchCalibration() {
208 ui->touch_calibration_config->setEnabled(false); 248 ui->touch_calibration_config->setEnabled(false);
209 ui->touch_calibration_config->setText(tr("Configuring")); 249 ui->touch_calibration_config->setText(tr("Configuring"));
210 CalibrationConfigurationDialog dialog( 250 CalibrationConfigurationDialog dialog(this, ui->udp_server->text().toStdString(),
211 this, ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toUInt()), 251 static_cast<u16>(ui->udp_port->text().toUInt()), 0,
212 static_cast<u8>(ui->udp_pad_index->currentIndex()), 24872); 252 24872);
213 dialog.exec(); 253 dialog.exec();
214 if (dialog.completed) { 254 if (dialog.completed) {
215 min_x = dialog.min_x; 255 min_x = dialog.min_x;
@@ -269,7 +309,7 @@ void ConfigureMotionTouch::OnConfigureTouchFromButton() {
269 309
270bool ConfigureMotionTouch::CanCloseDialog() { 310bool ConfigureMotionTouch::CanCloseDialog() {
271 if (udp_test_in_progress) { 311 if (udp_test_in_progress) {
272 QMessageBox::warning(this, tr("Citra"), 312 QMessageBox::warning(this, tr("yuzu"),
273 tr("UDP Test or calibration configuration is in progress.<br>Please " 313 tr("UDP Test or calibration configuration is in progress.<br>Please "
274 "wait for them to finish.")); 314 "wait for them to finish."));
275 return false; 315 return false;
@@ -282,17 +322,11 @@ void ConfigureMotionTouch::ApplyConfiguration() {
282 return; 322 return;
283 } 323 }
284 324
285 std::string motion_engine = ui->motion_provider->currentData().toString().toStdString();
286 std::string touch_engine = ui->touch_provider->currentData().toString().toStdString(); 325 std::string touch_engine = ui->touch_provider->currentData().toString().toStdString();
287 326
288 Common::ParamPackage motion_param{}, touch_param{}; 327 Common::ParamPackage touch_param{};
289 motion_param.Set("engine", std::move(motion_engine));
290 touch_param.Set("engine", std::move(touch_engine)); 328 touch_param.Set("engine", std::move(touch_engine));
291 329
292 if (motion_engine == "motion_emu") {
293 motion_param.Set("sensitivity", static_cast<float>(ui->motion_sensitivity->value()));
294 }
295
296 if (touch_engine == "cemuhookudp") { 330 if (touch_engine == "cemuhookudp") {
297 touch_param.Set("min_x", min_x); 331 touch_param.Set("min_x", min_x);
298 touch_param.Set("min_y", min_y); 332 touch_param.Set("min_y", min_y);
@@ -300,15 +334,25 @@ void ConfigureMotionTouch::ApplyConfiguration() {
300 touch_param.Set("max_y", max_y); 334 touch_param.Set("max_y", max_y);
301 } 335 }
302 336
303 Settings::values.motion_device = motion_param.Serialize();
304 Settings::values.touch_device = touch_param.Serialize(); 337 Settings::values.touch_device = touch_param.Serialize();
305 Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked(); 338 Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked();
306 Settings::values.touch_from_button_map_index = ui->touch_from_button_map->currentIndex(); 339 Settings::values.touch_from_button_map_index = ui->touch_from_button_map->currentIndex();
307 Settings::values.touch_from_button_maps = touch_from_button_maps; 340 Settings::values.touch_from_button_maps = touch_from_button_maps;
308 Settings::values.udp_input_address = ui->udp_server->text().toStdString(); 341 Settings::values.udp_input_servers = GetUDPServerString();
309 Settings::values.udp_input_port = static_cast<u16>(ui->udp_port->text().toInt());
310 Settings::values.udp_pad_index = static_cast<u8>(ui->udp_pad_index->currentIndex());
311 input_subsystem->ReloadInputDevices(); 342 input_subsystem->ReloadInputDevices();
312 343
313 accept(); 344 accept();
314} 345}
346
347std::string ConfigureMotionTouch::GetUDPServerString() const {
348 QString input_servers;
349
350 for (const auto& item : udp_server_list_model->stringList()) {
351 input_servers += item;
352 input_servers += QLatin1Char{','};
353 }
354
355 // Remove last comma
356 input_servers.chop(1);
357 return input_servers.toStdString();
358}
diff --git a/src/yuzu/configuration/configure_motion_touch.h b/src/yuzu/configuration/configure_motion_touch.h
index 3d4b5d659..15d61e8ba 100644
--- a/src/yuzu/configuration/configure_motion_touch.h
+++ b/src/yuzu/configuration/configure_motion_touch.h
@@ -10,6 +10,7 @@
10 10
11class QLabel; 11class QLabel;
12class QPushButton; 12class QPushButton;
13class QStringListModel;
13class QVBoxLayout; 14class QVBoxLayout;
14 15
15namespace InputCommon { 16namespace InputCommon {
@@ -62,6 +63,8 @@ public slots:
62 void ApplyConfiguration(); 63 void ApplyConfiguration();
63 64
64private slots: 65private slots:
66 void OnUDPAddServer();
67 void OnUDPDeleteServer();
65 void OnCemuhookUDPTest(); 68 void OnCemuhookUDPTest();
66 void OnConfigureTouchCalibration(); 69 void OnConfigureTouchCalibration();
67 void OnConfigureTouchFromButton(); 70 void OnConfigureTouchFromButton();
@@ -73,10 +76,12 @@ private:
73 void UpdateUiDisplay(); 76 void UpdateUiDisplay();
74 void ConnectEvents(); 77 void ConnectEvents();
75 bool CanCloseDialog(); 78 bool CanCloseDialog();
79 std::string GetUDPServerString() const;
76 80
77 InputCommon::InputSubsystem* input_subsystem; 81 InputCommon::InputSubsystem* input_subsystem;
78 82
79 std::unique_ptr<Ui::ConfigureMotionTouch> ui; 83 std::unique_ptr<Ui::ConfigureMotionTouch> ui;
84 QStringListModel* udp_server_list_model;
80 85
81 // Coordinate system of the CemuhookUDP touch provider 86 // Coordinate system of the CemuhookUDP touch provider
82 int min_x{}; 87 int min_x{};
diff --git a/src/yuzu/configuration/configure_motion_touch.ui b/src/yuzu/configuration/configure_motion_touch.ui
index 5b78c5a4b..ebca835ac 100644
--- a/src/yuzu/configuration/configure_motion_touch.ui
+++ b/src/yuzu/configuration/configure_motion_touch.ui
@@ -2,41 +2,30 @@
2<ui version="4.0"> 2<ui version="4.0">
3 <class>ConfigureMotionTouch</class> 3 <class>ConfigureMotionTouch</class>
4 <widget class="QDialog" name="ConfigureMotionTouch"> 4 <widget class="QDialog" name="ConfigureMotionTouch">
5 <property name="windowTitle">
6 <string>Configure Motion / Touch</string>
7 </property>
8 <property name="geometry"> 5 <property name="geometry">
9 <rect> 6 <rect>
10 <x>0</x> 7 <x>0</x>
11 <y>0</y> 8 <y>0</y>
12 <width>500</width> 9 <width>500</width>
13 <height>450</height> 10 <height>482</height>
14 </rect> 11 </rect>
15 </property> 12 </property>
13 <property name="windowTitle">
14 <string>Configure Motion / Touch</string>
15 </property>
16 <property name="styleSheet">
17 <string notr="true"/>
18 </property>
16 <layout class="QVBoxLayout"> 19 <layout class="QVBoxLayout">
17 <item> 20 <item>
18 <widget class="QGroupBox" name="motion_group_box"> 21 <widget class="QGroupBox" name="motion_group_box">
19 <property name="title"> 22 <property name="title">
20 <string>Motion</string> 23 <string>Mouse Motion</string>
21 </property> 24 </property>
22 <layout class="QVBoxLayout"> 25 <layout class="QVBoxLayout">
23 <item> 26 <item>
24 <layout class="QHBoxLayout"> 27 <layout class="QHBoxLayout">
25 <item> 28 <item>
26 <widget class="QLabel" name="motion_provider_label">
27 <property name="text">
28 <string>Motion Provider:</string>
29 </property>
30 </widget>
31 </item>
32 <item>
33 <widget class="QComboBox" name="motion_provider"/>
34 </item>
35 </layout>
36 </item>
37 <item>
38 <layout class="QHBoxLayout">
39 <item>
40 <widget class="QLabel" name="motion_sensitivity_label"> 29 <widget class="QLabel" name="motion_sensitivity_label">
41 <property name="text"> 30 <property name="text">
42 <string>Sensitivity:</string> 31 <string>Sensitivity:</string>
@@ -180,103 +169,171 @@
180 </widget> 169 </widget>
181 </item> 170 </item>
182 <item> 171 <item>
183 <layout class="QHBoxLayout"> 172 <layout class="QHBoxLayout" name="horizontalLayout">
184 <item> 173 <item>
185 <widget class="QLabel" name="udp_server_label"> 174 <widget class="QListView" name="udp_server_list"/>
186 <property name="text">
187 <string>Server:</string>
188 </property>
189 </widget>
190 </item> 175 </item>
191 <item> 176 <item>
192 <widget class="QLineEdit" name="udp_server"> 177 <layout class="QVBoxLayout" name="verticalLayout">
193 <property name="sizePolicy"> 178 <property name="leftMargin">
194 <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> 179 <number>0</number>
195 <horstretch>0</horstretch>
196 <verstretch>0</verstretch>
197 </sizepolicy>
198 </property> 180 </property>
199 </widget> 181 <property name="topMargin">
200 </item> 182 <number>0</number>
201 </layout>
202 </item>
203 <item>
204 <layout class="QHBoxLayout">
205 <item>
206 <widget class="QLabel" name="udp_port_label">
207 <property name="text">
208 <string>Port:</string>
209 </property> 183 </property>
210 </widget> 184 <property name="rightMargin">
211 </item> 185 <number>0</number>
212 <item>
213 <widget class="QLineEdit" name="udp_port">
214 <property name="sizePolicy">
215 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
216 <horstretch>0</horstretch>
217 <verstretch>0</verstretch>
218 </sizepolicy>
219 </property> 186 </property>
220 </widget> 187 <property name="bottomMargin">
221 </item> 188 <number>0</number>
222 </layout>
223 </item>
224 <item>
225 <layout class="QHBoxLayout">
226 <item>
227 <widget class="QLabel" name="udp_pad_index_label">
228 <property name="text">
229 <string>Pad:</string>
230 </property> 189 </property>
231 </widget>
232 </item>
233 <item>
234 <widget class="QComboBox" name="udp_pad_index">
235 <item> 190 <item>
236 <property name="text"> 191 <layout class="QHBoxLayout">
237 <string>Pad 1</string> 192 <property name="leftMargin">
238 </property> 193 <number>3</number>
194 </property>
195 <property name="topMargin">
196 <number>3</number>
197 </property>
198 <property name="rightMargin">
199 <number>0</number>
200 </property>
201 <item>
202 <widget class="QLabel" name="udp_server_label">
203 <property name="text">
204 <string>Server:</string>
205 </property>
206 </widget>
207 </item>
208 <item>
209 <widget class="QLineEdit" name="udp_server">
210 <property name="sizePolicy">
211 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
212 <horstretch>0</horstretch>
213 <verstretch>0</verstretch>
214 </sizepolicy>
215 </property>
216 </widget>
217 </item>
218 </layout>
239 </item> 219 </item>
240 <item> 220 <item>
241 <property name="text"> 221 <layout class="QHBoxLayout">
242 <string>Pad 2</string> 222 <property name="leftMargin">
243 </property> 223 <number>3</number>
224 </property>
225 <property name="rightMargin">
226 <number>0</number>
227 </property>
228 <item>
229 <widget class="QLabel" name="udp_port_label">
230 <property name="text">
231 <string>Port:</string>
232 </property>
233 </widget>
234 </item>
235 <item>
236 <widget class="QLineEdit" name="udp_port">
237 <property name="sizePolicy">
238 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
239 <horstretch>0</horstretch>
240 <verstretch>0</verstretch>
241 </sizepolicy>
242 </property>
243 </widget>
244 </item>
245 </layout>
244 </item> 246 </item>
245 <item> 247 <item>
246 <property name="text"> 248 <layout class="QHBoxLayout">
247 <string>Pad 3</string> 249 <property name="leftMargin">
248 </property> 250 <number>3</number>
251 </property>
252 <property name="rightMargin">
253 <number>0</number>
254 </property>
255 <item>
256 <widget class="QLabel" name="udp_learn_more">
257 <property name="text">
258 <string>Learn More</string>
259 </property>
260 </widget>
261 </item>
262 <item>
263 <widget class="QPushButton" name="udp_test">
264 <property name="sizePolicy">
265 <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
266 <horstretch>0</horstretch>
267 <verstretch>0</verstretch>
268 </sizepolicy>
269 </property>
270 <property name="text">
271 <string>Test</string>
272 </property>
273 </widget>
274 </item>
275 <item>
276 <widget class="QPushButton" name="udp_add">
277 <property name="sizePolicy">
278 <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
279 <horstretch>0</horstretch>
280 <verstretch>0</verstretch>
281 </sizepolicy>
282 </property>
283 <property name="text">
284 <string>Add Server</string>
285 </property>
286 </widget>
287 </item>
288 </layout>
249 </item> 289 </item>
250 <item> 290 <item>
251 <property name="text"> 291 <spacer name="verticalSpacer_3">
252 <string>Pad 4</string> 292 <property name="orientation">
253 </property> 293 <enum>Qt::Vertical</enum>
294 </property>
295 <property name="sizeHint" stdset="0">
296 <size>
297 <width>20</width>
298 <height>40</height>
299 </size>
300 </property>
301 </spacer>
254 </item> 302 </item>
255 </widget> 303 <item>
256 </item> 304 <layout class="QHBoxLayout" name="horizontalLayout_2">
257 </layout> 305 <property name="topMargin">
258 </item> 306 <number>0</number>
259 <item> 307 </property>
260 <layout class="QHBoxLayout"> 308 <item>
261 <item> 309 <widget class="QPushButton" name="udp_remove">
262 <widget class="QLabel" name="udp_learn_more"> 310 <property name="sizePolicy">
263 <property name="text"> 311 <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
264 <string>Learn More</string> 312 <horstretch>0</horstretch>
265 </property> 313 <verstretch>0</verstretch>
266 </widget> 314 </sizepolicy>
267 </item> 315 </property>
268 <item> 316 <property name="text">
269 <widget class="QPushButton" name="udp_test"> 317 <string>Remove Server</string>
270 <property name="sizePolicy"> 318 </property>
271 <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> 319 </widget>
272 <horstretch>0</horstretch> 320 </item>
273 <verstretch>0</verstretch> 321 <item>
274 </sizepolicy> 322 <spacer name="horizontalSpacer_2">
275 </property> 323 <property name="orientation">
276 <property name="text"> 324 <enum>Qt::Horizontal</enum>
277 <string>Test</string> 325 </property>
278 </property> 326 <property name="sizeHint" stdset="0">
279 </widget> 327 <size>
328 <width>40</width>
329 <height>20</height>
330 </size>
331 </property>
332 </spacer>
333 </item>
334 </layout>
335 </item>
336 </layout>
280 </item> 337 </item>
281 </layout> 338 </layout>
282 </item> 339 </item>
@@ -312,6 +369,16 @@
312 <signal>accepted()</signal> 369 <signal>accepted()</signal>
313 <receiver>ConfigureMotionTouch</receiver> 370 <receiver>ConfigureMotionTouch</receiver>
314 <slot>ApplyConfiguration()</slot> 371 <slot>ApplyConfiguration()</slot>
372 <hints>
373 <hint type="sourcelabel">
374 <x>20</x>
375 <y>20</y>
376 </hint>
377 <hint type="destinationlabel">
378 <x>20</x>
379 <y>20</y>
380 </hint>
381 </hints>
315 </connection> 382 </connection>
316 </connections> 383 </connections>
317</ui> 384</ui>
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index e1adbbf2b..34c9673bc 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -306,10 +306,8 @@ void Config::ReadValues() {
306 sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_x", 15); 306 sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_x", 15);
307 Settings::values.touchscreen.diameter_y = 307 Settings::values.touchscreen.diameter_y =
308 sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_y", 15); 308 sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_y", 15);
309 Settings::values.udp_input_address = 309 Settings::values.udp_input_servers =
310 sdl2_config->Get("Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_ADDR); 310 sdl2_config->Get("Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_SRV);
311 Settings::values.udp_input_port = static_cast<u16>(sdl2_config->GetInteger(
312 "Controls", "udp_input_port", InputCommon::CemuhookUDP::DEFAULT_PORT));
313 311
314 std::transform(keyboard_keys.begin(), keyboard_keys.end(), 312 std::transform(keyboard_keys.begin(), keyboard_keys.end(),
315 Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam); 313 Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);