summaryrefslogtreecommitdiff
path: root/src/input_common/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/drivers')
-rw-r--r--src/input_common/drivers/camera.cpp4
-rw-r--r--src/input_common/drivers/camera.h4
-rw-r--r--src/input_common/drivers/gc_adapter.cpp10
-rw-r--r--src/input_common/drivers/gc_adapter.h2
-rw-r--r--src/input_common/drivers/joycon.cpp724
-rw-r--r--src/input_common/drivers/joycon.h112
-rw-r--r--src/input_common/drivers/mouse.cpp67
-rw-r--r--src/input_common/drivers/mouse.h38
-rw-r--r--src/input_common/drivers/sdl_driver.cpp95
-rw-r--r--src/input_common/drivers/sdl_driver.h2
-rw-r--r--src/input_common/drivers/tas_input.cpp12
-rw-r--r--src/input_common/drivers/tas_input.h2
-rw-r--r--src/input_common/drivers/virtual_amiibo.cpp11
-rw-r--r--src/input_common/drivers/virtual_amiibo.h2
14 files changed, 1014 insertions, 71 deletions
diff --git a/src/input_common/drivers/camera.cpp b/src/input_common/drivers/camera.cpp
index fad9177dc..04970f635 100644
--- a/src/input_common/drivers/camera.cpp
+++ b/src/input_common/drivers/camera.cpp
@@ -72,11 +72,11 @@ std::size_t Camera::getImageHeight() const {
72 } 72 }
73} 73}
74 74
75Common::Input::CameraError Camera::SetCameraFormat( 75Common::Input::DriverResult Camera::SetCameraFormat(
76 [[maybe_unused]] const PadIdentifier& identifier_, 76 [[maybe_unused]] const PadIdentifier& identifier_,
77 const Common::Input::CameraFormat camera_format) { 77 const Common::Input::CameraFormat camera_format) {
78 status.format = camera_format; 78 status.format = camera_format;
79 return Common::Input::CameraError::None; 79 return Common::Input::DriverResult::Success;
80} 80}
81 81
82} // namespace InputCommon 82} // namespace InputCommon
diff --git a/src/input_common/drivers/camera.h b/src/input_common/drivers/camera.h
index ead3e0fde..24b27e325 100644
--- a/src/input_common/drivers/camera.h
+++ b/src/input_common/drivers/camera.h
@@ -22,8 +22,8 @@ public:
22 std::size_t getImageWidth() const; 22 std::size_t getImageWidth() const;
23 std::size_t getImageHeight() const; 23 std::size_t getImageHeight() const;
24 24
25 Common::Input::CameraError SetCameraFormat(const PadIdentifier& identifier_, 25 Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier_,
26 Common::Input::CameraFormat camera_format) override; 26 Common::Input::CameraFormat camera_format) override;
27 27
28private: 28private:
29 Common::Input::CameraStatus status{}; 29 Common::Input::CameraStatus status{};
diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp
index 826fa2109..d09ff178b 100644
--- a/src/input_common/drivers/gc_adapter.cpp
+++ b/src/input_common/drivers/gc_adapter.cpp
@@ -6,6 +6,7 @@
6 6
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/param_package.h" 8#include "common/param_package.h"
9#include "common/polyfill_thread.h"
9#include "common/settings_input.h" 10#include "common/settings_input.h"
10#include "common/thread.h" 11#include "common/thread.h"
11#include "input_common/drivers/gc_adapter.h" 12#include "input_common/drivers/gc_adapter.h"
@@ -217,8 +218,7 @@ void GCAdapter::AdapterScanThread(std::stop_token stop_token) {
217 Common::SetCurrentThreadName("ScanGCAdapter"); 218 Common::SetCurrentThreadName("ScanGCAdapter");
218 usb_adapter_handle = nullptr; 219 usb_adapter_handle = nullptr;
219 pads = {}; 220 pads = {};
220 while (!stop_token.stop_requested() && !Setup()) { 221 while (!Setup() && Common::StoppableTimedWait(stop_token, std::chrono::seconds{2})) {
221 std::this_thread::sleep_for(std::chrono::seconds(2));
222 } 222 }
223} 223}
224 224
@@ -324,7 +324,7 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) {
324 return true; 324 return true;
325} 325}
326 326
327Common::Input::VibrationError GCAdapter::SetVibration( 327Common::Input::DriverResult GCAdapter::SetVibration(
328 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { 328 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {
329 const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; 329 const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f;
330 const auto processed_amplitude = 330 const auto processed_amplitude =
@@ -333,9 +333,9 @@ Common::Input::VibrationError GCAdapter::SetVibration(
333 pads[identifier.port].rumble_amplitude = processed_amplitude; 333 pads[identifier.port].rumble_amplitude = processed_amplitude;
334 334
335 if (!rumble_enabled) { 335 if (!rumble_enabled) {
336 return Common::Input::VibrationError::Disabled; 336 return Common::Input::DriverResult::Disabled;
337 } 337 }
338 return Common::Input::VibrationError::None; 338 return Common::Input::DriverResult::Success;
339} 339}
340 340
341bool GCAdapter::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) { 341bool GCAdapter::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) {
diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h
index b5270fd0b..3c2eb376d 100644
--- a/src/input_common/drivers/gc_adapter.h
+++ b/src/input_common/drivers/gc_adapter.h
@@ -25,7 +25,7 @@ public:
25 explicit GCAdapter(std::string input_engine_); 25 explicit GCAdapter(std::string input_engine_);
26 ~GCAdapter() override; 26 ~GCAdapter() override;
27 27
28 Common::Input::VibrationError SetVibration( 28 Common::Input::DriverResult SetVibration(
29 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; 29 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
30 30
31 bool IsVibrationEnabled(const PadIdentifier& identifier) override; 31 bool IsVibrationEnabled(const PadIdentifier& identifier) override;
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp
new file mode 100644
index 000000000..b4cd39a20
--- /dev/null
+++ b/src/input_common/drivers/joycon.cpp
@@ -0,0 +1,724 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <fmt/format.h>
5
6#include "common/param_package.h"
7#include "common/polyfill_ranges.h"
8#include "common/polyfill_thread.h"
9#include "common/settings.h"
10#include "common/thread.h"
11#include "input_common/drivers/joycon.h"
12#include "input_common/helpers/joycon_driver.h"
13#include "input_common/helpers/joycon_protocol/joycon_types.h"
14
15namespace InputCommon {
16
17Joycons::Joycons(const std::string& input_engine_) : InputEngine(input_engine_) {
18 // Avoid conflicting with SDL driver
19 if (!Settings::values.enable_joycon_driver && !Settings::values.enable_procon_driver) {
20 return;
21 }
22 LOG_INFO(Input, "Joycon driver Initialization started");
23 const int init_res = SDL_hid_init();
24 if (init_res == 0) {
25 Setup();
26 } else {
27 LOG_ERROR(Input, "Hidapi could not be initialized. failed with error = {}", init_res);
28 }
29}
30
31Joycons::~Joycons() {
32 Reset();
33}
34
35void Joycons::Reset() {
36 scan_thread = {};
37 for (const auto& device : left_joycons) {
38 if (!device) {
39 continue;
40 }
41 device->Stop();
42 }
43 for (const auto& device : right_joycons) {
44 if (!device) {
45 continue;
46 }
47 device->Stop();
48 }
49 for (const auto& device : pro_controller) {
50 if (!device) {
51 continue;
52 }
53 device->Stop();
54 }
55 SDL_hid_exit();
56}
57
58void Joycons::Setup() {
59 u32 port = 0;
60 PreSetController(GetIdentifier(0, Joycon::ControllerType::None));
61 for (auto& device : left_joycons) {
62 PreSetController(GetIdentifier(port, Joycon::ControllerType::Left));
63 device = std::make_shared<Joycon::JoyconDriver>(port++);
64 }
65 port = 0;
66 for (auto& device : right_joycons) {
67 PreSetController(GetIdentifier(port, Joycon::ControllerType::Right));
68 device = std::make_shared<Joycon::JoyconDriver>(port++);
69 }
70 port = 0;
71 for (auto& device : pro_controller) {
72 PreSetController(GetIdentifier(port, Joycon::ControllerType::Pro));
73 device = std::make_shared<Joycon::JoyconDriver>(port++);
74 }
75
76 scan_thread = std::jthread([this](std::stop_token stop_token) { ScanThread(stop_token); });
77}
78
79void Joycons::ScanThread(std::stop_token stop_token) {
80 constexpr u16 nintendo_vendor_id = 0x057e;
81 Common::SetCurrentThreadName("JoyconScanThread");
82
83 do {
84 SDL_hid_device_info* devs = SDL_hid_enumerate(nintendo_vendor_id, 0x0);
85 SDL_hid_device_info* cur_dev = devs;
86
87 while (cur_dev) {
88 if (IsDeviceNew(cur_dev)) {
89 LOG_DEBUG(Input, "Device Found,type : {:04X} {:04X}", cur_dev->vendor_id,
90 cur_dev->product_id);
91 RegisterNewDevice(cur_dev);
92 }
93 cur_dev = cur_dev->next;
94 }
95
96 SDL_hid_free_enumeration(devs);
97 } while (Common::StoppableTimedWait(stop_token, std::chrono::seconds{5}));
98}
99
100bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const {
101 Joycon::ControllerType type{};
102 Joycon::SerialNumber serial_number{};
103
104 const auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type);
105 if (result != Joycon::DriverResult::Success) {
106 return false;
107 }
108
109 const auto result2 = Joycon::JoyconDriver::GetSerialNumber(device_info, serial_number);
110 if (result2 != Joycon::DriverResult::Success) {
111 return false;
112 }
113
114 auto is_handle_identical = [serial_number](std::shared_ptr<Joycon::JoyconDriver> device) {
115 if (!device) {
116 return false;
117 }
118 if (!device->IsConnected()) {
119 return false;
120 }
121 if (device->GetHandleSerialNumber() != serial_number) {
122 return false;
123 }
124 return true;
125 };
126
127 // Check if device already exist
128 switch (type) {
129 case Joycon::ControllerType::Left:
130 if (!Settings::values.enable_joycon_driver) {
131 return false;
132 }
133 for (const auto& device : left_joycons) {
134 if (is_handle_identical(device)) {
135 return false;
136 }
137 }
138 break;
139 case Joycon::ControllerType::Right:
140 if (!Settings::values.enable_joycon_driver) {
141 return false;
142 }
143 for (const auto& device : right_joycons) {
144 if (is_handle_identical(device)) {
145 return false;
146 }
147 }
148 break;
149 case Joycon::ControllerType::Pro:
150 if (!Settings::values.enable_procon_driver) {
151 return false;
152 }
153 for (const auto& device : pro_controller) {
154 if (is_handle_identical(device)) {
155 return false;
156 }
157 }
158 break;
159 default:
160 return false;
161 }
162
163 return true;
164}
165
166void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) {
167 Joycon::ControllerType type{};
168 auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type);
169 auto handle = GetNextFreeHandle(type);
170 if (handle == nullptr) {
171 LOG_WARNING(Input, "No free handles available");
172 return;
173 }
174 if (result == Joycon::DriverResult::Success) {
175 result = handle->RequestDeviceAccess(device_info);
176 }
177 if (result == Joycon::DriverResult::Success) {
178 LOG_WARNING(Input, "Initialize device");
179
180 const std::size_t port = handle->GetDevicePort();
181 const Joycon::JoyconCallbacks callbacks{
182 .on_battery_data = {[this, port, type](Joycon::Battery value) {
183 OnBatteryUpdate(port, type, value);
184 }},
185 .on_color_data = {[this, port, type](Joycon::Color value) {
186 OnColorUpdate(port, type, value);
187 }},
188 .on_button_data = {[this, port, type](int id, bool value) {
189 OnButtonUpdate(port, type, id, value);
190 }},
191 .on_stick_data = {[this, port, type](int id, f32 value) {
192 OnStickUpdate(port, type, id, value);
193 }},
194 .on_motion_data = {[this, port, type](int id, const Joycon::MotionData& value) {
195 OnMotionUpdate(port, type, id, value);
196 }},
197 .on_ring_data = {[this](f32 ring_data) { OnRingConUpdate(ring_data); }},
198 .on_amiibo_data = {[this, port](const std::vector<u8>& amiibo_data) {
199 OnAmiiboUpdate(port, amiibo_data);
200 }},
201 .on_camera_data = {[this, port](const std::vector<u8>& camera_data,
202 Joycon::IrsResolution format) {
203 OnCameraUpdate(port, camera_data, format);
204 }},
205 };
206
207 handle->InitializeDevice();
208 handle->SetCallbacks(callbacks);
209 }
210}
211
212std::shared_ptr<Joycon::JoyconDriver> Joycons::GetNextFreeHandle(
213 Joycon::ControllerType type) const {
214 if (type == Joycon::ControllerType::Left) {
215 const auto unconnected_device =
216 std::ranges::find_if(left_joycons, [](auto& device) { return !device->IsConnected(); });
217 if (unconnected_device != left_joycons.end()) {
218 return *unconnected_device;
219 }
220 }
221 if (type == Joycon::ControllerType::Right) {
222 const auto unconnected_device = std::ranges::find_if(
223 right_joycons, [](auto& device) { return !device->IsConnected(); });
224
225 if (unconnected_device != right_joycons.end()) {
226 return *unconnected_device;
227 }
228 }
229 if (type == Joycon::ControllerType::Pro) {
230 const auto unconnected_device = std::ranges::find_if(
231 pro_controller, [](auto& device) { return !device->IsConnected(); });
232
233 if (unconnected_device != pro_controller.end()) {
234 return *unconnected_device;
235 }
236 }
237 return nullptr;
238}
239
240bool Joycons::IsVibrationEnabled(const PadIdentifier& identifier) {
241 const auto handle = GetHandle(identifier);
242 if (handle == nullptr) {
243 return false;
244 }
245 return handle->IsVibrationEnabled();
246}
247
248Common::Input::DriverResult Joycons::SetVibration(const PadIdentifier& identifier,
249 const Common::Input::VibrationStatus& vibration) {
250 const Joycon::VibrationValue native_vibration{
251 .low_amplitude = vibration.low_amplitude,
252 .low_frequency = vibration.low_frequency,
253 .high_amplitude = vibration.high_amplitude,
254 .high_frequency = vibration.high_frequency,
255 };
256 auto handle = GetHandle(identifier);
257 if (handle == nullptr) {
258 return Common::Input::DriverResult::InvalidHandle;
259 }
260
261 handle->SetVibration(native_vibration);
262 return Common::Input::DriverResult::Success;
263}
264
265Common::Input::DriverResult Joycons::SetLeds(const PadIdentifier& identifier,
266 const Common::Input::LedStatus& led_status) {
267 auto handle = GetHandle(identifier);
268 if (handle == nullptr) {
269 return Common::Input::DriverResult::InvalidHandle;
270 }
271 int led_config = led_status.led_1 ? 1 : 0;
272 led_config += led_status.led_2 ? 2 : 0;
273 led_config += led_status.led_3 ? 4 : 0;
274 led_config += led_status.led_4 ? 8 : 0;
275
276 return static_cast<Common::Input::DriverResult>(
277 handle->SetLedConfig(static_cast<u8>(led_config)));
278}
279
280Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier,
281 Common::Input::CameraFormat camera_format) {
282 auto handle = GetHandle(identifier);
283 if (handle == nullptr) {
284 return Common::Input::DriverResult::InvalidHandle;
285 }
286 return static_cast<Common::Input::DriverResult>(handle->SetIrsConfig(
287 Joycon::IrsMode::ImageTransfer, static_cast<Joycon::IrsResolution>(camera_format)));
288};
289
290Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const {
291 return Common::Input::NfcState::Success;
292};
293
294Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier_,
295 const std::vector<u8>& data) {
296 return Common::Input::NfcState::NotSupported;
297};
298
299Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier,
300 const Common::Input::PollingMode polling_mode) {
301 auto handle = GetHandle(identifier);
302 if (handle == nullptr) {
303 LOG_ERROR(Input, "Invalid handle {}", identifier.port);
304 return Common::Input::DriverResult::InvalidHandle;
305 }
306
307 switch (polling_mode) {
308 case Common::Input::PollingMode::Active:
309 return static_cast<Common::Input::DriverResult>(handle->SetActiveMode());
310 case Common::Input::PollingMode::Pasive:
311 return static_cast<Common::Input::DriverResult>(handle->SetPasiveMode());
312 case Common::Input::PollingMode::IR:
313 return static_cast<Common::Input::DriverResult>(handle->SetIrMode());
314 case Common::Input::PollingMode::NFC:
315 return static_cast<Common::Input::DriverResult>(handle->SetNfcMode());
316 case Common::Input::PollingMode::Ring:
317 return static_cast<Common::Input::DriverResult>(handle->SetRingConMode());
318 default:
319 return Common::Input::DriverResult::NotSupported;
320 }
321}
322
323void Joycons::OnBatteryUpdate(std::size_t port, Joycon::ControllerType type,
324 Joycon::Battery value) {
325 const auto identifier = GetIdentifier(port, type);
326 if (value.charging != 0) {
327 SetBattery(identifier, Common::Input::BatteryLevel::Charging);
328 return;
329 }
330
331 Common::Input::BatteryLevel battery{};
332 switch (value.status) {
333 case 0:
334 battery = Common::Input::BatteryLevel::Empty;
335 break;
336 case 1:
337 battery = Common::Input::BatteryLevel::Critical;
338 break;
339 case 2:
340 battery = Common::Input::BatteryLevel::Low;
341 break;
342 case 3:
343 battery = Common::Input::BatteryLevel::Medium;
344 break;
345 case 4:
346 default:
347 battery = Common::Input::BatteryLevel::Full;
348 break;
349 }
350 SetBattery(identifier, battery);
351}
352
353void Joycons::OnColorUpdate(std::size_t port, Joycon::ControllerType type,
354 const Joycon::Color& value) {
355 const auto identifier = GetIdentifier(port, type);
356 Common::Input::BodyColorStatus color{
357 .body = value.body,
358 .buttons = value.buttons,
359 .left_grip = value.left_grip,
360 .right_grip = value.right_grip,
361 };
362 SetColor(identifier, color);
363}
364
365void Joycons::OnButtonUpdate(std::size_t port, Joycon::ControllerType type, int id, bool value) {
366 const auto identifier = GetIdentifier(port, type);
367 SetButton(identifier, id, value);
368}
369
370void Joycons::OnStickUpdate(std::size_t port, Joycon::ControllerType type, int id, f32 value) {
371 const auto identifier = GetIdentifier(port, type);
372 SetAxis(identifier, id, value);
373}
374
375void Joycons::OnMotionUpdate(std::size_t port, Joycon::ControllerType type, int id,
376 const Joycon::MotionData& value) {
377 const auto identifier = GetIdentifier(port, type);
378 BasicMotion motion_data{
379 .gyro_x = value.gyro_x,
380 .gyro_y = value.gyro_y,
381 .gyro_z = value.gyro_z,
382 .accel_x = value.accel_x,
383 .accel_y = value.accel_y,
384 .accel_z = value.accel_z,
385 .delta_timestamp = 15000,
386 };
387 SetMotion(identifier, id, motion_data);
388}
389
390void Joycons::OnRingConUpdate(f32 ring_data) {
391 // To simplify ring detection it will always be mapped to an empty identifier for all
392 // controllers
393 static constexpr PadIdentifier identifier = {
394 .guid = Common::UUID{},
395 .port = 0,
396 .pad = 0,
397 };
398 SetAxis(identifier, 100, ring_data);
399}
400
401void Joycons::OnAmiiboUpdate(std::size_t port, const std::vector<u8>& amiibo_data) {
402 const auto identifier = GetIdentifier(port, Joycon::ControllerType::Right);
403 const auto nfc_state = amiibo_data.empty() ? Common::Input::NfcState::AmiiboRemoved
404 : Common::Input::NfcState::NewAmiibo;
405 SetNfc(identifier, {nfc_state, amiibo_data});
406}
407
408void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data,
409 Joycon::IrsResolution format) {
410 const auto identifier = GetIdentifier(port, Joycon::ControllerType::Right);
411 SetCamera(identifier, {static_cast<Common::Input::CameraFormat>(format), camera_data});
412}
413
414std::shared_ptr<Joycon::JoyconDriver> Joycons::GetHandle(PadIdentifier identifier) const {
415 auto is_handle_active = [&](std::shared_ptr<Joycon::JoyconDriver> device) {
416 if (!device) {
417 return false;
418 }
419 if (!device->IsConnected()) {
420 return false;
421 }
422 if (device->GetDevicePort() == identifier.port) {
423 return true;
424 }
425 return false;
426 };
427 const auto type = static_cast<Joycon::ControllerType>(identifier.pad);
428
429 if (type == Joycon::ControllerType::Left) {
430 const auto matching_device = std::ranges::find_if(
431 left_joycons, [is_handle_active](auto& device) { return is_handle_active(device); });
432
433 if (matching_device != left_joycons.end()) {
434 return *matching_device;
435 }
436 }
437
438 if (type == Joycon::ControllerType::Right) {
439 const auto matching_device = std::ranges::find_if(
440 right_joycons, [is_handle_active](auto& device) { return is_handle_active(device); });
441
442 if (matching_device != right_joycons.end()) {
443 return *matching_device;
444 }
445 }
446
447 if (type == Joycon::ControllerType::Pro) {
448 const auto matching_device = std::ranges::find_if(
449 pro_controller, [is_handle_active](auto& device) { return is_handle_active(device); });
450
451 if (matching_device != pro_controller.end()) {
452 return *matching_device;
453 }
454 }
455
456 return nullptr;
457}
458
459PadIdentifier Joycons::GetIdentifier(std::size_t port, Joycon::ControllerType type) const {
460 const std::array<u8, 16> guid{0, 0, 0, 0, 0, 0, 0, 0,
461 0, 0, 0, 0, 0, 0, 0, static_cast<u8>(type)};
462 return {
463 .guid = Common::UUID{guid},
464 .port = port,
465 .pad = static_cast<std::size_t>(type),
466 };
467}
468
469Common::ParamPackage Joycons::GetParamPackage(std::size_t port, Joycon::ControllerType type) const {
470 const auto identifier = GetIdentifier(port, type);
471 return {
472 {"engine", GetEngineName()},
473 {"guid", identifier.guid.RawString()},
474 {"port", std::to_string(identifier.port)},
475 {"pad", std::to_string(identifier.pad)},
476 };
477}
478
479std::vector<Common::ParamPackage> Joycons::GetInputDevices() const {
480 std::vector<Common::ParamPackage> devices{};
481
482 auto add_entry = [&](std::shared_ptr<Joycon::JoyconDriver> device) {
483 if (!device) {
484 return;
485 }
486 if (!device->IsConnected()) {
487 return;
488 }
489 auto param = GetParamPackage(device->GetDevicePort(), device->GetHandleDeviceType());
490 std::string name = fmt::format("{} {}", JoyconName(device->GetHandleDeviceType()),
491 device->GetDevicePort() + 1);
492 param.Set("display", std::move(name));
493 devices.emplace_back(param);
494 };
495
496 for (const auto& controller : left_joycons) {
497 add_entry(controller);
498 }
499 for (const auto& controller : right_joycons) {
500 add_entry(controller);
501 }
502 for (const auto& controller : pro_controller) {
503 add_entry(controller);
504 }
505
506 // List dual joycon pairs
507 for (std::size_t i = 0; i < MaxSupportedControllers; i++) {
508 if (!left_joycons[i] || !right_joycons[i]) {
509 continue;
510 }
511 if (!left_joycons[i]->IsConnected() || !right_joycons[i]->IsConnected()) {
512 continue;
513 }
514 auto main_param = GetParamPackage(i, left_joycons[i]->GetHandleDeviceType());
515 const auto second_param = GetParamPackage(i, right_joycons[i]->GetHandleDeviceType());
516 const auto type = Joycon::ControllerType::Dual;
517 std::string name = fmt::format("{} {}", JoyconName(type), i + 1);
518
519 main_param.Set("display", std::move(name));
520 main_param.Set("guid2", second_param.Get("guid", ""));
521 main_param.Set("pad", std::to_string(static_cast<size_t>(type)));
522 devices.emplace_back(main_param);
523 }
524
525 return devices;
526}
527
528ButtonMapping Joycons::GetButtonMappingForDevice(const Common::ParamPackage& params) {
529 static constexpr std::array<std::tuple<Settings::NativeButton::Values, Joycon::PadButton, bool>,
530 18>
531 switch_to_joycon_button = {
532 std::tuple{Settings::NativeButton::A, Joycon::PadButton::A, true},
533 {Settings::NativeButton::B, Joycon::PadButton::B, true},
534 {Settings::NativeButton::X, Joycon::PadButton::X, true},
535 {Settings::NativeButton::Y, Joycon::PadButton::Y, true},
536 {Settings::NativeButton::DLeft, Joycon::PadButton::Left, false},
537 {Settings::NativeButton::DUp, Joycon::PadButton::Up, false},
538 {Settings::NativeButton::DRight, Joycon::PadButton::Right, false},
539 {Settings::NativeButton::DDown, Joycon::PadButton::Down, false},
540 {Settings::NativeButton::L, Joycon::PadButton::L, false},
541 {Settings::NativeButton::R, Joycon::PadButton::R, true},
542 {Settings::NativeButton::ZL, Joycon::PadButton::ZL, false},
543 {Settings::NativeButton::ZR, Joycon::PadButton::ZR, true},
544 {Settings::NativeButton::Plus, Joycon::PadButton::Plus, true},
545 {Settings::NativeButton::Minus, Joycon::PadButton::Minus, false},
546 {Settings::NativeButton::Home, Joycon::PadButton::Home, true},
547 {Settings::NativeButton::Screenshot, Joycon::PadButton::Capture, false},
548 {Settings::NativeButton::LStick, Joycon::PadButton::StickL, false},
549 {Settings::NativeButton::RStick, Joycon::PadButton::StickR, true},
550 };
551
552 if (!params.Has("port")) {
553 return {};
554 }
555
556 ButtonMapping mapping{};
557 for (const auto& [switch_button, joycon_button, side] : switch_to_joycon_button) {
558 const std::size_t port = static_cast<std::size_t>(params.Get("port", 0));
559 auto pad = static_cast<Joycon::ControllerType>(params.Get("pad", 0));
560 if (pad == Joycon::ControllerType::Dual) {
561 pad = side ? Joycon::ControllerType::Right : Joycon::ControllerType::Left;
562 }
563
564 Common::ParamPackage button_params = GetParamPackage(port, pad);
565 button_params.Set("button", static_cast<int>(joycon_button));
566 mapping.insert_or_assign(switch_button, std::move(button_params));
567 }
568
569 // Map SL and SR buttons for left joycons
570 if (params.Get("pad", 0) == static_cast<int>(Joycon::ControllerType::Left)) {
571 const std::size_t port = static_cast<std::size_t>(params.Get("port", 0));
572 Common::ParamPackage button_params = GetParamPackage(port, Joycon::ControllerType::Left);
573
574 Common::ParamPackage sl_button_params = button_params;
575 Common::ParamPackage sr_button_params = button_params;
576 sl_button_params.Set("button", static_cast<int>(Joycon::PadButton::LeftSL));
577 sr_button_params.Set("button", static_cast<int>(Joycon::PadButton::LeftSR));
578 mapping.insert_or_assign(Settings::NativeButton::SL, std::move(sl_button_params));
579 mapping.insert_or_assign(Settings::NativeButton::SR, std::move(sr_button_params));
580 }
581
582 // Map SL and SR buttons for right joycons
583 if (params.Get("pad", 0) == static_cast<int>(Joycon::ControllerType::Right)) {
584 const std::size_t port = static_cast<std::size_t>(params.Get("port", 0));
585 Common::ParamPackage button_params = GetParamPackage(port, Joycon::ControllerType::Right);
586
587 Common::ParamPackage sl_button_params = button_params;
588 Common::ParamPackage sr_button_params = button_params;
589 sl_button_params.Set("button", static_cast<int>(Joycon::PadButton::RightSL));
590 sr_button_params.Set("button", static_cast<int>(Joycon::PadButton::RightSR));
591 mapping.insert_or_assign(Settings::NativeButton::SL, std::move(sl_button_params));
592 mapping.insert_or_assign(Settings::NativeButton::SR, std::move(sr_button_params));
593 }
594
595 return mapping;
596}
597
598AnalogMapping Joycons::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
599 if (!params.Has("port")) {
600 return {};
601 }
602
603 const std::size_t port = static_cast<std::size_t>(params.Get("port", 0));
604 auto pad_left = static_cast<Joycon::ControllerType>(params.Get("pad", 0));
605 auto pad_right = pad_left;
606 if (pad_left == Joycon::ControllerType::Dual) {
607 pad_left = Joycon::ControllerType::Left;
608 pad_right = Joycon::ControllerType::Right;
609 }
610
611 AnalogMapping mapping = {};
612 Common::ParamPackage left_analog_params = GetParamPackage(port, pad_left);
613 left_analog_params.Set("axis_x", static_cast<int>(Joycon::PadAxes::LeftStickX));
614 left_analog_params.Set("axis_y", static_cast<int>(Joycon::PadAxes::LeftStickY));
615 mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params));
616 Common::ParamPackage right_analog_params = GetParamPackage(port, pad_right);
617 right_analog_params.Set("axis_x", static_cast<int>(Joycon::PadAxes::RightStickX));
618 right_analog_params.Set("axis_y", static_cast<int>(Joycon::PadAxes::RightStickY));
619 mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params));
620 return mapping;
621}
622
623MotionMapping Joycons::GetMotionMappingForDevice(const Common::ParamPackage& params) {
624 if (!params.Has("port")) {
625 return {};
626 }
627
628 const std::size_t port = static_cast<std::size_t>(params.Get("port", 0));
629 auto pad_left = static_cast<Joycon::ControllerType>(params.Get("pad", 0));
630 auto pad_right = pad_left;
631 if (pad_left == Joycon::ControllerType::Dual) {
632 pad_left = Joycon::ControllerType::Left;
633 pad_right = Joycon::ControllerType::Right;
634 }
635
636 MotionMapping mapping = {};
637 Common::ParamPackage left_motion_params = GetParamPackage(port, pad_left);
638 left_motion_params.Set("motion", 0);
639 mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, std::move(left_motion_params));
640 Common::ParamPackage right_Motion_params = GetParamPackage(port, pad_right);
641 right_Motion_params.Set("motion", 1);
642 mapping.insert_or_assign(Settings::NativeMotion::MotionRight, std::move(right_Motion_params));
643 return mapping;
644}
645
646Common::Input::ButtonNames Joycons::GetUIButtonName(const Common::ParamPackage& params) const {
647 const auto button = static_cast<Joycon::PadButton>(params.Get("button", 0));
648 switch (button) {
649 case Joycon::PadButton::Left:
650 return Common::Input::ButtonNames::ButtonLeft;
651 case Joycon::PadButton::Right:
652 return Common::Input::ButtonNames::ButtonRight;
653 case Joycon::PadButton::Down:
654 return Common::Input::ButtonNames::ButtonDown;
655 case Joycon::PadButton::Up:
656 return Common::Input::ButtonNames::ButtonUp;
657 case Joycon::PadButton::LeftSL:
658 case Joycon::PadButton::RightSL:
659 return Common::Input::ButtonNames::TriggerSL;
660 case Joycon::PadButton::LeftSR:
661 case Joycon::PadButton::RightSR:
662 return Common::Input::ButtonNames::TriggerSR;
663 case Joycon::PadButton::L:
664 return Common::Input::ButtonNames::TriggerL;
665 case Joycon::PadButton::R:
666 return Common::Input::ButtonNames::TriggerR;
667 case Joycon::PadButton::ZL:
668 return Common::Input::ButtonNames::TriggerZL;
669 case Joycon::PadButton::ZR:
670 return Common::Input::ButtonNames::TriggerZR;
671 case Joycon::PadButton::A:
672 return Common::Input::ButtonNames::ButtonA;
673 case Joycon::PadButton::B:
674 return Common::Input::ButtonNames::ButtonB;
675 case Joycon::PadButton::X:
676 return Common::Input::ButtonNames::ButtonX;
677 case Joycon::PadButton::Y:
678 return Common::Input::ButtonNames::ButtonY;
679 case Joycon::PadButton::Plus:
680 return Common::Input::ButtonNames::ButtonPlus;
681 case Joycon::PadButton::Minus:
682 return Common::Input::ButtonNames::ButtonMinus;
683 case Joycon::PadButton::Home:
684 return Common::Input::ButtonNames::ButtonHome;
685 case Joycon::PadButton::Capture:
686 return Common::Input::ButtonNames::ButtonCapture;
687 case Joycon::PadButton::StickL:
688 return Common::Input::ButtonNames::ButtonStickL;
689 case Joycon::PadButton::StickR:
690 return Common::Input::ButtonNames::ButtonStickR;
691 default:
692 return Common::Input::ButtonNames::Undefined;
693 }
694}
695
696Common::Input::ButtonNames Joycons::GetUIName(const Common::ParamPackage& params) const {
697 if (params.Has("button")) {
698 return GetUIButtonName(params);
699 }
700 if (params.Has("axis")) {
701 return Common::Input::ButtonNames::Value;
702 }
703 if (params.Has("motion")) {
704 return Common::Input::ButtonNames::Engine;
705 }
706
707 return Common::Input::ButtonNames::Invalid;
708}
709
710std::string Joycons::JoyconName(Joycon::ControllerType type) const {
711 switch (type) {
712 case Joycon::ControllerType::Left:
713 return "Left Joycon";
714 case Joycon::ControllerType::Right:
715 return "Right Joycon";
716 case Joycon::ControllerType::Pro:
717 return "Pro Controller";
718 case Joycon::ControllerType::Dual:
719 return "Dual Joycon";
720 default:
721 return "Unknown Switch Controller";
722 }
723}
724} // namespace InputCommon
diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h
new file mode 100644
index 000000000..473ba1b9e
--- /dev/null
+++ b/src/input_common/drivers/joycon.h
@@ -0,0 +1,112 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <span>
8#include <thread>
9#include <SDL_hidapi.h>
10
11#include "input_common/input_engine.h"
12
13namespace InputCommon::Joycon {
14using SerialNumber = std::array<u8, 15>;
15struct Battery;
16struct Color;
17struct MotionData;
18enum class ControllerType : u8;
19enum class DriverResult;
20enum class IrsResolution;
21class JoyconDriver;
22} // namespace InputCommon::Joycon
23
24namespace InputCommon {
25
26class Joycons final : public InputCommon::InputEngine {
27public:
28 explicit Joycons(const std::string& input_engine_);
29
30 ~Joycons();
31
32 bool IsVibrationEnabled(const PadIdentifier& identifier) override;
33 Common::Input::DriverResult SetVibration(
34 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
35
36 Common::Input::DriverResult SetLeds(const PadIdentifier& identifier,
37 const Common::Input::LedStatus& led_status) override;
38
39 Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier,
40 Common::Input::CameraFormat camera_format) override;
41
42 Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override;
43 Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_,
44 const std::vector<u8>& data) override;
45
46 Common::Input::DriverResult SetPollingMode(
47 const PadIdentifier& identifier, const Common::Input::PollingMode polling_mode) override;
48
49 /// Used for automapping features
50 std::vector<Common::ParamPackage> GetInputDevices() const override;
51 ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;
52 AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override;
53 MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override;
54 Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override;
55
56private:
57 static constexpr std::size_t MaxSupportedControllers = 8;
58
59 /// For shutting down, clear all data, join all threads, release usb devices
60 void Reset();
61
62 /// Registers controllers, clears all data and starts the scan thread
63 void Setup();
64
65 /// Actively searchs for new devices
66 void ScanThread(std::stop_token stop_token);
67
68 /// Returns true if device is valid and not registered
69 bool IsDeviceNew(SDL_hid_device_info* device_info) const;
70
71 /// Tries to connect to the new device
72 void RegisterNewDevice(SDL_hid_device_info* device_info);
73
74 /// Returns the next free handle
75 std::shared_ptr<Joycon::JoyconDriver> GetNextFreeHandle(Joycon::ControllerType type) const;
76
77 void OnBatteryUpdate(std::size_t port, Joycon::ControllerType type, Joycon::Battery value);
78 void OnColorUpdate(std::size_t port, Joycon::ControllerType type, const Joycon::Color& value);
79 void OnButtonUpdate(std::size_t port, Joycon::ControllerType type, int id, bool value);
80 void OnStickUpdate(std::size_t port, Joycon::ControllerType type, int id, f32 value);
81 void OnMotionUpdate(std::size_t port, Joycon::ControllerType type, int id,
82 const Joycon::MotionData& value);
83 void OnRingConUpdate(f32 ring_data);
84 void OnAmiiboUpdate(std::size_t port, const std::vector<u8>& amiibo_data);
85 void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data,
86 Joycon::IrsResolution format);
87
88 /// Returns a JoyconHandle corresponding to a PadIdentifier
89 std::shared_ptr<Joycon::JoyconDriver> GetHandle(PadIdentifier identifier) const;
90
91 /// Returns a PadIdentifier corresponding to the port number and joycon type
92 PadIdentifier GetIdentifier(std::size_t port, Joycon::ControllerType type) const;
93
94 /// Returns a ParamPackage corresponding to the port number and joycon type
95 Common::ParamPackage GetParamPackage(std::size_t port, Joycon::ControllerType type) const;
96
97 std::string JoyconName(std::size_t port) const;
98
99 Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const;
100
101 /// Returns the name of the device in text format
102 std::string JoyconName(Joycon::ControllerType type) const;
103
104 std::jthread scan_thread;
105
106 // Joycon types are split by type to ease supporting dualjoycon configurations
107 std::array<std::shared_ptr<Joycon::JoyconDriver>, MaxSupportedControllers> left_joycons{};
108 std::array<std::shared_ptr<Joycon::JoyconDriver>, MaxSupportedControllers> right_joycons{};
109 std::array<std::shared_ptr<Joycon::JoyconDriver>, MaxSupportedControllers> pro_controller{};
110};
111
112} // namespace InputCommon
diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp
index faf9cbdc3..da50e0a24 100644
--- a/src/input_common/drivers/mouse.cpp
+++ b/src/input_common/drivers/mouse.cpp
@@ -15,23 +15,39 @@ constexpr int mouse_axis_y = 1;
15constexpr int wheel_axis_x = 2; 15constexpr int wheel_axis_x = 2;
16constexpr int wheel_axis_y = 3; 16constexpr int wheel_axis_y = 3;
17constexpr int motion_wheel_y = 4; 17constexpr int motion_wheel_y = 4;
18constexpr int touch_axis_x = 10;
19constexpr int touch_axis_y = 11;
20constexpr PadIdentifier identifier = { 18constexpr PadIdentifier identifier = {
21 .guid = Common::UUID{}, 19 .guid = Common::UUID{},
22 .port = 0, 20 .port = 0,
23 .pad = 0, 21 .pad = 0,
24}; 22};
25 23
24constexpr PadIdentifier real_mouse_identifier = {
25 .guid = Common::UUID{},
26 .port = 1,
27 .pad = 0,
28};
29
30constexpr PadIdentifier touch_identifier = {
31 .guid = Common::UUID{},
32 .port = 2,
33 .pad = 0,
34};
35
26Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) { 36Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
27 PreSetController(identifier); 37 PreSetController(identifier);
38 PreSetController(real_mouse_identifier);
39 PreSetController(touch_identifier);
40
41 // Initialize all mouse axis
28 PreSetAxis(identifier, mouse_axis_x); 42 PreSetAxis(identifier, mouse_axis_x);
29 PreSetAxis(identifier, mouse_axis_y); 43 PreSetAxis(identifier, mouse_axis_y);
30 PreSetAxis(identifier, wheel_axis_x); 44 PreSetAxis(identifier, wheel_axis_x);
31 PreSetAxis(identifier, wheel_axis_y); 45 PreSetAxis(identifier, wheel_axis_y);
32 PreSetAxis(identifier, motion_wheel_y); 46 PreSetAxis(identifier, motion_wheel_y);
33 PreSetAxis(identifier, touch_axis_x); 47 PreSetAxis(real_mouse_identifier, mouse_axis_x);
34 PreSetAxis(identifier, touch_axis_y); 48 PreSetAxis(real_mouse_identifier, mouse_axis_y);
49 PreSetAxis(touch_identifier, mouse_axis_x);
50 PreSetAxis(touch_identifier, mouse_axis_y);
35 update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); }); 51 update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); });
36} 52}
37 53
@@ -39,7 +55,7 @@ void Mouse::UpdateThread(std::stop_token stop_token) {
39 Common::SetCurrentThreadName("Mouse"); 55 Common::SetCurrentThreadName("Mouse");
40 constexpr int update_time = 10; 56 constexpr int update_time = 10;
41 while (!stop_token.stop_requested()) { 57 while (!stop_token.stop_requested()) {
42 if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { 58 if (Settings::values.mouse_panning) {
43 // Slow movement by 4% 59 // Slow movement by 4%
44 last_mouse_change *= 0.96f; 60 last_mouse_change *= 0.96f;
45 const float sensitivity = 61 const float sensitivity =
@@ -57,17 +73,7 @@ void Mouse::UpdateThread(std::stop_token stop_token) {
57 } 73 }
58} 74}
59 75
60void Mouse::MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int center_y) { 76void Mouse::Move(int x, int y, int center_x, int center_y) {
61 // If native mouse is enabled just set the screen coordinates
62 if (Settings::values.mouse_enabled) {
63 SetAxis(identifier, mouse_axis_x, touch_x);
64 SetAxis(identifier, mouse_axis_y, touch_y);
65 return;
66 }
67
68 SetAxis(identifier, touch_axis_x, touch_x);
69 SetAxis(identifier, touch_axis_y, touch_y);
70
71 if (Settings::values.mouse_panning) { 77 if (Settings::values.mouse_panning) {
72 auto mouse_change = 78 auto mouse_change =
73 (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>(); 79 (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>();
@@ -113,20 +119,41 @@ void Mouse::MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int
113 } 119 }
114} 120}
115 121
116void Mouse::PressButton(int x, int y, f32 touch_x, f32 touch_y, MouseButton button) { 122void Mouse::MouseMove(f32 touch_x, f32 touch_y) {
117 SetAxis(identifier, touch_axis_x, touch_x); 123 SetAxis(real_mouse_identifier, mouse_axis_x, touch_x);
118 SetAxis(identifier, touch_axis_y, touch_y); 124 SetAxis(real_mouse_identifier, mouse_axis_y, touch_y);
125}
126
127void Mouse::TouchMove(f32 touch_x, f32 touch_y) {
128 SetAxis(touch_identifier, mouse_axis_x, touch_x);
129 SetAxis(touch_identifier, mouse_axis_y, touch_y);
130}
131
132void Mouse::PressButton(int x, int y, MouseButton button) {
119 SetButton(identifier, static_cast<int>(button), true); 133 SetButton(identifier, static_cast<int>(button), true);
134
120 // Set initial analog parameters 135 // Set initial analog parameters
121 mouse_origin = {x, y}; 136 mouse_origin = {x, y};
122 last_mouse_position = {x, y}; 137 last_mouse_position = {x, y};
123 button_pressed = true; 138 button_pressed = true;
124} 139}
125 140
141void Mouse::PressMouseButton(MouseButton button) {
142 SetButton(real_mouse_identifier, static_cast<int>(button), true);
143}
144
145void Mouse::PressTouchButton(f32 touch_x, f32 touch_y, MouseButton button) {
146 SetAxis(touch_identifier, mouse_axis_x, touch_x);
147 SetAxis(touch_identifier, mouse_axis_y, touch_y);
148 SetButton(touch_identifier, static_cast<int>(button), true);
149}
150
126void Mouse::ReleaseButton(MouseButton button) { 151void Mouse::ReleaseButton(MouseButton button) {
127 SetButton(identifier, static_cast<int>(button), false); 152 SetButton(identifier, static_cast<int>(button), false);
153 SetButton(real_mouse_identifier, static_cast<int>(button), false);
154 SetButton(touch_identifier, static_cast<int>(button), false);
128 155
129 if (!Settings::values.mouse_panning && !Settings::values.mouse_enabled) { 156 if (!Settings::values.mouse_panning) {
130 SetAxis(identifier, mouse_axis_x, 0); 157 SetAxis(identifier, mouse_axis_x, 0);
131 SetAxis(identifier, mouse_axis_y, 0); 158 SetAxis(identifier, mouse_axis_y, 0);
132 } 159 }
diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h
index 72073cc23..f3b65bdd1 100644
--- a/src/input_common/drivers/mouse.h
+++ b/src/input_common/drivers/mouse.h
@@ -37,13 +37,43 @@ public:
37 * @param center_x the x-coordinate of the middle of the screen 37 * @param center_x the x-coordinate of the middle of the screen
38 * @param center_y the y-coordinate of the middle of the screen 38 * @param center_y the y-coordinate of the middle of the screen
39 */ 39 */
40 void MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int center_y); 40 void Move(int x, int y, int center_x, int center_y);
41 41
42 /** 42 /**
43 * Sets the status of all buttons bound with the key to pressed 43 * Signals that real mouse has moved.
44 * @param key_code the code of the key to press 44 * @param x the absolute position on the touchscreen of the cursor
45 * @param y the absolute position on the touchscreen of the cursor
45 */ 46 */
46 void PressButton(int x, int y, f32 touch_x, f32 touch_y, MouseButton button); 47 void MouseMove(f32 touch_x, f32 touch_y);
48
49 /**
50 * Signals that touch finger has moved.
51 * @param x the absolute position on the touchscreen of the cursor
52 * @param y the absolute position on the touchscreen of the cursor
53 */
54 void TouchMove(f32 touch_x, f32 touch_y);
55
56 /**
57 * Sets the status of a button to pressed
58 * @param x the x-coordinate of the cursor
59 * @param y the y-coordinate of the cursor
60 * @param button the id of the button to press
61 */
62 void PressButton(int x, int y, MouseButton button);
63
64 /**
65 * Sets the status of a mouse button to pressed
66 * @param button the id of the button to press
67 */
68 void PressMouseButton(MouseButton button);
69
70 /**
71 * Sets the status of touch finger to pressed
72 * @param x the absolute position on the touchscreen of the cursor
73 * @param y the absolute position on the touchscreen of the cursor
74 * @param button the id of the button to press
75 */
76 void PressTouchButton(f32 touch_x, f32 touch_y, MouseButton button);
47 77
48 /** 78 /**
49 * Sets the status of all buttons bound with the key to released 79 * Sets the status of all buttons bound with the key to released
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index 4818bb744..5c20b3426 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -40,25 +40,26 @@ public:
40 } 40 }
41 41
42 void EnableMotion() { 42 void EnableMotion() {
43 if (sdl_controller) { 43 if (!sdl_controller) {
44 SDL_GameController* controller = sdl_controller.get(); 44 return;
45 has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) == SDL_TRUE; 45 }
46 has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) == SDL_TRUE; 46 SDL_GameController* controller = sdl_controller.get();
47 if (has_accel) { 47 if (HasMotion()) {
48 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); 48 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_FALSE);
49 } 49 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_FALSE);
50 if (has_gyro) { 50 }
51 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); 51 has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) == SDL_TRUE;
52 } 52 has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) == SDL_TRUE;
53 if (has_accel) {
54 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
55 }
56 if (has_gyro) {
57 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE);
53 } 58 }
54 } 59 }
55 60
56 bool HasGyro() const { 61 bool HasMotion() const {
57 return has_gyro; 62 return has_gyro || has_accel;
58 }
59
60 bool HasAccel() const {
61 return has_accel;
62 } 63 }
63 64
64 bool UpdateMotion(SDL_ControllerSensorEvent event) { 65 bool UpdateMotion(SDL_ControllerSensorEvent event) {
@@ -85,6 +86,20 @@ public:
85 if (time_difference == 0) { 86 if (time_difference == 0) {
86 return false; 87 return false;
87 } 88 }
89
90 // Motion data is invalid
91 if (motion.accel_x == 0 && motion.gyro_x == 0 && motion.accel_y == 0 &&
92 motion.gyro_y == 0 && motion.accel_z == 0 && motion.gyro_z == 0) {
93 if (motion_error_count++ < 200) {
94 return false;
95 }
96 // Try restarting the sensor
97 motion_error_count = 0;
98 EnableMotion();
99 return false;
100 }
101
102 motion_error_count = 0;
88 motion.delta_timestamp = time_difference * 1000; 103 motion.delta_timestamp = time_difference * 1000;
89 return true; 104 return true;
90 } 105 }
@@ -250,6 +265,7 @@ private:
250 mutable std::mutex mutex; 265 mutable std::mutex mutex;
251 266
252 u64 last_motion_update{}; 267 u64 last_motion_update{};
268 std::size_t motion_error_count{};
253 bool has_gyro{false}; 269 bool has_gyro{false};
254 bool has_accel{false}; 270 bool has_accel{false};
255 bool has_vibration{false}; 271 bool has_vibration{false};
@@ -318,6 +334,23 @@ void SDLDriver::InitJoystick(int joystick_index) {
318 334
319 const auto guid = GetGUID(sdl_joystick); 335 const auto guid = GetGUID(sdl_joystick);
320 336
337 if (Settings::values.enable_joycon_driver) {
338 if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e &&
339 (guid.uuid[8] == 0x06 || guid.uuid[8] == 0x07)) {
340 LOG_WARNING(Input, "Preferring joycon driver for device index {}", joystick_index);
341 SDL_JoystickClose(sdl_joystick);
342 return;
343 }
344 }
345
346 if (Settings::values.enable_procon_driver) {
347 if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e && guid.uuid[8] == 0x09) {
348 LOG_WARNING(Input, "Preferring joycon driver for device index {}", joystick_index);
349 SDL_JoystickClose(sdl_joystick);
350 return;
351 }
352 }
353
321 std::scoped_lock lock{joystick_map_mutex}; 354 std::scoped_lock lock{joystick_map_mutex};
322 if (joystick_map.find(guid) == joystick_map.end()) { 355 if (joystick_map.find(guid) == joystick_map.end()) {
323 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller); 356 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
@@ -440,9 +473,19 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
440 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); 473 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
441 SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); 474 SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
442 475
443 // Use hidapi driver for joycons. This will allow joycons to be detected as a GameController and 476 // Disable hidapi drivers for joycon controllers when the custom joycon driver is enabled
444 // not a generic one 477 if (Settings::values.enable_joycon_driver) {
445 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); 478 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0");
479 } else {
480 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
481 }
482
483 // Disable hidapi drivers for pro controllers when the custom joycon driver is enabled
484 if (Settings::values.enable_procon_driver) {
485 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0");
486 } else {
487 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1");
488 }
446 489
447 // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native 490 // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native
448 // driver on Linux. 491 // driver on Linux.
@@ -532,7 +575,7 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {
532 return devices; 575 return devices;
533} 576}
534 577
535Common::Input::VibrationError SDLDriver::SetVibration( 578Common::Input::DriverResult SDLDriver::SetVibration(
536 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { 579 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {
537 const auto joystick = 580 const auto joystick =
538 GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port)); 581 GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port));
@@ -566,14 +609,14 @@ Common::Input::VibrationError SDLDriver::SetVibration(
566 .vibration = new_vibration, 609 .vibration = new_vibration,
567 }); 610 });
568 611
569 return Common::Input::VibrationError::None; 612 return Common::Input::DriverResult::Success;
570} 613}
571 614
572bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) { 615bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) {
573 const auto joystick = 616 const auto joystick =
574 GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port)); 617 GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port));
575 618
576 constexpr Common::Input::VibrationStatus test_vibration{ 619 static constexpr Common::Input::VibrationStatus test_vibration{
577 .low_amplitude = 1, 620 .low_amplitude = 1,
578 .low_frequency = 160.0f, 621 .low_frequency = 160.0f,
579 .high_amplitude = 1, 622 .high_amplitude = 1,
@@ -581,7 +624,7 @@ bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) {
581 .type = Common::Input::VibrationAmplificationType::Exponential, 624 .type = Common::Input::VibrationAmplificationType::Exponential,
582 }; 625 };
583 626
584 constexpr Common::Input::VibrationStatus zero_vibration{ 627 static constexpr Common::Input::VibrationStatus zero_vibration{
585 .low_amplitude = 0, 628 .low_amplitude = 0,
586 .low_frequency = 160.0f, 629 .low_frequency = 160.0f,
587 .high_amplitude = 0, 630 .high_amplitude = 0,
@@ -942,18 +985,18 @@ MotionMapping SDLDriver::GetMotionMappingForDevice(const Common::ParamPackage& p
942 MotionMapping mapping = {}; 985 MotionMapping mapping = {};
943 joystick->EnableMotion(); 986 joystick->EnableMotion();
944 987
945 if (joystick->HasGyro() || joystick->HasAccel()) { 988 if (joystick->HasMotion()) {
946 mapping.insert_or_assign(Settings::NativeMotion::MotionRight, 989 mapping.insert_or_assign(Settings::NativeMotion::MotionRight,
947 BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); 990 BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
948 } 991 }
949 if (params.Has("guid2")) { 992 if (params.Has("guid2")) {
950 joystick2->EnableMotion(); 993 joystick2->EnableMotion();
951 if (joystick2->HasGyro() || joystick2->HasAccel()) { 994 if (joystick2->HasMotion()) {
952 mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, 995 mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
953 BuildMotionParam(joystick2->GetPort(), joystick2->GetGUID())); 996 BuildMotionParam(joystick2->GetPort(), joystick2->GetGUID()));
954 } 997 }
955 } else { 998 } else {
956 if (joystick->HasGyro() || joystick->HasAccel()) { 999 if (joystick->HasMotion()) {
957 mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, 1000 mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
958 BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); 1001 BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
959 } 1002 }
diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h
index 366bcc496..ffde169b3 100644
--- a/src/input_common/drivers/sdl_driver.h
+++ b/src/input_common/drivers/sdl_driver.h
@@ -63,7 +63,7 @@ public:
63 63
64 bool IsStickInverted(const Common::ParamPackage& params) override; 64 bool IsStickInverted(const Common::ParamPackage& params) override;
65 65
66 Common::Input::VibrationError SetVibration( 66 Common::Input::DriverResult SetVibration(
67 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; 67 const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
68 68
69 bool IsVibrationEnabled(const PadIdentifier& identifier) override; 69 bool IsVibrationEnabled(const PadIdentifier& identifier) override;
diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp
index f3ade90da..f3cb14c56 100644
--- a/src/input_common/drivers/tas_input.cpp
+++ b/src/input_common/drivers/tas_input.cpp
@@ -156,10 +156,12 @@ void Tas::RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis) {
156 }; 156 };
157} 157}
158 158
159std::tuple<TasState, size_t, size_t> Tas::GetStatus() const { 159std::tuple<TasState, size_t, std::array<size_t, PLAYER_NUMBER>> Tas::GetStatus() const {
160 TasState state; 160 TasState state;
161 std::array<size_t, PLAYER_NUMBER> lengths{0};
161 if (is_recording) { 162 if (is_recording) {
162 return {TasState::Recording, 0, record_commands.size()}; 163 lengths[0] = record_commands.size();
164 return {TasState::Recording, record_commands.size(), lengths};
163 } 165 }
164 166
165 if (is_running) { 167 if (is_running) {
@@ -168,7 +170,11 @@ std::tuple<TasState, size_t, size_t> Tas::GetStatus() const {
168 state = TasState::Stopped; 170 state = TasState::Stopped;
169 } 171 }
170 172
171 return {state, current_command, script_length}; 173 for (size_t i = 0; i < PLAYER_NUMBER; i++) {
174 lengths[i] = commands[i].size();
175 }
176
177 return {state, current_command, lengths};
172} 178}
173 179
174void Tas::UpdateThread() { 180void Tas::UpdateThread() {
diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h
index 38a27a230..5be66d142 100644
--- a/src/input_common/drivers/tas_input.h
+++ b/src/input_common/drivers/tas_input.h
@@ -124,7 +124,7 @@ public:
124 * Current playback progress ; 124 * Current playback progress ;
125 * Total length of script file currently loaded or being recorded 125 * Total length of script file currently loaded or being recorded
126 */ 126 */
127 std::tuple<TasState, size_t, size_t> GetStatus() const; 127 std::tuple<TasState, size_t, std::array<size_t, PLAYER_NUMBER>> GetStatus() const;
128 128
129private: 129private:
130 enum class TasAxis : u8; 130 enum class TasAxis : u8;
diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp
index 63ffaca67..4a0268a4d 100644
--- a/src/input_common/drivers/virtual_amiibo.cpp
+++ b/src/input_common/drivers/virtual_amiibo.cpp
@@ -22,22 +22,23 @@ VirtualAmiibo::VirtualAmiibo(std::string input_engine_) : InputEngine(std::move(
22 22
23VirtualAmiibo::~VirtualAmiibo() = default; 23VirtualAmiibo::~VirtualAmiibo() = default;
24 24
25Common::Input::PollingError VirtualAmiibo::SetPollingMode( 25Common::Input::DriverResult VirtualAmiibo::SetPollingMode(
26 [[maybe_unused]] const PadIdentifier& identifier_, 26 [[maybe_unused]] const PadIdentifier& identifier_,
27 const Common::Input::PollingMode polling_mode_) { 27 const Common::Input::PollingMode polling_mode_) {
28 polling_mode = polling_mode_; 28 polling_mode = polling_mode_;
29 29
30 if (polling_mode == Common::Input::PollingMode::NFC) { 30 switch (polling_mode) {
31 case Common::Input::PollingMode::NFC:
31 if (state == State::Initialized) { 32 if (state == State::Initialized) {
32 state = State::WaitingForAmiibo; 33 state = State::WaitingForAmiibo;
33 } 34 }
34 } else { 35 return Common::Input::DriverResult::Success;
36 default:
35 if (state == State::AmiiboIsOpen) { 37 if (state == State::AmiiboIsOpen) {
36 CloseAmiibo(); 38 CloseAmiibo();
37 } 39 }
40 return Common::Input::DriverResult::NotSupported;
38 } 41 }
39
40 return Common::Input::PollingError::None;
41} 42}
42 43
43Common::Input::NfcState VirtualAmiibo::SupportsNfc( 44Common::Input::NfcState VirtualAmiibo::SupportsNfc(
diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h
index 0f9dad333..13cacfc0a 100644
--- a/src/input_common/drivers/virtual_amiibo.h
+++ b/src/input_common/drivers/virtual_amiibo.h
@@ -36,7 +36,7 @@ public:
36 ~VirtualAmiibo() override; 36 ~VirtualAmiibo() override;
37 37
38 // Sets polling mode to a controller 38 // Sets polling mode to a controller
39 Common::Input::PollingError SetPollingMode( 39 Common::Input::DriverResult SetPollingMode(
40 const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override; 40 const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override;
41 41
42 Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; 42 Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override;