summaryrefslogtreecommitdiff
path: root/src/core/hid/emulated_controller.cpp
diff options
context:
space:
mode:
authorGravatar german772021-09-20 19:43:16 -0500
committerGravatar Narr the Reg2021-11-24 20:30:23 -0600
commitc3f54ff2329d79bdbb273678b5123cf0b1cd090c (patch)
tree671542346e2f692b2cef8dc4da6ccdb0b9e21dc2 /src/core/hid/emulated_controller.cpp
parentyuzu_cmd: Use new input (diff)
downloadyuzu-c3f54ff2329d79bdbb273678b5123cf0b1cd090c.tar.gz
yuzu-c3f54ff2329d79bdbb273678b5123cf0b1cd090c.tar.xz
yuzu-c3f54ff2329d79bdbb273678b5123cf0b1cd090c.zip
core/hid: Add emulated controllers
Diffstat (limited to 'src/core/hid/emulated_controller.cpp')
-rw-r--r--src/core/hid/emulated_controller.cpp745
1 files changed, 745 insertions, 0 deletions
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
new file mode 100644
index 000000000..4eb5d99bc
--- /dev/null
+++ b/src/core/hid/emulated_controller.cpp
@@ -0,0 +1,745 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included
4
5#include <fmt/format.h>
6
7#include "core/hid/emulated_controller.h"
8#include "core/hid/input_converter.h"
9
10namespace Core::HID {
11constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
12constexpr s32 HID_TRIGGER_MAX = 0x7fff;
13
14EmulatedController::EmulatedController(NpadIdType npad_id_type_) : npad_id_type(npad_id_type_) {}
15
16EmulatedController::~EmulatedController() = default;
17
18NpadType EmulatedController::MapSettingsTypeToNPad(Settings::ControllerType type) {
19 switch (type) {
20 case Settings::ControllerType::ProController:
21 return NpadType::ProController;
22 case Settings::ControllerType::DualJoyconDetached:
23 return NpadType::JoyconDual;
24 case Settings::ControllerType::LeftJoycon:
25 return NpadType::JoyconLeft;
26 case Settings::ControllerType::RightJoycon:
27 return NpadType::JoyconRight;
28 case Settings::ControllerType::Handheld:
29 return NpadType::Handheld;
30 case Settings::ControllerType::GameCube:
31 return NpadType::GameCube;
32 default:
33 return NpadType::ProController;
34 }
35}
36
37Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadType type) {
38 switch (type) {
39 case NpadType::ProController:
40 return Settings::ControllerType::ProController;
41 case NpadType::JoyconDual:
42 return Settings::ControllerType::DualJoyconDetached;
43 case NpadType::JoyconLeft:
44 return Settings::ControllerType::LeftJoycon;
45 case NpadType::JoyconRight:
46 return Settings::ControllerType::RightJoycon;
47 case NpadType::Handheld:
48 return Settings::ControllerType::Handheld;
49 case NpadType::GameCube:
50 return Settings::ControllerType::GameCube;
51 default:
52 return Settings::ControllerType::ProController;
53 }
54}
55
56void EmulatedController::ReloadFromSettings() {
57 const auto player_index = NpadIdTypeToIndex(npad_id_type);
58 const auto& player = Settings::values.players.GetValue()[player_index];
59
60 for (std::size_t index = 0; index < player.buttons.size(); ++index) {
61 button_params[index] = Common::ParamPackage(player.buttons[index]);
62 }
63 for (std::size_t index = 0; index < player.analogs.size(); ++index) {
64 stick_params[index] = Common::ParamPackage(player.analogs[index]);
65 }
66 for (std::size_t index = 0; index < player.motions.size(); ++index) {
67 motion_params[index] = Common::ParamPackage(player.motions[index]);
68 }
69 ReloadInput();
70}
71
72void EmulatedController::ReloadInput() {
73 const auto player_index = NpadIdTypeToIndex(npad_id_type);
74 const auto& player = Settings::values.players.GetValue()[player_index];
75 const auto left_side = button_params[Settings::NativeButton::ZL];
76 const auto right_side = button_params[Settings::NativeButton::ZR];
77
78 std::transform(button_params.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
79 button_params.begin() + Settings::NativeButton::BUTTON_NS_END,
80 button_devices.begin(), Input::CreateDevice<Input::InputDevice>);
81 std::transform(stick_params.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
82 stick_params.begin() + Settings::NativeAnalog::STICK_HID_END,
83 stick_devices.begin(), Input::CreateDevice<Input::InputDevice>);
84 std::transform(motion_params.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,
85 motion_params.begin() + Settings::NativeMotion::MOTION_HID_END,
86 motion_devices.begin(), Input::CreateDevice<Input::InputDevice>);
87
88 trigger_devices[0] =
89 Input::CreateDevice<Input::InputDevice>(button_params[Settings::NativeButton::ZL]);
90 trigger_devices[1] =
91 Input::CreateDevice<Input::InputDevice>(button_params[Settings::NativeButton::ZR]);
92
93 controller.colors_state.left = {
94 .body = player.body_color_left,
95 .button = player.button_color_left,
96 };
97
98 controller.colors_state.right = {
99 .body = player.body_color_right,
100 .button = player.button_color_right,
101 };
102
103 controller.colors_state.fullkey = controller.colors_state.left;
104
105 battery_devices[0] = Input::CreateDevice<Input::InputDevice>(left_side);
106 battery_devices[1] = Input::CreateDevice<Input::InputDevice>(right_side);
107
108 for (std::size_t index = 0; index < button_devices.size(); ++index) {
109 if (!button_devices[index]) {
110 continue;
111 }
112 Input::InputCallback button_callback{
113 [this, index](Input::CallbackStatus callback) { SetButton(callback, index); }};
114 button_devices[index]->SetCallback(button_callback);
115 }
116
117 for (std::size_t index = 0; index < stick_devices.size(); ++index) {
118 if (!stick_devices[index]) {
119 continue;
120 }
121 Input::InputCallback stick_callback{
122 [this, index](Input::CallbackStatus callback) { SetStick(callback, index); }};
123 stick_devices[index]->SetCallback(stick_callback);
124 }
125
126 for (std::size_t index = 0; index < trigger_devices.size(); ++index) {
127 if (!trigger_devices[index]) {
128 continue;
129 }
130 Input::InputCallback trigger_callback{
131 [this, index](Input::CallbackStatus callback) { SetTrigger(callback, index); }};
132 trigger_devices[index]->SetCallback(trigger_callback);
133 }
134
135 for (std::size_t index = 0; index < battery_devices.size(); ++index) {
136 if (!battery_devices[index]) {
137 continue;
138 }
139 Input::InputCallback battery_callback{
140 [this, index](Input::CallbackStatus callback) { SetBattery(callback, index); }};
141 battery_devices[index]->SetCallback(battery_callback);
142 }
143
144 for (std::size_t index = 0; index < motion_devices.size(); ++index) {
145 if (!motion_devices[index]) {
146 continue;
147 }
148 Input::InputCallback motion_callback{
149 [this, index](Input::CallbackStatus callback) { SetMotion(callback, index); }};
150 motion_devices[index]->SetCallback(motion_callback);
151 }
152
153 SetNpadType(MapSettingsTypeToNPad(player.controller_type));
154
155 if (player.connected) {
156 Connect();
157 } else {
158 Disconnect();
159 }
160}
161
162void EmulatedController::UnloadInput() {
163 for (auto& button : button_devices) {
164 button.reset();
165 }
166 for (auto& stick : stick_devices) {
167 stick.reset();
168 }
169 for (auto& motion : motion_devices) {
170 motion.reset();
171 }
172 for (auto& trigger : trigger_devices) {
173 trigger.reset();
174 }
175 for (auto& battery : battery_devices) {
176 battery.reset();
177 }
178}
179
180void EmulatedController::EnableConfiguration() {
181 is_configuring = true;
182 SaveCurrentConfig();
183}
184
185void EmulatedController::DisableConfiguration() {
186 is_configuring = false;
187}
188
189bool EmulatedController::IsConfiguring() const {
190 return is_configuring;
191}
192
193void EmulatedController::SaveCurrentConfig() {
194 if (!is_configuring) {
195 return;
196 }
197
198 const auto player_index = NpadIdTypeToIndex(npad_id_type);
199 auto& player = Settings::values.players.GetValue()[player_index];
200
201 for (std::size_t index = 0; index < player.buttons.size(); ++index) {
202 player.buttons[index] = button_params[index].Serialize();
203 }
204 for (std::size_t index = 0; index < player.analogs.size(); ++index) {
205 player.analogs[index] = stick_params[index].Serialize();
206 }
207 for (std::size_t index = 0; index < player.motions.size(); ++index) {
208 player.motions[index] = motion_params[index].Serialize();
209 }
210}
211
212void EmulatedController::RestoreConfig() {
213 if (!is_configuring) {
214 return;
215 }
216 ReloadFromSettings();
217}
218
219std::vector<Common::ParamPackage> EmulatedController::GetMappedDevices() const {
220 std::vector<Common::ParamPackage> devices;
221 for (const auto& param : button_params) {
222 if (!param.Has("engine")) {
223 continue;
224 }
225 const auto devices_it = std::find_if(
226 devices.begin(), devices.end(), [param](const Common::ParamPackage param_) {
227 return param.Get("engine", "") == param_.Get("engine", "") &&
228 param.Get("guid", "") == param_.Get("guid", "") &&
229 param.Get("port", "") == param_.Get("port", "");
230 });
231 if (devices_it != devices.end()) {
232 continue;
233 }
234 Common::ParamPackage device{};
235 device.Set("engine", param.Get("engine", ""));
236 device.Set("guid", param.Get("guid", ""));
237 device.Set("port", param.Get("port", ""));
238 devices.push_back(device);
239 }
240
241 for (const auto& param : stick_params) {
242 if (!param.Has("engine")) {
243 continue;
244 }
245 if (param.Get("engine", "") == "analog_from_button") {
246 continue;
247 }
248 const auto devices_it = std::find_if(
249 devices.begin(), devices.end(), [param](const Common::ParamPackage param_) {
250 return param.Get("engine", "") == param_.Get("engine", "") &&
251 param.Get("guid", "") == param_.Get("guid", "") &&
252 param.Get("port", "") == param_.Get("port", "");
253 });
254 if (devices_it != devices.end()) {
255 continue;
256 }
257 Common::ParamPackage device{};
258 device.Set("engine", param.Get("engine", ""));
259 device.Set("guid", param.Get("guid", ""));
260 device.Set("port", param.Get("port", ""));
261 devices.push_back(device);
262 }
263 return devices;
264}
265
266Common::ParamPackage EmulatedController::GetButtonParam(std::size_t index) const {
267 if (index >= button_params.size()) {
268 return {};
269 }
270 return button_params[index];
271}
272
273Common::ParamPackage EmulatedController::GetStickParam(std::size_t index) const {
274 if (index >= stick_params.size()) {
275 return {};
276 }
277 return stick_params[index];
278}
279
280Common::ParamPackage EmulatedController::GetMotionParam(std::size_t index) const {
281 if (index >= motion_params.size()) {
282 return {};
283 }
284 return motion_params[index];
285}
286
287void EmulatedController::SetButtonParam(std::size_t index, Common::ParamPackage param) {
288 if (index >= button_params.size()) {
289 return;
290 }
291 button_params[index] = param;
292 ReloadInput();
293}
294
295void EmulatedController::SetStickParam(std::size_t index, Common::ParamPackage param) {
296 if (index >= stick_params.size()) {
297 return;
298 }
299 stick_params[index] = param;
300 ReloadInput();
301}
302
303void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage param) {
304 if (index >= motion_params.size()) {
305 return;
306 }
307 motion_params[index] = param;
308 ReloadInput();
309}
310
311void EmulatedController::SetButton(Input::CallbackStatus callback, std::size_t index) {
312 if (index >= controller.button_values.size()) {
313 return;
314 }
315 std::lock_guard lock{mutex};
316 bool value_changed = false;
317 const auto new_status = TransformToButton(callback);
318 auto& current_status = controller.button_values[index];
319 current_status.toggle = new_status.toggle;
320
321 // Update button status with current
322 if (!current_status.toggle) {
323 current_status.locked = false;
324 if (current_status.value != new_status.value) {
325 current_status.value = new_status.value;
326 value_changed = true;
327 }
328 } else {
329 // Toggle button and lock status
330 if (new_status.value && !current_status.locked) {
331 current_status.locked = true;
332 current_status.value = !current_status.value;
333 value_changed = true;
334 }
335
336 // Unlock button ready for next press
337 if (!new_status.value && current_status.locked) {
338 current_status.locked = false;
339 }
340 }
341
342 if (!value_changed) {
343 return;
344 }
345
346 if (is_configuring) {
347 controller.npad_button_state.raw = NpadButton::None;
348 controller.debug_pad_button_state.raw = 0;
349 TriggerOnChange(ControllerTriggerType::Button);
350 return;
351 }
352
353 switch (index) {
354 case Settings::NativeButton::A:
355 controller.npad_button_state.a.Assign(current_status.value);
356 controller.debug_pad_button_state.a.Assign(current_status.value);
357 break;
358 case Settings::NativeButton::B:
359 controller.npad_button_state.b.Assign(current_status.value);
360 controller.debug_pad_button_state.b.Assign(current_status.value);
361 break;
362 case Settings::NativeButton::X:
363 controller.npad_button_state.x.Assign(current_status.value);
364 controller.debug_pad_button_state.x.Assign(current_status.value);
365 break;
366 case Settings::NativeButton::Y:
367 controller.npad_button_state.y.Assign(current_status.value);
368 controller.debug_pad_button_state.y.Assign(current_status.value);
369 break;
370 case Settings::NativeButton::LStick:
371 controller.npad_button_state.stick_l.Assign(current_status.value);
372 break;
373 case Settings::NativeButton::RStick:
374 controller.npad_button_state.stick_r.Assign(current_status.value);
375 break;
376 case Settings::NativeButton::L:
377 controller.npad_button_state.l.Assign(current_status.value);
378 controller.debug_pad_button_state.l.Assign(current_status.value);
379 break;
380 case Settings::NativeButton::R:
381 controller.npad_button_state.r.Assign(current_status.value);
382 controller.debug_pad_button_state.r.Assign(current_status.value);
383 break;
384 case Settings::NativeButton::ZL:
385 controller.npad_button_state.zl.Assign(current_status.value);
386 controller.debug_pad_button_state.zl.Assign(current_status.value);
387 break;
388 case Settings::NativeButton::ZR:
389 controller.npad_button_state.zr.Assign(current_status.value);
390 controller.debug_pad_button_state.zr.Assign(current_status.value);
391 break;
392 case Settings::NativeButton::Plus:
393 controller.npad_button_state.plus.Assign(current_status.value);
394 controller.debug_pad_button_state.plus.Assign(current_status.value);
395 break;
396 case Settings::NativeButton::Minus:
397 controller.npad_button_state.minus.Assign(current_status.value);
398 controller.debug_pad_button_state.minus.Assign(current_status.value);
399 break;
400 case Settings::NativeButton::DLeft:
401 controller.npad_button_state.left.Assign(current_status.value);
402 controller.debug_pad_button_state.d_left.Assign(current_status.value);
403 break;
404 case Settings::NativeButton::DUp:
405 controller.npad_button_state.up.Assign(current_status.value);
406 controller.debug_pad_button_state.d_up.Assign(current_status.value);
407 break;
408 case Settings::NativeButton::DRight:
409 controller.npad_button_state.right.Assign(current_status.value);
410 controller.debug_pad_button_state.d_right.Assign(current_status.value);
411 break;
412 case Settings::NativeButton::DDown:
413 controller.npad_button_state.down.Assign(current_status.value);
414 controller.debug_pad_button_state.d_down.Assign(current_status.value);
415 break;
416 case Settings::NativeButton::SL:
417 controller.npad_button_state.left_sl.Assign(current_status.value);
418 controller.npad_button_state.right_sl.Assign(current_status.value);
419 break;
420 case Settings::NativeButton::SR:
421 controller.npad_button_state.left_sr.Assign(current_status.value);
422 controller.npad_button_state.right_sr.Assign(current_status.value);
423 break;
424 case Settings::NativeButton::Home:
425 case Settings::NativeButton::Screenshot:
426 break;
427 }
428 TriggerOnChange(ControllerTriggerType::Button);
429}
430
431void EmulatedController::SetStick(Input::CallbackStatus callback, std::size_t index) {
432 if (index >= controller.stick_values.size()) {
433 return;
434 }
435 std::lock_guard lock{mutex};
436 controller.stick_values[index] = TransformToStick(callback);
437
438 if (is_configuring) {
439 controller.analog_stick_state.left = {};
440 controller.analog_stick_state.right = {};
441 TriggerOnChange(ControllerTriggerType::Stick);
442 return;
443 }
444
445 const AnalogStickState stick{
446 .x = static_cast<s32>(controller.stick_values[index].x.value * HID_JOYSTICK_MAX),
447 .y = static_cast<s32>(controller.stick_values[index].y.value * HID_JOYSTICK_MAX),
448 };
449
450 switch (index) {
451 case Settings::NativeAnalog::LStick:
452 controller.analog_stick_state.left = stick;
453 controller.npad_button_state.stick_l_left.Assign(controller.stick_values[index].left);
454 controller.npad_button_state.stick_l_up.Assign(controller.stick_values[index].up);
455 controller.npad_button_state.stick_l_right.Assign(controller.stick_values[index].right);
456 controller.npad_button_state.stick_l_down.Assign(controller.stick_values[index].down);
457 break;
458 case Settings::NativeAnalog::RStick:
459 controller.analog_stick_state.right = stick;
460 controller.npad_button_state.stick_r_left.Assign(controller.stick_values[index].left);
461 controller.npad_button_state.stick_r_up.Assign(controller.stick_values[index].up);
462 controller.npad_button_state.stick_r_right.Assign(controller.stick_values[index].right);
463 controller.npad_button_state.stick_r_down.Assign(controller.stick_values[index].down);
464 break;
465 }
466
467 TriggerOnChange(ControllerTriggerType::Stick);
468}
469
470void EmulatedController::SetTrigger(Input::CallbackStatus callback, std::size_t index) {
471 if (index >= controller.trigger_values.size()) {
472 return;
473 }
474 std::lock_guard lock{mutex};
475 controller.trigger_values[index] = TransformToTrigger(callback);
476
477 if (is_configuring) {
478 controller.gc_trigger_state.left = 0;
479 controller.gc_trigger_state.right = 0;
480 TriggerOnChange(ControllerTriggerType::Trigger);
481 return;
482 }
483
484 const auto trigger = controller.trigger_values[index];
485
486 switch (index) {
487 case Settings::NativeTrigger::LTrigger:
488 controller.gc_trigger_state.left = static_cast<s32>(trigger.analog.value * HID_TRIGGER_MAX);
489 controller.npad_button_state.zl.Assign(trigger.pressed);
490 break;
491 case Settings::NativeTrigger::RTrigger:
492 controller.gc_trigger_state.right =
493 static_cast<s32>(trigger.analog.value * HID_TRIGGER_MAX);
494 controller.npad_button_state.zr.Assign(trigger.pressed);
495 break;
496 }
497
498 TriggerOnChange(ControllerTriggerType::Trigger);
499}
500
501void EmulatedController::SetMotion(Input::CallbackStatus callback, std::size_t index) {
502 if (index >= controller.motion_values.size()) {
503 return;
504 }
505 std::lock_guard lock{mutex};
506 auto& raw_status = controller.motion_values[index].raw_status;
507 auto& emulated = controller.motion_values[index].emulated;
508
509 raw_status = TransformToMotion(callback);
510 emulated.SetAcceleration(Common::Vec3f{
511 raw_status.accel.x.value,
512 raw_status.accel.y.value,
513 raw_status.accel.z.value,
514 });
515 emulated.SetGyroscope(Common::Vec3f{
516 raw_status.gyro.x.value,
517 raw_status.gyro.y.value,
518 raw_status.gyro.z.value,
519 });
520 emulated.UpdateRotation(raw_status.delta_timestamp);
521 emulated.UpdateOrientation(raw_status.delta_timestamp);
522
523 if (is_configuring) {
524 TriggerOnChange(ControllerTriggerType::Motion);
525 return;
526 }
527
528 auto& motion = controller.motion_state[index];
529 motion.accel = emulated.GetAcceleration();
530 motion.gyro = emulated.GetGyroscope();
531 motion.rotation = emulated.GetGyroscope();
532 motion.orientation = emulated.GetOrientation();
533 motion.is_at_rest = emulated.IsMoving(motion_sensitivity);
534
535 TriggerOnChange(ControllerTriggerType::Motion);
536}
537
538void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t index) {
539 if (index >= controller.battery_values.size()) {
540 return;
541 }
542 std::lock_guard lock{mutex};
543 controller.battery_values[index] = TransformToBattery(callback);
544
545 if (is_configuring) {
546 TriggerOnChange(ControllerTriggerType::Battery);
547 return;
548 }
549
550 bool is_charging = false;
551 bool is_powered = false;
552 BatteryLevel battery_level = 0;
553 switch (controller.battery_values[index]) {
554 case Input::BatteryLevel::Charging:
555 is_charging = true;
556 is_powered = true;
557 battery_level = 6;
558 break;
559 case Input::BatteryLevel::Medium:
560 battery_level = 6;
561 break;
562 case Input::BatteryLevel::Low:
563 battery_level = 4;
564 break;
565 case Input::BatteryLevel::Critical:
566 battery_level = 2;
567 break;
568 case Input::BatteryLevel::Empty:
569 battery_level = 0;
570 break;
571 case Input::BatteryLevel::Full:
572 default:
573 is_powered = true;
574 battery_level = 8;
575 break;
576 }
577
578 switch (index) {
579 case 0:
580 controller.battery_state.left = {
581 .is_powered = is_powered,
582 .is_charging = is_charging,
583 .battery_level = battery_level,
584 };
585 break;
586 case 1:
587 controller.battery_state.right = {
588 .is_powered = is_powered,
589 .is_charging = is_charging,
590 .battery_level = battery_level,
591 };
592 break;
593 case 2:
594 controller.battery_state.dual = {
595 .is_powered = is_powered,
596 .is_charging = is_charging,
597 .battery_level = battery_level,
598 };
599 break;
600 }
601 TriggerOnChange(ControllerTriggerType::Battery);
602}
603
604bool EmulatedController::SetVibration([[maybe_unused]] std::size_t device_index,
605 [[maybe_unused]] VibrationValue vibration) {
606 return false;
607}
608
609int EmulatedController::TestVibration(std::size_t device_index) {
610 return 1;
611}
612
613void EmulatedController::Connect() {
614 std::lock_guard lock{mutex};
615 if (is_connected) {
616 LOG_WARNING(Service_HID, "Tried to turn on a connected controller {}", npad_id_type);
617 return;
618 }
619 is_connected = true;
620 TriggerOnChange(ControllerTriggerType::Connected);
621}
622
623void EmulatedController::Disconnect() {
624 std::lock_guard lock{mutex};
625 if (!is_connected) {
626 LOG_WARNING(Service_HID, "Tried to turn off a disconnected controller {}", npad_id_type);
627 return;
628 }
629 is_connected = false;
630 TriggerOnChange(ControllerTriggerType::Disconnected);
631}
632
633bool EmulatedController::IsConnected() const {
634 return is_connected;
635}
636
637bool EmulatedController::IsVibrationEnabled() const {
638 return is_vibration_enabled;
639}
640
641NpadIdType EmulatedController::GetNpadIdType() const {
642 return npad_id_type;
643}
644
645NpadType EmulatedController::GetNpadType() const {
646 return npad_type;
647}
648
649void EmulatedController::SetNpadType(NpadType npad_type_) {
650 std::lock_guard lock{mutex};
651 if (npad_type == npad_type_) {
652 return;
653 }
654 npad_type = npad_type_;
655 TriggerOnChange(ControllerTriggerType::Type);
656}
657
658ButtonValues EmulatedController::GetButtonsValues() const {
659 return controller.button_values;
660}
661
662SticksValues EmulatedController::GetSticksValues() const {
663 return controller.stick_values;
664}
665
666TriggerValues EmulatedController::GetTriggersValues() const {
667 return controller.trigger_values;
668}
669
670ControllerMotionValues EmulatedController::GetMotionValues() const {
671 return controller.motion_values;
672}
673
674ColorValues EmulatedController::GetColorsValues() const {
675 return controller.color_values;
676}
677
678BatteryValues EmulatedController::GetBatteryValues() const {
679 return controller.battery_values;
680}
681
682NpadButtonState EmulatedController::GetNpadButtons() const {
683 if (is_configuring) {
684 return {};
685 }
686 return controller.npad_button_state;
687}
688
689DebugPadButton EmulatedController::GetDebugPadButtons() const {
690 if (is_configuring) {
691 return {};
692 }
693 return controller.debug_pad_button_state;
694}
695
696AnalogSticks EmulatedController::GetSticks() const {
697 if (is_configuring) {
698 return {};
699 }
700 return controller.analog_stick_state;
701}
702
703NpadGcTriggerState EmulatedController::GetTriggers() const {
704 if (is_configuring) {
705 return {};
706 }
707 return controller.gc_trigger_state;
708}
709
710MotionState EmulatedController::GetMotions() const {
711 return controller.motion_state;
712}
713
714ControllerColors EmulatedController::GetColors() const {
715 return controller.colors_state;
716}
717
718BatteryLevelState EmulatedController::GetBattery() const {
719 return controller.battery_state;
720}
721
722void EmulatedController::TriggerOnChange(ControllerTriggerType type) {
723 for (const std::pair<int, ControllerUpdateCallback> poller_pair : callback_list) {
724 const ControllerUpdateCallback& poller = poller_pair.second;
725 if (poller.on_change) {
726 poller.on_change(type);
727 }
728 }
729}
730
731int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) {
732 std::lock_guard lock{mutex};
733 callback_list.insert_or_assign(last_callback_key, update_callback);
734 return last_callback_key++;
735}
736
737void EmulatedController::DeleteCallback(int key) {
738 std::lock_guard lock{mutex};
739 if (!callback_list.contains(key)) {
740 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
741 return;
742 }
743 callback_list.erase(key);
744}
745} // namespace Core::HID