diff options
Diffstat (limited to '')
| -rw-r--r-- | src/input_common/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | src/input_common/drivers/udp_client.cpp (renamed from src/input_common/udp/client.cpp) | 242 | ||||
| -rw-r--r-- | src/input_common/drivers/udp_client.h (renamed from src/input_common/udp/client.h) | 80 | ||||
| -rw-r--r-- | src/input_common/udp/udp.cpp | 110 | ||||
| -rw-r--r-- | src/input_common/udp/udp.h | 57 |
5 files changed, 54 insertions, 441 deletions
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 19270dc84..9c0c82138 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt | |||
| @@ -9,6 +9,8 @@ add_library(input_common STATIC | |||
| 9 | drivers/tas_input.h | 9 | drivers/tas_input.h |
| 10 | drivers/touch_screen.cpp | 10 | drivers/touch_screen.cpp |
| 11 | drivers/touch_screen.h | 11 | drivers/touch_screen.h |
| 12 | drivers/udp_client.cpp | ||
| 13 | drivers/udp_client.h | ||
| 12 | helpers/stick_from_buttons.cpp | 14 | helpers/stick_from_buttons.cpp |
| 13 | helpers/stick_from_buttons.h | 15 | helpers/stick_from_buttons.h |
| 14 | helpers/touch_from_buttons.cpp | 16 | helpers/touch_from_buttons.cpp |
| @@ -29,10 +31,6 @@ add_library(input_common STATIC | |||
| 29 | motion_input.h | 31 | motion_input.h |
| 30 | sdl/sdl.cpp | 32 | sdl/sdl.cpp |
| 31 | sdl/sdl.h | 33 | sdl/sdl.h |
| 32 | udp/client.cpp | ||
| 33 | udp/client.h | ||
| 34 | udp/udp.cpp | ||
| 35 | udp/udp.h | ||
| 36 | ) | 34 | ) |
| 37 | 35 | ||
| 38 | if (MSVC) | 36 | if (MSVC) |
diff --git a/src/input_common/udp/client.cpp b/src/input_common/drivers/udp_client.cpp index bcc29c4e0..6fcc3a01b 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/drivers/udp_client.cpp | |||
| @@ -2,15 +2,13 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <chrono> | ||
| 6 | #include <cstring> | ||
| 7 | #include <functional> | ||
| 8 | #include <random> | 5 | #include <random> |
| 9 | #include <thread> | ||
| 10 | #include <boost/asio.hpp> | 6 | #include <boost/asio.hpp> |
| 7 | |||
| 11 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "common/param_package.h" | ||
| 12 | #include "common/settings.h" | 10 | #include "common/settings.h" |
| 13 | #include "input_common/udp/client.h" | 11 | #include "input_common/drivers/udp_client.h" |
| 14 | #include "input_common/helpers/udp_protocol.h" | 12 | #include "input_common/helpers/udp_protocol.h" |
| 15 | 13 | ||
| 16 | using boost::asio::ip::udp; | 14 | using boost::asio::ip::udp; |
| @@ -86,7 +84,6 @@ private: | |||
| 86 | case Type::PadData: { | 84 | case Type::PadData: { |
| 87 | Response::PadData pad_data; | 85 | Response::PadData pad_data; |
| 88 | std::memcpy(&pad_data, &receive_buffer[sizeof(Header)], sizeof(Response::PadData)); | 86 | std::memcpy(&pad_data, &receive_buffer[sizeof(Header)], sizeof(Response::PadData)); |
| 89 | SanitizeMotion(pad_data); | ||
| 90 | callback.pad_data(std::move(pad_data)); | 87 | callback.pad_data(std::move(pad_data)); |
| 91 | break; | 88 | break; |
| 92 | } | 89 | } |
| @@ -115,28 +112,6 @@ private: | |||
| 115 | StartSend(timer.expiry()); | 112 | StartSend(timer.expiry()); |
| 116 | } | 113 | } |
| 117 | 114 | ||
| 118 | void SanitizeMotion(Response::PadData& data) { | ||
| 119 | // Zero out any non number value | ||
| 120 | if (!std::isnormal(data.gyro.pitch)) { | ||
| 121 | data.gyro.pitch = 0; | ||
| 122 | } | ||
| 123 | if (!std::isnormal(data.gyro.roll)) { | ||
| 124 | data.gyro.roll = 0; | ||
| 125 | } | ||
| 126 | if (!std::isnormal(data.gyro.yaw)) { | ||
| 127 | data.gyro.yaw = 0; | ||
| 128 | } | ||
| 129 | if (!std::isnormal(data.accel.x)) { | ||
| 130 | data.accel.x = 0; | ||
| 131 | } | ||
| 132 | if (!std::isnormal(data.accel.y)) { | ||
| 133 | data.accel.y = 0; | ||
| 134 | } | ||
| 135 | if (!std::isnormal(data.accel.z)) { | ||
| 136 | data.accel.z = 0; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | SocketCallback callback; | 115 | SocketCallback callback; |
| 141 | boost::asio::io_service io_service; | 116 | boost::asio::io_service io_service; |
| 142 | boost::asio::basic_waitable_timer<clock> timer; | 117 | boost::asio::basic_waitable_timer<clock> timer; |
| @@ -160,48 +135,23 @@ static void SocketLoop(Socket* socket) { | |||
| 160 | socket->Loop(); | 135 | socket->Loop(); |
| 161 | } | 136 | } |
| 162 | 137 | ||
| 163 | Client::Client() { | 138 | UDPClient::UDPClient(const std::string& input_engine_) : InputEngine(input_engine_) { |
| 164 | LOG_INFO(Input, "Udp Initialization started"); | 139 | LOG_INFO(Input, "Udp Initialization started"); |
| 165 | finger_id.fill(MAX_TOUCH_FINGERS); | ||
| 166 | ReloadSockets(); | 140 | ReloadSockets(); |
| 167 | } | 141 | } |
| 168 | 142 | ||
| 169 | Client::~Client() { | 143 | UDPClient::~UDPClient() { |
| 170 | Reset(); | 144 | Reset(); |
| 171 | } | 145 | } |
| 172 | 146 | ||
| 173 | Client::ClientConnection::ClientConnection() = default; | 147 | UDPClient::ClientConnection::ClientConnection() = default; |
| 174 | 148 | ||
| 175 | Client::ClientConnection::~ClientConnection() = default; | 149 | UDPClient::ClientConnection::~ClientConnection() = default; |
| 176 | |||
| 177 | std::vector<Common::ParamPackage> Client::GetInputDevices() const { | ||
| 178 | std::vector<Common::ParamPackage> devices; | ||
| 179 | for (std::size_t pad = 0; pad < pads.size(); pad++) { | ||
| 180 | if (!DeviceConnected(pad)) { | ||
| 181 | continue; | ||
| 182 | } | ||
| 183 | std::string name = fmt::format("UDP Controller {}", pad); | ||
| 184 | devices.emplace_back(Common::ParamPackage{ | ||
| 185 | {"class", "cemuhookudp"}, | ||
| 186 | {"display", std::move(name)}, | ||
| 187 | {"port", std::to_string(pad)}, | ||
| 188 | }); | ||
| 189 | } | ||
| 190 | return devices; | ||
| 191 | } | ||
| 192 | |||
| 193 | bool Client::DeviceConnected(std::size_t pad) const { | ||
| 194 | // Use last timestamp to detect if the socket has stopped sending data | ||
| 195 | const auto now = std::chrono::steady_clock::now(); | ||
| 196 | const auto time_difference = static_cast<u64>( | ||
| 197 | std::chrono::duration_cast<std::chrono::milliseconds>(now - pads[pad].last_update).count()); | ||
| 198 | return time_difference < 1000 && pads[pad].connected; | ||
| 199 | } | ||
| 200 | 150 | ||
| 201 | void Client::ReloadSockets() { | 151 | void UDPClient::ReloadSockets() { |
| 202 | Reset(); | 152 | Reset(); |
| 203 | 153 | ||
| 204 | std::stringstream servers_ss(static_cast<std::string>(Settings::values.udp_input_servers)); | 154 | std::stringstream servers_ss(Settings::values.udp_input_servers.GetValue()); |
| 205 | std::string server_token; | 155 | std::string server_token; |
| 206 | std::size_t client = 0; | 156 | std::size_t client = 0; |
| 207 | while (std::getline(servers_ss, server_token, ',')) { | 157 | while (std::getline(servers_ss, server_token, ',')) { |
| @@ -229,7 +179,7 @@ void Client::ReloadSockets() { | |||
| 229 | } | 179 | } |
| 230 | } | 180 | } |
| 231 | 181 | ||
| 232 | std::size_t Client::GetClientNumber(std::string_view host, u16 port) const { | 182 | std::size_t UDPClient::GetClientNumber(std::string_view host, u16 port) const { |
| 233 | for (std::size_t client = 0; client < clients.size(); client++) { | 183 | for (std::size_t client = 0; client < clients.size(); client++) { |
| 234 | if (clients[client].active == -1) { | 184 | if (clients[client].active == -1) { |
| 235 | continue; | 185 | continue; |
| @@ -241,15 +191,15 @@ std::size_t Client::GetClientNumber(std::string_view host, u16 port) const { | |||
| 241 | return MAX_UDP_CLIENTS; | 191 | return MAX_UDP_CLIENTS; |
| 242 | } | 192 | } |
| 243 | 193 | ||
| 244 | void Client::OnVersion([[maybe_unused]] Response::Version data) { | 194 | void UDPClient::OnVersion([[maybe_unused]] Response::Version data) { |
| 245 | LOG_TRACE(Input, "Version packet received: {}", data.version); | 195 | LOG_TRACE(Input, "Version packet received: {}", data.version); |
| 246 | } | 196 | } |
| 247 | 197 | ||
| 248 | void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) { | 198 | void UDPClient::OnPortInfo([[maybe_unused]] Response::PortInfo data) { |
| 249 | LOG_TRACE(Input, "PortInfo packet received: {}", data.model); | 199 | LOG_TRACE(Input, "PortInfo packet received: {}", data.model); |
| 250 | } | 200 | } |
| 251 | 201 | ||
| 252 | void Client::OnPadData(Response::PadData data, std::size_t client) { | 202 | void UDPClient::OnPadData(Response::PadData data, std::size_t client) { |
| 253 | const std::size_t pad_index = (client * PADS_PER_CLIENT) + data.info.id; | 203 | const std::size_t pad_index = (client * PADS_PER_CLIENT) + data.info.id; |
| 254 | 204 | ||
| 255 | if (pad_index >= pads.size()) { | 205 | if (pad_index >= pads.size()) { |
| @@ -277,32 +227,25 @@ void Client::OnPadData(Response::PadData data, std::size_t client) { | |||
| 277 | .count()); | 227 | .count()); |
| 278 | pads[pad_index].last_update = now; | 228 | pads[pad_index].last_update = now; |
| 279 | 229 | ||
| 280 | const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw}; | ||
| 281 | pads[pad_index].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y}); | ||
| 282 | // Gyroscope values are not it the correct scale from better joy. | 230 | // Gyroscope values are not it the correct scale from better joy. |
| 283 | // Dividing by 312 allows us to make one full turn = 1 turn | 231 | // Dividing by 312 allows us to make one full turn = 1 turn |
| 284 | // This must be a configurable valued called sensitivity | 232 | // This must be a configurable valued called sensitivity |
| 285 | pads[pad_index].motion.SetGyroscope(raw_gyroscope / 312.0f); | 233 | const float gyro_scale = 1.0f / 312.0f; |
| 286 | pads[pad_index].motion.UpdateRotation(time_difference); | 234 | |
| 287 | pads[pad_index].motion.UpdateOrientation(time_difference); | 235 | const BasicMotion motion{ |
| 288 | 236 | .gyro_x = data.gyro.pitch * gyro_scale, | |
| 289 | { | 237 | .gyro_y = data.gyro.roll * gyro_scale, |
| 290 | std::lock_guard guard(pads[pad_index].status.update_mutex); | 238 | .gyro_z = -data.gyro.yaw * gyro_scale, |
| 291 | pads[pad_index].status.motion_status = pads[pad_index].motion.GetMotion(); | 239 | .accel_x = data.accel.x, |
| 292 | 240 | .accel_y = -data.accel.z, | |
| 293 | for (std::size_t id = 0; id < data.touch.size(); ++id) { | 241 | .accel_z = data.accel.y, |
| 294 | UpdateTouchInput(data.touch[id], client, id); | 242 | .delta_timestamp = time_difference, |
| 295 | } | 243 | }; |
| 296 | 244 | const PadIdentifier identifier = GetPadIdentifier(pad_index); | |
| 297 | if (configuring) { | 245 | SetMotion(identifier, 0, motion); |
| 298 | const Common::Vec3f gyroscope = pads[pad_index].motion.GetGyroscope(); | ||
| 299 | const Common::Vec3f accelerometer = pads[pad_index].motion.GetAcceleration(); | ||
| 300 | UpdateYuzuSettings(client, data.info.id, accelerometer, gyroscope); | ||
| 301 | } | ||
| 302 | } | ||
| 303 | } | 246 | } |
| 304 | 247 | ||
| 305 | void Client::StartCommunication(std::size_t client, const std::string& host, u16 port) { | 248 | void UDPClient::StartCommunication(std::size_t client, const std::string& host, u16 port) { |
| 306 | SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, | 249 | SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, |
| 307 | [this](Response::PortInfo info) { OnPortInfo(info); }, | 250 | [this](Response::PortInfo info) { OnPortInfo(info); }, |
| 308 | [this, client](Response::PadData data) { OnPadData(data, client); }}; | 251 | [this, client](Response::PadData data) { OnPadData(data, client); }}; |
| @@ -312,16 +255,22 @@ void Client::StartCommunication(std::size_t client, const std::string& host, u16 | |||
| 312 | clients[client].active = 0; | 255 | clients[client].active = 0; |
| 313 | clients[client].socket = std::make_unique<Socket>(host, port, callback); | 256 | clients[client].socket = std::make_unique<Socket>(host, port, callback); |
| 314 | clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; | 257 | clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; |
| 315 | 258 | for (std::size_t index = 0; index < PADS_PER_CLIENT; ++index) { | |
| 316 | // Set motion parameters | 259 | const PadIdentifier identifier = GetPadIdentifier(client * PADS_PER_CLIENT + index); |
| 317 | // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode | 260 | PreSetController(identifier); |
| 318 | // Real HW values are unknown, 0.0001 is an approximate to Standard | ||
| 319 | for (std::size_t pad = 0; pad < PADS_PER_CLIENT; pad++) { | ||
| 320 | pads[client * PADS_PER_CLIENT + pad].motion.SetGyroThreshold(0.0001f); | ||
| 321 | } | 261 | } |
| 322 | } | 262 | } |
| 323 | 263 | ||
| 324 | void Client::Reset() { | 264 | const PadIdentifier UDPClient::GetPadIdentifier(std::size_t pad_index) const { |
| 265 | const std::size_t client = pad_index / PADS_PER_CLIENT; | ||
| 266 | return { | ||
| 267 | .guid = Common::UUID{clients[client].host}, | ||
| 268 | .port = static_cast<std::size_t>(clients[client].port), | ||
| 269 | .pad = pad_index, | ||
| 270 | }; | ||
| 271 | } | ||
| 272 | |||
| 273 | void UDPClient::Reset() { | ||
| 325 | for (auto& client : clients) { | 274 | for (auto& client : clients) { |
| 326 | if (client.thread.joinable()) { | 275 | if (client.thread.joinable()) { |
| 327 | client.active = -1; | 276 | client.active = -1; |
| @@ -331,117 +280,6 @@ void Client::Reset() { | |||
| 331 | } | 280 | } |
| 332 | } | 281 | } |
| 333 | 282 | ||
| 334 | void Client::UpdateYuzuSettings(std::size_t client, std::size_t pad_index, | ||
| 335 | const Common::Vec3<float>& acc, const Common::Vec3<float>& gyro) { | ||
| 336 | if (gyro.Length() > 0.2f) { | ||
| 337 | LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client, | ||
| 338 | gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]); | ||
| 339 | } | ||
| 340 | UDPPadStatus pad{ | ||
| 341 | .host = clients[client].host, | ||
| 342 | .port = clients[client].port, | ||
| 343 | .pad_index = pad_index, | ||
| 344 | }; | ||
| 345 | for (std::size_t i = 0; i < 3; ++i) { | ||
| 346 | if (gyro[i] > 5.0f || gyro[i] < -5.0f) { | ||
| 347 | pad.motion = static_cast<PadMotion>(i); | ||
| 348 | pad.motion_value = gyro[i]; | ||
| 349 | pad_queue.Push(pad); | ||
| 350 | } | ||
| 351 | if (acc[i] > 1.75f || acc[i] < -1.75f) { | ||
| 352 | pad.motion = static_cast<PadMotion>(i + 3); | ||
| 353 | pad.motion_value = acc[i]; | ||
| 354 | pad_queue.Push(pad); | ||
| 355 | } | ||
| 356 | } | ||
| 357 | } | ||
| 358 | |||
| 359 | std::optional<std::size_t> Client::GetUnusedFingerID() const { | ||
| 360 | std::size_t first_free_id = 0; | ||
| 361 | while (first_free_id < MAX_TOUCH_FINGERS) { | ||
| 362 | if (!std::get<2>(touch_status[first_free_id])) { | ||
| 363 | return first_free_id; | ||
| 364 | } else { | ||
| 365 | first_free_id++; | ||
| 366 | } | ||
| 367 | } | ||
| 368 | return std::nullopt; | ||
| 369 | } | ||
| 370 | |||
| 371 | void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id) { | ||
| 372 | // TODO: Use custom calibration per device | ||
| 373 | const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue()); | ||
| 374 | const u16 min_x = static_cast<u16>(touch_param.Get("min_x", 100)); | ||
| 375 | const u16 min_y = static_cast<u16>(touch_param.Get("min_y", 50)); | ||
| 376 | const u16 max_x = static_cast<u16>(touch_param.Get("max_x", 1800)); | ||
| 377 | const u16 max_y = static_cast<u16>(touch_param.Get("max_y", 850)); | ||
| 378 | const std::size_t touch_id = client * 2 + id; | ||
| 379 | if (touch_pad.is_active) { | ||
| 380 | if (finger_id[touch_id] == MAX_TOUCH_FINGERS) { | ||
| 381 | const auto first_free_id = GetUnusedFingerID(); | ||
| 382 | if (!first_free_id) { | ||
| 383 | // Invalid finger id skip to next input | ||
| 384 | return; | ||
| 385 | } | ||
| 386 | finger_id[touch_id] = *first_free_id; | ||
| 387 | } | ||
| 388 | auto& [x, y, pressed] = touch_status[finger_id[touch_id]]; | ||
| 389 | x = static_cast<float>(std::clamp(static_cast<u16>(touch_pad.x), min_x, max_x) - min_x) / | ||
| 390 | static_cast<float>(max_x - min_x); | ||
| 391 | y = static_cast<float>(std::clamp(static_cast<u16>(touch_pad.y), min_y, max_y) - min_y) / | ||
| 392 | static_cast<float>(max_y - min_y); | ||
| 393 | pressed = true; | ||
| 394 | return; | ||
| 395 | } | ||
| 396 | |||
| 397 | if (finger_id[touch_id] != MAX_TOUCH_FINGERS) { | ||
| 398 | touch_status[finger_id[touch_id]] = {}; | ||
| 399 | finger_id[touch_id] = MAX_TOUCH_FINGERS; | ||
| 400 | } | ||
| 401 | } | ||
| 402 | |||
| 403 | void Client::BeginConfiguration() { | ||
| 404 | pad_queue.Clear(); | ||
| 405 | configuring = true; | ||
| 406 | } | ||
| 407 | |||
| 408 | void Client::EndConfiguration() { | ||
| 409 | pad_queue.Clear(); | ||
| 410 | configuring = false; | ||
| 411 | } | ||
| 412 | |||
| 413 | DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { | ||
| 414 | const std::size_t client_number = GetClientNumber(host, port); | ||
| 415 | if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) { | ||
| 416 | return pads[0].status; | ||
| 417 | } | ||
| 418 | return pads[(client_number * PADS_PER_CLIENT) + pad].status; | ||
| 419 | } | ||
| 420 | |||
| 421 | const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { | ||
| 422 | const std::size_t client_number = GetClientNumber(host, port); | ||
| 423 | if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) { | ||
| 424 | return pads[0].status; | ||
| 425 | } | ||
| 426 | return pads[(client_number * PADS_PER_CLIENT) + pad].status; | ||
| 427 | } | ||
| 428 | |||
| 429 | Input::TouchStatus& Client::GetTouchState() { | ||
| 430 | return touch_status; | ||
| 431 | } | ||
| 432 | |||
| 433 | const Input::TouchStatus& Client::GetTouchState() const { | ||
| 434 | return touch_status; | ||
| 435 | } | ||
| 436 | |||
| 437 | Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() { | ||
| 438 | return pad_queue; | ||
| 439 | } | ||
| 440 | |||
| 441 | const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const { | ||
| 442 | return pad_queue; | ||
| 443 | } | ||
| 444 | |||
| 445 | void TestCommunication(const std::string& host, u16 port, | 283 | void TestCommunication(const std::string& host, u16 port, |
| 446 | const std::function<void()>& success_callback, | 284 | const std::function<void()>& success_callback, |
| 447 | const std::function<void()>& failure_callback) { | 285 | const std::function<void()>& failure_callback) { |
diff --git a/src/input_common/udp/client.h b/src/input_common/drivers/udp_client.h index 380f9bb76..58b2e921d 100644 --- a/src/input_common/udp/client.h +++ b/src/input_common/drivers/udp_client.h | |||
| @@ -1,23 +1,14 @@ | |||
| 1 | // Copyright 2018 Citra Emulator Project | 1 | // Copyright 2021 yuzu Emulator Project |
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included |
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <functional> | ||
| 8 | #include <memory> | ||
| 9 | #include <mutex> | ||
| 10 | #include <optional> | 7 | #include <optional> |
| 11 | #include <string> | 8 | |
| 12 | #include <thread> | ||
| 13 | #include <tuple> | ||
| 14 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 15 | #include "common/param_package.h" | ||
| 16 | #include "common/thread.h" | 10 | #include "common/thread.h" |
| 17 | #include "common/threadsafe_queue.h" | 11 | #include "input_common/input_engine.h" |
| 18 | #include "common/vector_math.h" | ||
| 19 | #include "core/frontend/input.h" | ||
| 20 | #include "input_common/motion_input.h" | ||
| 21 | 12 | ||
| 22 | namespace InputCommon::CemuhookUDP { | 13 | namespace InputCommon::CemuhookUDP { |
| 23 | 14 | ||
| @@ -30,16 +21,6 @@ struct TouchPad; | |||
| 30 | struct Version; | 21 | struct Version; |
| 31 | } // namespace Response | 22 | } // namespace Response |
| 32 | 23 | ||
| 33 | enum class PadMotion { | ||
| 34 | GyroX, | ||
| 35 | GyroY, | ||
| 36 | GyroZ, | ||
| 37 | AccX, | ||
| 38 | AccY, | ||
| 39 | AccZ, | ||
| 40 | Undefined, | ||
| 41 | }; | ||
| 42 | |||
| 43 | enum class PadTouch { | 24 | enum class PadTouch { |
| 44 | Click, | 25 | Click, |
| 45 | Undefined, | 26 | Undefined, |
| @@ -49,14 +30,10 @@ struct UDPPadStatus { | |||
| 49 | std::string host{"127.0.0.1"}; | 30 | std::string host{"127.0.0.1"}; |
| 50 | u16 port{26760}; | 31 | u16 port{26760}; |
| 51 | std::size_t pad_index{}; | 32 | std::size_t pad_index{}; |
| 52 | PadMotion motion{PadMotion::Undefined}; | ||
| 53 | f32 motion_value{0.0f}; | ||
| 54 | }; | 33 | }; |
| 55 | 34 | ||
| 56 | struct DeviceStatus { | 35 | struct DeviceStatus { |
| 57 | std::mutex update_mutex; | 36 | std::mutex update_mutex; |
| 58 | Input::MotionStatus motion_status; | ||
| 59 | std::tuple<float, float, bool> touch_status; | ||
| 60 | 37 | ||
| 61 | // calibration data for scaling the device's touch area to 3ds | 38 | // calibration data for scaling the device's touch area to 3ds |
| 62 | struct CalibrationData { | 39 | struct CalibrationData { |
| @@ -68,32 +45,17 @@ struct DeviceStatus { | |||
| 68 | std::optional<CalibrationData> touch_calibration; | 45 | std::optional<CalibrationData> touch_calibration; |
| 69 | }; | 46 | }; |
| 70 | 47 | ||
| 71 | class Client { | 48 | /** |
| 49 | * A button device factory representing a keyboard. It receives keyboard events and forward them | ||
| 50 | * to all button devices it created. | ||
| 51 | */ | ||
| 52 | class UDPClient final : public InputCommon::InputEngine { | ||
| 72 | public: | 53 | public: |
| 73 | // Initialize the UDP client capture and read sequence | 54 | explicit UDPClient(const std::string& input_engine_); |
| 74 | Client(); | 55 | ~UDPClient(); |
| 75 | |||
| 76 | // Close and release the client | ||
| 77 | ~Client(); | ||
| 78 | |||
| 79 | // Used for polling | ||
| 80 | void BeginConfiguration(); | ||
| 81 | void EndConfiguration(); | ||
| 82 | |||
| 83 | std::vector<Common::ParamPackage> GetInputDevices() const; | ||
| 84 | 56 | ||
| 85 | bool DeviceConnected(std::size_t pad) const; | ||
| 86 | void ReloadSockets(); | 57 | void ReloadSockets(); |
| 87 | 58 | ||
| 88 | Common::SPSCQueue<UDPPadStatus>& GetPadQueue(); | ||
| 89 | const Common::SPSCQueue<UDPPadStatus>& GetPadQueue() const; | ||
| 90 | |||
| 91 | DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad); | ||
| 92 | const DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad) const; | ||
| 93 | |||
| 94 | Input::TouchStatus& GetTouchState(); | ||
| 95 | const Input::TouchStatus& GetTouchState() const; | ||
| 96 | |||
| 97 | private: | 59 | private: |
| 98 | struct PadData { | 60 | struct PadData { |
| 99 | std::size_t pad_index{}; | 61 | std::size_t pad_index{}; |
| @@ -101,9 +63,6 @@ private: | |||
| 101 | DeviceStatus status; | 63 | DeviceStatus status; |
| 102 | u64 packet_sequence{}; | 64 | u64 packet_sequence{}; |
| 103 | 65 | ||
| 104 | // Realtime values | ||
| 105 | // motion is initalized with PID values for drift correction on joycons | ||
| 106 | InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f}; | ||
| 107 | std::chrono::time_point<std::chrono::steady_clock> last_update; | 66 | std::chrono::time_point<std::chrono::steady_clock> last_update; |
| 108 | }; | 67 | }; |
| 109 | 68 | ||
| @@ -127,28 +86,13 @@ private: | |||
| 127 | void OnPortInfo(Response::PortInfo); | 86 | void OnPortInfo(Response::PortInfo); |
| 128 | void OnPadData(Response::PadData, std::size_t client); | 87 | void OnPadData(Response::PadData, std::size_t client); |
| 129 | void StartCommunication(std::size_t client, const std::string& host, u16 port); | 88 | void StartCommunication(std::size_t client, const std::string& host, u16 port); |
| 130 | void UpdateYuzuSettings(std::size_t client, std::size_t pad_index, | 89 | const PadIdentifier GetPadIdentifier(std::size_t pad_index) const; |
| 131 | const Common::Vec3<float>& acc, const Common::Vec3<float>& gyro); | ||
| 132 | |||
| 133 | // Returns an unused finger id, if there is no fingers available std::nullopt will be | ||
| 134 | // returned | ||
| 135 | std::optional<std::size_t> GetUnusedFingerID() const; | ||
| 136 | |||
| 137 | // Merges and updates all touch inputs into the touch_status array | ||
| 138 | void UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id); | ||
| 139 | |||
| 140 | bool configuring = false; | ||
| 141 | 90 | ||
| 142 | // Allocate clients for 8 udp servers | 91 | // Allocate clients for 8 udp servers |
| 143 | static constexpr std::size_t MAX_UDP_CLIENTS = 8; | 92 | static constexpr std::size_t MAX_UDP_CLIENTS = 8; |
| 144 | static constexpr std::size_t PADS_PER_CLIENT = 4; | 93 | static constexpr std::size_t PADS_PER_CLIENT = 4; |
| 145 | // Each client can have up 2 touch inputs | ||
| 146 | static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2; | ||
| 147 | std::array<PadData, MAX_UDP_CLIENTS * PADS_PER_CLIENT> pads{}; | 94 | std::array<PadData, MAX_UDP_CLIENTS * PADS_PER_CLIENT> pads{}; |
| 148 | std::array<ClientConnection, MAX_UDP_CLIENTS> clients{}; | 95 | std::array<ClientConnection, MAX_UDP_CLIENTS> clients{}; |
| 149 | Common::SPSCQueue<UDPPadStatus> pad_queue{}; | ||
| 150 | Input::TouchStatus touch_status{}; | ||
| 151 | std::array<std::size_t, MAX_TOUCH_FINGERS> finger_id{}; | ||
| 152 | }; | 96 | }; |
| 153 | 97 | ||
| 154 | /// An async job allowing configuration of the touchpad calibration. | 98 | /// 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 deleted file mode 100644 index 9829da6f0..000000000 --- a/src/input_common/udp/udp.cpp +++ /dev/null | |||
| @@ -1,110 +0,0 @@ | |||
| 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 <mutex> | ||
| 6 | #include <utility> | ||
| 7 | #include "common/assert.h" | ||
| 8 | #include "common/threadsafe_queue.h" | ||
| 9 | #include "input_common/udp/client.h" | ||
| 10 | #include "input_common/udp/udp.h" | ||
| 11 | |||
| 12 | namespace InputCommon { | ||
| 13 | |||
| 14 | class UDPMotion final : public Input::MotionDevice { | ||
| 15 | public: | ||
| 16 | explicit UDPMotion(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_) | ||
| 17 | : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} | ||
| 18 | |||
| 19 | Input::MotionStatus GetStatus() const override { | ||
| 20 | return client->GetPadState(ip, port, pad).motion_status; | ||
| 21 | } | ||
| 22 | |||
| 23 | private: | ||
| 24 | const std::string ip; | ||
| 25 | const u16 port; | ||
| 26 | const u16 pad; | ||
| 27 | CemuhookUDP::Client* client; | ||
| 28 | mutable std::mutex mutex; | ||
| 29 | }; | ||
| 30 | |||
| 31 | /// A motion device factory that creates motion devices from a UDP client | ||
| 32 | UDPMotionFactory::UDPMotionFactory(std::shared_ptr<CemuhookUDP::Client> client_) | ||
| 33 | : client(std::move(client_)) {} | ||
| 34 | |||
| 35 | /** | ||
| 36 | * Creates motion device | ||
| 37 | * @param params contains parameters for creating the device: | ||
| 38 | * - "port": the UDP port number | ||
| 39 | */ | ||
| 40 | std::unique_ptr<Input::MotionDevice> UDPMotionFactory::Create(const Common::ParamPackage& params) { | ||
| 41 | auto ip = params.Get("ip", "127.0.0.1"); | ||
| 42 | const auto port = static_cast<u16>(params.Get("port", 26760)); | ||
| 43 | const auto pad = static_cast<u16>(params.Get("pad_index", 0)); | ||
| 44 | |||
| 45 | return std::make_unique<UDPMotion>(std::move(ip), port, pad, client.get()); | ||
| 46 | } | ||
| 47 | |||
| 48 | void UDPMotionFactory::BeginConfiguration() { | ||
| 49 | polling = true; | ||
| 50 | client->BeginConfiguration(); | ||
| 51 | } | ||
| 52 | |||
| 53 | void UDPMotionFactory::EndConfiguration() { | ||
| 54 | polling = false; | ||
| 55 | client->EndConfiguration(); | ||
| 56 | } | ||
| 57 | |||
| 58 | Common::ParamPackage UDPMotionFactory::GetNextInput() { | ||
| 59 | Common::ParamPackage params; | ||
| 60 | CemuhookUDP::UDPPadStatus pad; | ||
| 61 | auto& queue = client->GetPadQueue(); | ||
| 62 | while (queue.Pop(pad)) { | ||
| 63 | if (pad.motion == CemuhookUDP::PadMotion::Undefined || std::abs(pad.motion_value) < 1) { | ||
| 64 | continue; | ||
| 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; | ||
| 72 | } | ||
| 73 | return params; | ||
| 74 | } | ||
| 75 | |||
| 76 | class UDPTouch final : public Input::TouchDevice { | ||
| 77 | public: | ||
| 78 | explicit UDPTouch(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_) | ||
| 79 | : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} | ||
| 80 | |||
| 81 | Input::TouchStatus GetStatus() const override { | ||
| 82 | return client->GetTouchState(); | ||
| 83 | } | ||
| 84 | |||
| 85 | private: | ||
| 86 | const std::string ip; | ||
| 87 | [[maybe_unused]] const u16 port; | ||
| 88 | [[maybe_unused]] const u16 pad; | ||
| 89 | CemuhookUDP::Client* client; | ||
| 90 | mutable std::mutex mutex; | ||
| 91 | }; | ||
| 92 | |||
| 93 | /// A motion device factory that creates motion devices from a UDP client | ||
| 94 | UDPTouchFactory::UDPTouchFactory(std::shared_ptr<CemuhookUDP::Client> client_) | ||
| 95 | : client(std::move(client_)) {} | ||
| 96 | |||
| 97 | /** | ||
| 98 | * Creates motion device | ||
| 99 | * @param params contains parameters for creating the device: | ||
| 100 | * - "port": the UDP port number | ||
| 101 | */ | ||
| 102 | std::unique_ptr<Input::TouchDevice> UDPTouchFactory::Create(const Common::ParamPackage& params) { | ||
| 103 | auto ip = params.Get("ip", "127.0.0.1"); | ||
| 104 | const auto port = static_cast<u16>(params.Get("port", 26760)); | ||
| 105 | const auto pad = static_cast<u16>(params.Get("pad_index", 0)); | ||
| 106 | |||
| 107 | return std::make_unique<UDPTouch>(std::move(ip), port, pad, client.get()); | ||
| 108 | } | ||
| 109 | |||
| 110 | } // namespace InputCommon | ||
diff --git a/src/input_common/udp/udp.h b/src/input_common/udp/udp.h deleted file mode 100644 index ea3fd4175..000000000 --- a/src/input_common/udp/udp.h +++ /dev/null | |||
| @@ -1,57 +0,0 @@ | |||
| 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 <memory> | ||
| 8 | #include "core/frontend/input.h" | ||
| 9 | #include "input_common/udp/client.h" | ||
| 10 | |||
| 11 | namespace InputCommon { | ||
| 12 | |||
| 13 | /// A motion device factory that creates motion devices from udp clients | ||
| 14 | class UDPMotionFactory final : public Input::Factory<Input::MotionDevice> { | ||
| 15 | public: | ||
| 16 | explicit UDPMotionFactory(std::shared_ptr<CemuhookUDP::Client> client_); | ||
| 17 | |||
| 18 | std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override; | ||
| 19 | |||
| 20 | Common::ParamPackage GetNextInput(); | ||
| 21 | |||
| 22 | /// For device input configuration/polling | ||
| 23 | void BeginConfiguration(); | ||
| 24 | void EndConfiguration(); | ||
| 25 | |||
| 26 | bool IsPolling() const { | ||
| 27 | return polling; | ||
| 28 | } | ||
| 29 | |||
| 30 | private: | ||
| 31 | std::shared_ptr<CemuhookUDP::Client> client; | ||
| 32 | bool polling = false; | ||
| 33 | }; | ||
| 34 | |||
| 35 | /// A touch device factory that creates touch devices from udp clients | ||
| 36 | class UDPTouchFactory final : public Input::Factory<Input::TouchDevice> { | ||
| 37 | public: | ||
| 38 | explicit UDPTouchFactory(std::shared_ptr<CemuhookUDP::Client> client_); | ||
| 39 | |||
| 40 | std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override; | ||
| 41 | |||
| 42 | Common::ParamPackage GetNextInput(); | ||
| 43 | |||
| 44 | /// For device input configuration/polling | ||
| 45 | void BeginConfiguration(); | ||
| 46 | void EndConfiguration(); | ||
| 47 | |||
| 48 | bool IsPolling() const { | ||
| 49 | return polling; | ||
| 50 | } | ||
| 51 | |||
| 52 | private: | ||
| 53 | std::shared_ptr<CemuhookUDP::Client> client; | ||
| 54 | bool polling = false; | ||
| 55 | }; | ||
| 56 | |||
| 57 | } // namespace InputCommon | ||