summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorGravatar Narr the Reg2024-01-04 20:37:43 -0600
committerGravatar Narr the Reg2024-01-05 11:41:15 -0600
commitee847f8ff0b1b0aec39c1b78c010bc0c08a0a613 (patch)
tree3b95cbb74be05f0ce7a007353f1f9f95e1ed3901 /src/core
parentMerge pull request #12437 from ameerj/gl-amd-fixes (diff)
downloadyuzu-ee847f8ff0b1b0aec39c1b78c010bc0c08a0a613.tar.gz
yuzu-ee847f8ff0b1b0aec39c1b78c010bc0c08a0a613.tar.xz
yuzu-ee847f8ff0b1b0aec39c1b78c010bc0c08a0a613.zip
hid_core: Move hid to it's own subproject
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt96
-rw-r--r--src/core/core.cpp2
-rw-r--r--src/core/frontend/applets/controller.cpp6
-rw-r--r--src/core/hid/emulated_console.cpp324
-rw-r--r--src/core/hid/emulated_console.h192
-rw-r--r--src/core/hid/emulated_controller.cpp1972
-rw-r--r--src/core/hid/emulated_controller.h619
-rw-r--r--src/core/hid/emulated_devices.cpp483
-rw-r--r--src/core/hid/emulated_devices.h212
-rw-r--r--src/core/hid/hid_core.cpp222
-rw-r--r--src/core/hid/hid_core.h89
-rw-r--r--src/core/hid/hid_types.h736
-rw-r--r--src/core/hid/input_converter.cpp436
-rw-r--r--src/core/hid/input_converter.h119
-rw-r--r--src/core/hid/input_interpreter.cpp64
-rw-r--r--src/core/hid/input_interpreter.h111
-rw-r--r--src/core/hid/irs_types.h301
-rw-r--r--src/core/hid/motion_input.cpp357
-rw-r--r--src/core/hid/motion_input.h119
-rw-r--r--src/core/hle/service/am/am.cpp4
-rw-r--r--src/core/hle/service/am/applets/applet_cabinet.cpp2
-rw-r--r--src/core/hle/service/am/applets/applet_controller.cpp8
-rw-r--r--src/core/hle/service/hid/controllers/applet_resource.cpp329
-rw-r--r--src/core/hle/service/hid/controllers/applet_resource.h123
-rw-r--r--src/core/hle/service/hid/controllers/capture_button.cpp39
-rw-r--r--src/core/hle/service/hid/controllers/capture_button.h27
-rw-r--r--src/core/hle/service/hid/controllers/console_six_axis.cpp45
-rw-r--r--src/core/hle/service/hid/controllers/console_six_axis.h30
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.cpp41
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h55
-rw-r--r--src/core/hle/service/hid/controllers/debug_mouse.cpp64
-rw-r--r--src/core/hle/service/hid/controllers/debug_mouse.h34
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp59
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h36
-rw-r--r--src/core/hle/service/hid/controllers/digitizer.cpp39
-rw-r--r--src/core/hle/service/hid/controllers/digitizer.h27
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp366
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h87
-rw-r--r--src/core/hle/service/hid/controllers/home_button.cpp39
-rw-r--r--src/core/hle/service/hid/controllers/home_button.h27
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp56
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h28
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp64
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h34
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp1342
-rw-r--r--src/core/hle/service/hid/controllers/npad.h214
-rw-r--r--src/core/hle/service/hid/controllers/npad/npad_data.cpp228
-rw-r--r--src/core/hle/service/hid/controllers/npad/npad_data.h88
-rw-r--r--src/core/hle/service/hid/controllers/npad/npad_resource.cpp685
-rw-r--r--src/core/hle/service/hid/controllers/npad/npad_resource.h132
-rw-r--r--src/core/hle/service/hid/controllers/palma.cpp226
-rw-r--r--src/core/hle/service/hid/controllers/palma.h162
-rw-r--r--src/core/hle/service/hid/controllers/seven_six_axis.cpp66
-rw-r--r--src/core/hle/service/hid/controllers/seven_six_axis.h65
-rw-r--r--src/core/hle/service/hid/controllers/shared_memory_holder.cpp54
-rw-r--r--src/core/hle/service/hid/controllers/shared_memory_holder.h44
-rw-r--r--src/core/hle/service/hid/controllers/six_axis.cpp421
-rw-r--r--src/core/hle/service/hid/controllers/six_axis.h111
-rw-r--r--src/core/hle/service/hid/controllers/sleep_button.cpp39
-rw-r--r--src/core/hle/service/hid/controllers/sleep_button.h27
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp132
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h43
-rw-r--r--src/core/hle/service/hid/controllers/types/debug_pad_types.h31
-rw-r--r--src/core/hle/service/hid/controllers/types/gesture_types.h77
-rw-r--r--src/core/hle/service/hid/controllers/types/keyboard_types.h20
-rw-r--r--src/core/hle/service/hid/controllers/types/mouse_types.h8
-rw-r--r--src/core/hle/service/hid/controllers/types/npad_types.h255
-rw-r--r--src/core/hle/service/hid/controllers/types/shared_memory_format.h240
-rw-r--r--src/core/hle/service/hid/controllers/types/touch_types.h90
-rw-r--r--src/core/hle/service/hid/controllers/unique_pad.cpp38
-rw-r--r--src/core/hle/service/hid/controllers/unique_pad.h27
-rw-r--r--src/core/hle/service/hid/errors.h59
-rw-r--r--src/core/hle/service/hid/hid.cpp4
-rw-r--r--src/core/hle/service/hid/hid_debug_server.cpp2
-rw-r--r--src/core/hle/service/hid/hid_firmware_settings.cpp99
-rw-r--r--src/core/hle/service/hid/hid_firmware_settings.h54
-rw-r--r--src/core/hle/service/hid/hid_server.cpp35
-rw-r--r--src/core/hle/service/hid/hid_system_server.cpp15
-rw-r--r--src/core/hle/service/hid/hid_util.h146
-rw-r--r--src/core/hle/service/hid/hidbus.cpp8
-rw-r--r--src/core/hle/service/hid/hidbus.h2
-rw-r--r--src/core/hle/service/hid/hidbus/hidbus_base.cpp73
-rw-r--r--src/core/hle/service/hid/hidbus/hidbus_base.h183
-rw-r--r--src/core/hle/service/hid/hidbus/ringcon.cpp292
-rw-r--r--src/core/hle/service/hid/hidbus/ringcon.h253
-rw-r--r--src/core/hle/service/hid/hidbus/starlink.cpp50
-rw-r--r--src/core/hle/service/hid/hidbus/starlink.h37
-rw-r--r--src/core/hle/service/hid/hidbus/stubbed.cpp50
-rw-r--r--src/core/hle/service/hid/hidbus/stubbed.h37
-rw-r--r--src/core/hle/service/hid/irs.cpp20
-rw-r--r--src/core/hle/service/hid/irs.h6
-rw-r--r--src/core/hle/service/hid/irs_ring_lifo.h47
-rw-r--r--src/core/hle/service/hid/irsensor/clustering_processor.cpp267
-rw-r--r--src/core/hle/service/hid/irsensor/clustering_processor.h115
-rw-r--r--src/core/hle/service/hid/irsensor/image_transfer_processor.cpp155
-rw-r--r--src/core/hle/service/hid/irsensor/image_transfer_processor.h77
-rw-r--r--src/core/hle/service/hid/irsensor/ir_led_processor.cpp27
-rw-r--r--src/core/hle/service/hid/irsensor/ir_led_processor.h47
-rw-r--r--src/core/hle/service/hid/irsensor/moment_processor.cpp149
-rw-r--r--src/core/hle/service/hid/irsensor/moment_processor.h91
-rw-r--r--src/core/hle/service/hid/irsensor/pointing_processor.cpp26
-rw-r--r--src/core/hle/service/hid/irsensor/pointing_processor.h61
-rw-r--r--src/core/hle/service/hid/irsensor/processor_base.cpp67
-rw-r--r--src/core/hle/service/hid/irsensor/processor_base.h33
-rw-r--r--src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp29
-rw-r--r--src/core/hle/service/hid/irsensor/tera_plugin_processor.h53
-rw-r--r--src/core/hle/service/hid/resource_manager.cpp362
-rw-r--r--src/core/hle/service/hid/resource_manager.h149
-rw-r--r--src/core/hle/service/hid/ring_lifo.h53
-rw-r--r--src/core/hle/service/nfc/common/device.cpp6
-rw-r--r--src/core/hle/service/nfc/common/device_manager.cpp4
-rw-r--r--src/core/hle/service/nfc/common/device_manager.h2
-rw-r--r--src/core/hle/service/nfc/nfc_interface.cpp2
-rw-r--r--src/core/hle/service/nfp/nfp_interface.cpp2
-rw-r--r--src/core/memory/cheat_engine.cpp4
115 files changed, 67 insertions, 16174 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index e2ec2164c..adcc23c18 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -183,22 +183,6 @@ add_library(core STATIC
183 frontend/framebuffer_layout.cpp 183 frontend/framebuffer_layout.cpp
184 frontend/framebuffer_layout.h 184 frontend/framebuffer_layout.h
185 frontend/graphics_context.h 185 frontend/graphics_context.h
186 hid/emulated_console.cpp
187 hid/emulated_console.h
188 hid/emulated_controller.cpp
189 hid/emulated_controller.h
190 hid/emulated_devices.cpp
191 hid/emulated_devices.h
192 hid/hid_core.cpp
193 hid/hid_core.h
194 hid/hid_types.h
195 hid/input_converter.cpp
196 hid/input_converter.h
197 hid/input_interpreter.cpp
198 hid/input_interpreter.h
199 hid/irs_types.h
200 hid/motion_input.cpp
201 hid/motion_input.h
202 hle/api_version.h 186 hle/api_version.h
203 hle/ipc.h 187 hle/ipc.h
204 hle/kernel/board/nintendo/nx/k_memory_layout.cpp 188 hle/kernel/board/nintendo/nx/k_memory_layout.cpp
@@ -531,94 +515,16 @@ add_library(core STATIC
531 hle/service/hid/hid.h 515 hle/service/hid/hid.h
532 hle/service/hid/hid_debug_server.cpp 516 hle/service/hid/hid_debug_server.cpp
533 hle/service/hid/hid_debug_server.h 517 hle/service/hid/hid_debug_server.h
534 hle/service/hid/hid_firmware_settings.cpp
535 hle/service/hid/hid_firmware_settings.h
536 hle/service/hid/hid_server.cpp 518 hle/service/hid/hid_server.cpp
537 hle/service/hid/hid_server.h 519 hle/service/hid/hid_server.h
538 hle/service/hid/hid_system_server.cpp 520 hle/service/hid/hid_system_server.cpp
539 hle/service/hid/hid_system_server.h 521 hle/service/hid/hid_system_server.h
540 hle/service/hid/hid_util.h
541 hle/service/hid/hidbus.cpp 522 hle/service/hid/hidbus.cpp
542 hle/service/hid/hidbus.h 523 hle/service/hid/hidbus.h
543 hle/service/hid/irs.cpp 524 hle/service/hid/irs.cpp
544 hle/service/hid/irs.h 525 hle/service/hid/irs.h
545 hle/service/hid/irs_ring_lifo.h
546 hle/service/hid/resource_manager.cpp
547 hle/service/hid/resource_manager.h
548 hle/service/hid/ring_lifo.h
549 hle/service/hid/xcd.cpp 526 hle/service/hid/xcd.cpp
550 hle/service/hid/xcd.h 527 hle/service/hid/xcd.h
551 hle/service/hid/errors.h
552 hle/service/hid/controllers/npad/npad_data.cpp
553 hle/service/hid/controllers/npad/npad_data.h
554 hle/service/hid/controllers/npad/npad_resource.cpp
555 hle/service/hid/controllers/npad/npad_resource.h
556 hle/service/hid/controllers/types/debug_pad_types.h
557 hle/service/hid/controllers/types/keyboard_types.h
558 hle/service/hid/controllers/types/mouse_types.h
559 hle/service/hid/controllers/types/npad_types.h
560 hle/service/hid/controllers/types/shared_memory_format.h
561 hle/service/hid/controllers/types/touch_types.h
562 hle/service/hid/controllers/applet_resource.cpp
563 hle/service/hid/controllers/applet_resource.h
564 hle/service/hid/controllers/capture_button.cpp
565 hle/service/hid/controllers/capture_button.h
566 hle/service/hid/controllers/console_six_axis.cpp
567 hle/service/hid/controllers/console_six_axis.h
568 hle/service/hid/controllers/controller_base.cpp
569 hle/service/hid/controllers/controller_base.h
570 hle/service/hid/controllers/debug_mouse.cpp
571 hle/service/hid/controllers/debug_mouse.h
572 hle/service/hid/controllers/debug_pad.cpp
573 hle/service/hid/controllers/debug_pad.h
574 hle/service/hid/controllers/digitizer.cpp
575 hle/service/hid/controllers/digitizer.h
576 hle/service/hid/controllers/gesture.cpp
577 hle/service/hid/controllers/gesture.h
578 hle/service/hid/controllers/home_button.cpp
579 hle/service/hid/controllers/home_button.h
580 hle/service/hid/controllers/keyboard.cpp
581 hle/service/hid/controllers/keyboard.h
582 hle/service/hid/controllers/mouse.cpp
583 hle/service/hid/controllers/mouse.h
584 hle/service/hid/controllers/npad.cpp
585 hle/service/hid/controllers/npad.h
586 hle/service/hid/controllers/palma.cpp
587 hle/service/hid/controllers/palma.h
588 hle/service/hid/controllers/seven_six_axis.cpp
589 hle/service/hid/controllers/seven_six_axis.h
590 hle/service/hid/controllers/shared_memory_holder.cpp
591 hle/service/hid/controllers/shared_memory_holder.h
592 hle/service/hid/controllers/six_axis.cpp
593 hle/service/hid/controllers/six_axis.h
594 hle/service/hid/controllers/sleep_button.cpp
595 hle/service/hid/controllers/sleep_button.h
596 hle/service/hid/controllers/touchscreen.cpp
597 hle/service/hid/controllers/touchscreen.h
598 hle/service/hid/controllers/unique_pad.cpp
599 hle/service/hid/controllers/unique_pad.h
600 hle/service/hid/hidbus/hidbus_base.cpp
601 hle/service/hid/hidbus/hidbus_base.h
602 hle/service/hid/hidbus/ringcon.cpp
603 hle/service/hid/hidbus/ringcon.h
604 hle/service/hid/hidbus/starlink.cpp
605 hle/service/hid/hidbus/starlink.h
606 hle/service/hid/hidbus/stubbed.cpp
607 hle/service/hid/hidbus/stubbed.h
608 hle/service/hid/irsensor/clustering_processor.cpp
609 hle/service/hid/irsensor/clustering_processor.h
610 hle/service/hid/irsensor/image_transfer_processor.cpp
611 hle/service/hid/irsensor/image_transfer_processor.h
612 hle/service/hid/irsensor/ir_led_processor.cpp
613 hle/service/hid/irsensor/ir_led_processor.h
614 hle/service/hid/irsensor/moment_processor.cpp
615 hle/service/hid/irsensor/moment_processor.h
616 hle/service/hid/irsensor/pointing_processor.cpp
617 hle/service/hid/irsensor/pointing_processor.h
618 hle/service/hid/irsensor/processor_base.cpp
619 hle/service/hid/irsensor/processor_base.h
620 hle/service/hid/irsensor/tera_plugin_processor.cpp
621 hle/service/hid/irsensor/tera_plugin_processor.h
622 hle/service/lbl/lbl.cpp 528 hle/service/lbl/lbl.cpp
623 hle/service/lbl/lbl.h 529 hle/service/lbl/lbl.h
624 hle/service/ldn/lan_discovery.cpp 530 hle/service/ldn/lan_discovery.cpp
@@ -959,7 +865,7 @@ endif()
959 865
960create_target_directory_groups(core) 866create_target_directory_groups(core)
961 867
962target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core nx_tzdb) 868target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb)
963target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API) 869target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API)
964if (MINGW) 870if (MINGW)
965 target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY}) 871 target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY})
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 66f444d39..c063f7719 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -28,7 +28,6 @@
28#include "core/file_sys/savedata_factory.h" 28#include "core/file_sys/savedata_factory.h"
29#include "core/file_sys/vfs_concat.h" 29#include "core/file_sys/vfs_concat.h"
30#include "core/file_sys/vfs_real.h" 30#include "core/file_sys/vfs_real.h"
31#include "core/hid/hid_core.h"
32#include "core/hle/kernel/k_memory_manager.h" 31#include "core/hle/kernel/k_memory_manager.h"
33#include "core/hle/kernel/k_process.h" 32#include "core/hle/kernel/k_process.h"
34#include "core/hle/kernel/k_resource_limit.h" 33#include "core/hle/kernel/k_resource_limit.h"
@@ -52,6 +51,7 @@
52#include "core/telemetry_session.h" 51#include "core/telemetry_session.h"
53#include "core/tools/freezer.h" 52#include "core/tools/freezer.h"
54#include "core/tools/renderdoc.h" 53#include "core/tools/renderdoc.h"
54#include "hid_core/hid_core.h"
55#include "network/network.h" 55#include "network/network.h"
56#include "video_core/host1x/host1x.h" 56#include "video_core/host1x/host1x.h"
57#include "video_core/renderer_base.h" 57#include "video_core/renderer_base.h"
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp
index 27755cb58..34fe23b6a 100644
--- a/src/core/frontend/applets/controller.cpp
+++ b/src/core/frontend/applets/controller.cpp
@@ -6,9 +6,9 @@
6#include "common/settings.h" 6#include "common/settings.h"
7#include "common/settings_enums.h" 7#include "common/settings_enums.h"
8#include "core/frontend/applets/controller.h" 8#include "core/frontend/applets/controller.h"
9#include "core/hid/emulated_controller.h" 9#include "hid_core/frontend/emulated_controller.h"
10#include "core/hid/hid_core.h" 10#include "hid_core/hid_core.h"
11#include "core/hid/hid_types.h" 11#include "hid_core/hid_types.h"
12 12
13namespace Core::Frontend { 13namespace Core::Frontend {
14 14
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp
deleted file mode 100644
index b4afd930e..000000000
--- a/src/core/hid/emulated_console.cpp
+++ /dev/null
@@ -1,324 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/settings.h"
5#include "core/hid/emulated_console.h"
6#include "core/hid/input_converter.h"
7
8namespace Core::HID {
9EmulatedConsole::EmulatedConsole() = default;
10
11EmulatedConsole::~EmulatedConsole() = default;
12
13void EmulatedConsole::ReloadFromSettings() {
14 // Using first motion device from player 1. No need to assign any unique config at the moment
15 const auto& player = Settings::values.players.GetValue()[0];
16 motion_params[0] = Common::ParamPackage(player.motions[0]);
17
18 ReloadInput();
19}
20
21void EmulatedConsole::SetTouchParams() {
22 std::size_t index = 0;
23
24 // We can't use mouse as touch if native mouse is enabled
25 if (!Settings::values.mouse_enabled) {
26 touch_params[index++] =
27 Common::ParamPackage{"engine:mouse,axis_x:0,axis_y:1,button:0,port:2"};
28 }
29
30 touch_params[index++] =
31 Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"};
32 touch_params[index++] =
33 Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"};
34
35 for (int i = 0; i < static_cast<int>(MaxActiveTouchInputs); i++) {
36 Common::ParamPackage touchscreen_param{};
37 touchscreen_param.Set("engine", "touch");
38 touchscreen_param.Set("axis_x", i * 2);
39 touchscreen_param.Set("axis_y", (i * 2) + 1);
40 touchscreen_param.Set("button", i);
41 touch_params[index++] = std::move(touchscreen_param);
42 }
43
44 if (Settings::values.touch_from_button_maps.empty()) {
45 LOG_WARNING(Input, "touch_from_button_maps is unset by frontend config");
46 return;
47 }
48
49 const auto button_index =
50 static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
51 const auto& touch_buttons = Settings::values.touch_from_button_maps[button_index].buttons;
52
53 // Map the rest of the fingers from touch from button configuration
54 for (const auto& config_entry : touch_buttons) {
55 if (index >= MaxTouchDevices) {
56 continue;
57 }
58 Common::ParamPackage params{config_entry};
59 Common::ParamPackage touch_button_params;
60 const int x = params.Get("x", 0);
61 const int y = params.Get("y", 0);
62 params.Erase("x");
63 params.Erase("y");
64 touch_button_params.Set("engine", "touch_from_button");
65 touch_button_params.Set("button", params.Serialize());
66 touch_button_params.Set("x", x);
67 touch_button_params.Set("y", y);
68 touch_params[index] = std::move(touch_button_params);
69 index++;
70 }
71}
72
73void EmulatedConsole::ReloadInput() {
74 // If you load any device here add the equivalent to the UnloadInput() function
75 SetTouchParams();
76
77 motion_params[1] = Common::ParamPackage{"engine:virtual_gamepad,port:8,motion:0"};
78
79 for (std::size_t index = 0; index < motion_devices.size(); ++index) {
80 motion_devices[index] = Common::Input::CreateInputDevice(motion_params[index]);
81 if (!motion_devices[index]) {
82 continue;
83 }
84 motion_devices[index]->SetCallback({
85 .on_change =
86 [this](const Common::Input::CallbackStatus& callback) { SetMotion(callback); },
87 });
88 }
89
90 // Restore motion state
91 auto& emulated_motion = console.motion_values.emulated;
92 auto& motion = console.motion_state;
93 emulated_motion.ResetRotations();
94 emulated_motion.ResetQuaternion();
95 motion.accel = emulated_motion.GetAcceleration();
96 motion.gyro = emulated_motion.GetGyroscope();
97 motion.rotation = emulated_motion.GetRotations();
98 motion.orientation = emulated_motion.GetOrientation();
99 motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity);
100
101 // Unique index for identifying touch device source
102 std::size_t index = 0;
103 for (auto& touch_device : touch_devices) {
104 touch_device = Common::Input::CreateInputDevice(touch_params[index]);
105 if (!touch_device) {
106 continue;
107 }
108 touch_device->SetCallback({
109 .on_change =
110 [this, index](const Common::Input::CallbackStatus& callback) {
111 SetTouch(callback, index);
112 },
113 });
114 index++;
115 }
116}
117
118void EmulatedConsole::UnloadInput() {
119 for (auto& motion : motion_devices) {
120 motion.reset();
121 }
122 for (auto& touch : touch_devices) {
123 touch.reset();
124 }
125}
126
127void EmulatedConsole::EnableConfiguration() {
128 is_configuring = true;
129 SaveCurrentConfig();
130}
131
132void EmulatedConsole::DisableConfiguration() {
133 is_configuring = false;
134}
135
136bool EmulatedConsole::IsConfiguring() const {
137 return is_configuring;
138}
139
140void EmulatedConsole::SaveCurrentConfig() {
141 if (!is_configuring) {
142 return;
143 }
144}
145
146void EmulatedConsole::RestoreConfig() {
147 if (!is_configuring) {
148 return;
149 }
150 ReloadFromSettings();
151}
152
153Common::ParamPackage EmulatedConsole::GetMotionParam() const {
154 return motion_params[0];
155}
156
157void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {
158 motion_params[0] = std::move(param);
159 ReloadInput();
160}
161
162void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
163 std::unique_lock lock{mutex};
164 auto& raw_status = console.motion_values.raw_status;
165 auto& emulated = console.motion_values.emulated;
166
167 raw_status = TransformToMotion(callback);
168 emulated.SetAcceleration(Common::Vec3f{
169 raw_status.accel.x.value,
170 raw_status.accel.y.value,
171 raw_status.accel.z.value,
172 });
173 emulated.SetGyroscope(Common::Vec3f{
174 raw_status.gyro.x.value,
175 raw_status.gyro.y.value,
176 raw_status.gyro.z.value,
177 });
178 emulated.UpdateRotation(raw_status.delta_timestamp);
179 emulated.UpdateOrientation(raw_status.delta_timestamp);
180
181 if (is_configuring) {
182 lock.unlock();
183 TriggerOnChange(ConsoleTriggerType::Motion);
184 return;
185 }
186
187 auto& motion = console.motion_state;
188 motion.accel = emulated.GetAcceleration();
189 motion.gyro = emulated.GetGyroscope();
190 motion.rotation = emulated.GetRotations();
191 motion.orientation = emulated.GetOrientation();
192 motion.quaternion = emulated.GetQuaternion();
193 motion.gyro_bias = emulated.GetGyroBias();
194 motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
195 // Find what is this value
196 motion.verticalization_error = 0.0f;
197
198 lock.unlock();
199 TriggerOnChange(ConsoleTriggerType::Motion);
200}
201
202void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) {
203 if (index >= MaxTouchDevices) {
204 return;
205 }
206 std::unique_lock lock{mutex};
207
208 const auto touch_input = TransformToTouch(callback);
209 auto touch_index = GetIndexFromFingerId(index);
210 bool is_new_input = false;
211
212 if (!touch_index.has_value() && touch_input.pressed.value) {
213 touch_index = GetNextFreeIndex();
214 is_new_input = true;
215 }
216
217 // No free entries or invalid state. Ignore input
218 if (!touch_index.has_value()) {
219 return;
220 }
221
222 auto& touch_value = console.touch_values[touch_index.value()];
223
224 if (is_new_input) {
225 touch_value.pressed.value = true;
226 touch_value.id = static_cast<int>(index);
227 }
228
229 touch_value.x = touch_input.x;
230 touch_value.y = touch_input.y;
231
232 if (!touch_input.pressed.value) {
233 touch_value.pressed.value = false;
234 }
235
236 if (is_configuring) {
237 lock.unlock();
238 TriggerOnChange(ConsoleTriggerType::Touch);
239 return;
240 }
241
242 // Touch outside allowed range. Ignore input
243 if (touch_index.value() >= MaxActiveTouchInputs) {
244 return;
245 }
246
247 console.touch_state[touch_index.value()] = {
248 .position = {touch_value.x.value, touch_value.y.value},
249 .id = static_cast<u32>(touch_index.value()),
250 .pressed = touch_input.pressed.value,
251 };
252
253 lock.unlock();
254 TriggerOnChange(ConsoleTriggerType::Touch);
255}
256
257ConsoleMotionValues EmulatedConsole::GetMotionValues() const {
258 std::scoped_lock lock{mutex};
259 return console.motion_values;
260}
261
262TouchValues EmulatedConsole::GetTouchValues() const {
263 std::scoped_lock lock{mutex};
264 return console.touch_values;
265}
266
267ConsoleMotion EmulatedConsole::GetMotion() const {
268 std::scoped_lock lock{mutex};
269 return console.motion_state;
270}
271
272TouchFingerState EmulatedConsole::GetTouch() const {
273 std::scoped_lock lock{mutex};
274 return console.touch_state;
275}
276
277std::optional<std::size_t> EmulatedConsole::GetIndexFromFingerId(std::size_t finger_id) const {
278 for (std::size_t index = 0; index < MaxTouchDevices; ++index) {
279 const auto& finger = console.touch_values[index];
280 if (!finger.pressed.value) {
281 continue;
282 }
283 if (finger.id == static_cast<int>(finger_id)) {
284 return index;
285 }
286 }
287 return std::nullopt;
288}
289
290std::optional<std::size_t> EmulatedConsole::GetNextFreeIndex() const {
291 for (std::size_t index = 0; index < MaxTouchDevices; ++index) {
292 if (!console.touch_values[index].pressed.value) {
293 return index;
294 }
295 }
296 return std::nullopt;
297}
298
299void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
300 std::scoped_lock lock{callback_mutex};
301 for (const auto& poller_pair : callback_list) {
302 const ConsoleUpdateCallback& poller = poller_pair.second;
303 if (poller.on_change) {
304 poller.on_change(type);
305 }
306 }
307}
308
309int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) {
310 std::scoped_lock lock{callback_mutex};
311 callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
312 return last_callback_key++;
313}
314
315void EmulatedConsole::DeleteCallback(int key) {
316 std::scoped_lock lock{callback_mutex};
317 const auto& iterator = callback_list.find(key);
318 if (iterator == callback_list.end()) {
319 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
320 return;
321 }
322 callback_list.erase(iterator);
323}
324} // namespace Core::HID
diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h
deleted file mode 100644
index fae15a556..000000000
--- a/src/core/hid/emulated_console.h
+++ /dev/null
@@ -1,192 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <functional>
8#include <memory>
9#include <mutex>
10#include <optional>
11#include <unordered_map>
12
13#include "common/common_funcs.h"
14#include "common/common_types.h"
15#include "common/input.h"
16#include "common/param_package.h"
17#include "common/point.h"
18#include "common/quaternion.h"
19#include "common/vector_math.h"
20#include "core/hid/hid_types.h"
21#include "core/hid/motion_input.h"
22
23namespace Core::HID {
24static constexpr std::size_t MaxTouchDevices = 32;
25static constexpr std::size_t MaxActiveTouchInputs = 16;
26
27struct ConsoleMotionInfo {
28 Common::Input::MotionStatus raw_status{};
29 MotionInput emulated{};
30};
31
32using ConsoleMotionDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, 2>;
33using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, MaxTouchDevices>;
34
35using ConsoleMotionParams = std::array<Common::ParamPackage, 2>;
36using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>;
37
38using ConsoleMotionValues = ConsoleMotionInfo;
39using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>;
40
41// Contains all motion related data that is used on the services
42struct ConsoleMotion {
43 Common::Vec3f accel{};
44 Common::Vec3f gyro{};
45 Common::Vec3f rotation{};
46 std::array<Common::Vec3f, 3> orientation{};
47 Common::Quaternion<f32> quaternion{};
48 Common::Vec3f gyro_bias{};
49 f32 verticalization_error{};
50 bool is_at_rest{};
51};
52
53using TouchFingerState = std::array<TouchFinger, MaxActiveTouchInputs>;
54
55struct ConsoleStatus {
56 // Data from input_common
57 ConsoleMotionValues motion_values{};
58 TouchValues touch_values{};
59
60 // Data for HID services
61 ConsoleMotion motion_state{};
62 TouchFingerState touch_state{};
63};
64
65enum class ConsoleTriggerType {
66 Motion,
67 Touch,
68 All,
69};
70
71struct ConsoleUpdateCallback {
72 std::function<void(ConsoleTriggerType)> on_change;
73};
74
75class EmulatedConsole {
76public:
77 /**
78 * Contains all input data within the emulated switch console tablet such as touch and motion
79 */
80 explicit EmulatedConsole();
81 ~EmulatedConsole();
82
83 YUZU_NON_COPYABLE(EmulatedConsole);
84 YUZU_NON_MOVEABLE(EmulatedConsole);
85
86 /// Removes all callbacks created from input devices
87 void UnloadInput();
88
89 /**
90 * Sets the emulated console into configuring mode
91 * This prevents the modification of the HID state of the emulated console by input commands
92 */
93 void EnableConfiguration();
94
95 /// Returns the emulated console into normal mode, allowing the modification of the HID state
96 void DisableConfiguration();
97
98 /// Returns true if the emulated console is in configuring mode
99 bool IsConfiguring() const;
100
101 /// Reload all input devices
102 void ReloadInput();
103
104 /// Overrides current mapped devices with the stored configuration and reloads all input devices
105 void ReloadFromSettings();
106
107 /// Saves the current mapped configuration
108 void SaveCurrentConfig();
109
110 /// Reverts any mapped changes made that weren't saved
111 void RestoreConfig();
112
113 // Returns the current mapped motion device
114 Common::ParamPackage GetMotionParam() const;
115
116 /**
117 * Updates the current mapped motion device
118 * @param param ParamPackage with controller data to be mapped
119 */
120 void SetMotionParam(Common::ParamPackage param);
121
122 /// Returns the latest status of motion input from the console with parameters
123 ConsoleMotionValues GetMotionValues() const;
124
125 /// Returns the latest status of touch input from the console with parameters
126 TouchValues GetTouchValues() const;
127
128 /// Returns the latest status of motion input from the console
129 ConsoleMotion GetMotion() const;
130
131 /// Returns the latest status of touch input from the console
132 TouchFingerState GetTouch() const;
133
134 /**
135 * Adds a callback to the list of events
136 * @param update_callback A ConsoleUpdateCallback that will be triggered
137 * @return an unique key corresponding to the callback index in the list
138 */
139 int SetCallback(ConsoleUpdateCallback update_callback);
140
141 /**
142 * Removes a callback from the list stopping any future events to this object
143 * @param key Key corresponding to the callback index in the list
144 */
145 void DeleteCallback(int key);
146
147private:
148 /// Creates and stores the touch params
149 void SetTouchParams();
150
151 /**
152 * Updates the motion status of the console
153 * @param callback A CallbackStatus containing gyro and accelerometer data
154 */
155 void SetMotion(const Common::Input::CallbackStatus& callback);
156
157 /**
158 * Updates the touch status of the console
159 * @param callback A CallbackStatus containing the touch position
160 * @param index Finger ID to be updated
161 */
162 void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index);
163
164 std::optional<std::size_t> GetIndexFromFingerId(std::size_t finger_id) const;
165
166 std::optional<std::size_t> GetNextFreeIndex() const;
167
168 /**
169 * Triggers a callback that something has changed on the console status
170 * @param type Input type of the event to trigger
171 */
172 void TriggerOnChange(ConsoleTriggerType type);
173
174 bool is_configuring{false};
175 f32 motion_sensitivity{0.01f};
176
177 ConsoleMotionParams motion_params;
178 TouchParams touch_params;
179
180 ConsoleMotionDevices motion_devices;
181 TouchDevices touch_devices;
182
183 mutable std::mutex mutex;
184 mutable std::mutex callback_mutex;
185 std::unordered_map<int, ConsoleUpdateCallback> callback_list;
186 int last_callback_key = 0;
187
188 // Stores the current status of all console input
189 ConsoleStatus console;
190};
191
192} // namespace Core::HID
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
deleted file mode 100644
index a6e681e15..000000000
--- a/src/core/hid/emulated_controller.cpp
+++ /dev/null
@@ -1,1972 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <common/scope_exit.h>
6
7#include "common/polyfill_ranges.h"
8#include "common/thread.h"
9#include "core/hid/emulated_controller.h"
10#include "core/hid/input_converter.h"
11#include "core/hle/service/hid/hid_util.h"
12
13namespace Core::HID {
14constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
15constexpr s32 HID_TRIGGER_MAX = 0x7fff;
16constexpr u32 TURBO_BUTTON_DELAY = 4;
17// Use a common UUID for TAS and Virtual Gamepad
18constexpr Common::UUID TAS_UUID =
19 Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
20constexpr Common::UUID VIRTUAL_UUID =
21 Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
22
23EmulatedController::EmulatedController(NpadIdType npad_id_type_) : npad_id_type(npad_id_type_) {}
24
25EmulatedController::~EmulatedController() = default;
26
27NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerType type) {
28 switch (type) {
29 case Settings::ControllerType::ProController:
30 return NpadStyleIndex::ProController;
31 case Settings::ControllerType::DualJoyconDetached:
32 return NpadStyleIndex::JoyconDual;
33 case Settings::ControllerType::LeftJoycon:
34 return NpadStyleIndex::JoyconLeft;
35 case Settings::ControllerType::RightJoycon:
36 return NpadStyleIndex::JoyconRight;
37 case Settings::ControllerType::Handheld:
38 return NpadStyleIndex::Handheld;
39 case Settings::ControllerType::GameCube:
40 return NpadStyleIndex::GameCube;
41 case Settings::ControllerType::Pokeball:
42 return NpadStyleIndex::Pokeball;
43 case Settings::ControllerType::NES:
44 return NpadStyleIndex::NES;
45 case Settings::ControllerType::SNES:
46 return NpadStyleIndex::SNES;
47 case Settings::ControllerType::N64:
48 return NpadStyleIndex::N64;
49 case Settings::ControllerType::SegaGenesis:
50 return NpadStyleIndex::SegaGenesis;
51 default:
52 return NpadStyleIndex::ProController;
53 }
54}
55
56Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadStyleIndex type) {
57 switch (type) {
58 case NpadStyleIndex::ProController:
59 return Settings::ControllerType::ProController;
60 case NpadStyleIndex::JoyconDual:
61 return Settings::ControllerType::DualJoyconDetached;
62 case NpadStyleIndex::JoyconLeft:
63 return Settings::ControllerType::LeftJoycon;
64 case NpadStyleIndex::JoyconRight:
65 return Settings::ControllerType::RightJoycon;
66 case NpadStyleIndex::Handheld:
67 return Settings::ControllerType::Handheld;
68 case NpadStyleIndex::GameCube:
69 return Settings::ControllerType::GameCube;
70 case NpadStyleIndex::Pokeball:
71 return Settings::ControllerType::Pokeball;
72 case NpadStyleIndex::NES:
73 return Settings::ControllerType::NES;
74 case NpadStyleIndex::SNES:
75 return Settings::ControllerType::SNES;
76 case NpadStyleIndex::N64:
77 return Settings::ControllerType::N64;
78 case NpadStyleIndex::SegaGenesis:
79 return Settings::ControllerType::SegaGenesis;
80 default:
81 return Settings::ControllerType::ProController;
82 }
83}
84
85void EmulatedController::ReloadFromSettings() {
86 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
87 const auto& player = Settings::values.players.GetValue()[player_index];
88
89 for (std::size_t index = 0; index < player.buttons.size(); ++index) {
90 button_params[index] = Common::ParamPackage(player.buttons[index]);
91 }
92 for (std::size_t index = 0; index < player.analogs.size(); ++index) {
93 stick_params[index] = Common::ParamPackage(player.analogs[index]);
94 }
95 for (std::size_t index = 0; index < player.motions.size(); ++index) {
96 motion_params[index] = Common::ParamPackage(player.motions[index]);
97 }
98
99 controller.color_values = {};
100 ReloadColorsFromSettings();
101
102 ring_params[0] = Common::ParamPackage(Settings::values.ringcon_analogs);
103
104 // Other or debug controller should always be a pro controller
105 if (npad_id_type != NpadIdType::Other) {
106 SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type));
107 original_npad_type = npad_type;
108 } else {
109 SetNpadStyleIndex(NpadStyleIndex::ProController);
110 original_npad_type = npad_type;
111 }
112
113 Disconnect();
114 if (player.connected) {
115 Connect();
116 }
117
118 ReloadInput();
119}
120
121void EmulatedController::ReloadColorsFromSettings() {
122 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
123 const auto& player = Settings::values.players.GetValue()[player_index];
124
125 // Avoid updating colors if overridden by physical controller
126 if (controller.color_values[LeftIndex].body != 0 &&
127 controller.color_values[RightIndex].body != 0) {
128 return;
129 }
130
131 controller.colors_state.fullkey = {
132 .body = GetNpadColor(player.body_color_left),
133 .button = GetNpadColor(player.button_color_left),
134 };
135 controller.colors_state.left = {
136 .body = GetNpadColor(player.body_color_left),
137 .button = GetNpadColor(player.button_color_left),
138 };
139 controller.colors_state.right = {
140 .body = GetNpadColor(player.body_color_right),
141 .button = GetNpadColor(player.button_color_right),
142 };
143}
144
145void EmulatedController::LoadDevices() {
146 // TODO(german77): Use more buttons to detect the correct device
147 const auto left_joycon = button_params[Settings::NativeButton::DRight];
148 const auto right_joycon = button_params[Settings::NativeButton::A];
149
150 // Triggers for GC controllers
151 trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL];
152 trigger_params[RightIndex] = button_params[Settings::NativeButton::ZR];
153
154 color_params[LeftIndex] = left_joycon;
155 color_params[RightIndex] = right_joycon;
156 color_params[LeftIndex].Set("color", true);
157 color_params[RightIndex].Set("color", true);
158
159 battery_params[LeftIndex] = left_joycon;
160 battery_params[RightIndex] = right_joycon;
161 battery_params[LeftIndex].Set("battery", true);
162 battery_params[RightIndex].Set("battery", true);
163
164 camera_params[0] = right_joycon;
165 camera_params[0].Set("camera", true);
166 nfc_params[1] = right_joycon;
167 nfc_params[1].Set("nfc", true);
168
169 // Only map virtual devices to the first controller
170 if (npad_id_type == NpadIdType::Player1 || npad_id_type == NpadIdType::Handheld) {
171 camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"};
172 ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"};
173 nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"};
174 }
175
176 output_params[LeftIndex] = left_joycon;
177 output_params[RightIndex] = right_joycon;
178 output_params[2] = camera_params[1];
179 output_params[3] = nfc_params[0];
180 output_params[LeftIndex].Set("output", true);
181 output_params[RightIndex].Set("output", true);
182 output_params[2].Set("output", true);
183 output_params[3].Set("output", true);
184
185 LoadTASParams();
186 LoadVirtualGamepadParams();
187
188 std::ranges::transform(button_params, button_devices.begin(), Common::Input::CreateInputDevice);
189 std::ranges::transform(stick_params, stick_devices.begin(), Common::Input::CreateInputDevice);
190 std::ranges::transform(motion_params, motion_devices.begin(), Common::Input::CreateInputDevice);
191 std::ranges::transform(trigger_params, trigger_devices.begin(),
192 Common::Input::CreateInputDevice);
193 std::ranges::transform(battery_params, battery_devices.begin(),
194 Common::Input::CreateInputDevice);
195 std::ranges::transform(color_params, color_devices.begin(), Common::Input::CreateInputDevice);
196 std::ranges::transform(camera_params, camera_devices.begin(), Common::Input::CreateInputDevice);
197 std::ranges::transform(ring_params, ring_analog_devices.begin(),
198 Common::Input::CreateInputDevice);
199 std::ranges::transform(nfc_params, nfc_devices.begin(), Common::Input::CreateInputDevice);
200 std::ranges::transform(output_params, output_devices.begin(),
201 Common::Input::CreateOutputDevice);
202
203 // Initialize TAS devices
204 std::ranges::transform(tas_button_params, tas_button_devices.begin(),
205 Common::Input::CreateInputDevice);
206 std::ranges::transform(tas_stick_params, tas_stick_devices.begin(),
207 Common::Input::CreateInputDevice);
208
209 // Initialize virtual gamepad devices
210 std::ranges::transform(virtual_button_params, virtual_button_devices.begin(),
211 Common::Input::CreateInputDevice);
212 std::ranges::transform(virtual_stick_params, virtual_stick_devices.begin(),
213 Common::Input::CreateInputDevice);
214 std::ranges::transform(virtual_motion_params, virtual_motion_devices.begin(),
215 Common::Input::CreateInputDevice);
216}
217
218void EmulatedController::LoadTASParams() {
219 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
220 Common::ParamPackage common_params{};
221 common_params.Set("engine", "tas");
222 common_params.Set("port", static_cast<int>(player_index));
223 for (auto& param : tas_button_params) {
224 param = common_params;
225 }
226 for (auto& param : tas_stick_params) {
227 param = common_params;
228 }
229
230 // TODO(german77): Replace this with an input profile or something better
231 tas_button_params[Settings::NativeButton::A].Set("button", 0);
232 tas_button_params[Settings::NativeButton::B].Set("button", 1);
233 tas_button_params[Settings::NativeButton::X].Set("button", 2);
234 tas_button_params[Settings::NativeButton::Y].Set("button", 3);
235 tas_button_params[Settings::NativeButton::LStick].Set("button", 4);
236 tas_button_params[Settings::NativeButton::RStick].Set("button", 5);
237 tas_button_params[Settings::NativeButton::L].Set("button", 6);
238 tas_button_params[Settings::NativeButton::R].Set("button", 7);
239 tas_button_params[Settings::NativeButton::ZL].Set("button", 8);
240 tas_button_params[Settings::NativeButton::ZR].Set("button", 9);
241 tas_button_params[Settings::NativeButton::Plus].Set("button", 10);
242 tas_button_params[Settings::NativeButton::Minus].Set("button", 11);
243 tas_button_params[Settings::NativeButton::DLeft].Set("button", 12);
244 tas_button_params[Settings::NativeButton::DUp].Set("button", 13);
245 tas_button_params[Settings::NativeButton::DRight].Set("button", 14);
246 tas_button_params[Settings::NativeButton::DDown].Set("button", 15);
247 tas_button_params[Settings::NativeButton::SLLeft].Set("button", 16);
248 tas_button_params[Settings::NativeButton::SRLeft].Set("button", 17);
249 tas_button_params[Settings::NativeButton::Home].Set("button", 18);
250 tas_button_params[Settings::NativeButton::Screenshot].Set("button", 19);
251 tas_button_params[Settings::NativeButton::SLRight].Set("button", 20);
252 tas_button_params[Settings::NativeButton::SRRight].Set("button", 21);
253
254 tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0);
255 tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
256 tas_stick_params[Settings::NativeAnalog::RStick].Set("axis_x", 2);
257 tas_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3);
258
259 // set to optimal stick to avoid sanitizing the stick and tweaking the coordinates
260 // making sure they play back in the game as originally written down in the script file
261 tas_stick_params[Settings::NativeAnalog::LStick].Set("deadzone", 0.0f);
262 tas_stick_params[Settings::NativeAnalog::LStick].Set("range", 1.0f);
263 tas_stick_params[Settings::NativeAnalog::RStick].Set("deadzone", 0.0f);
264 tas_stick_params[Settings::NativeAnalog::RStick].Set("range", 1.0f);
265}
266
267void EmulatedController::LoadVirtualGamepadParams() {
268 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
269 Common::ParamPackage common_params{};
270 common_params.Set("engine", "virtual_gamepad");
271 common_params.Set("port", static_cast<int>(player_index));
272 for (auto& param : virtual_button_params) {
273 param = common_params;
274 }
275 for (auto& param : virtual_stick_params) {
276 param = common_params;
277 }
278 for (auto& param : virtual_stick_params) {
279 param = common_params;
280 }
281 for (auto& param : virtual_motion_params) {
282 param = common_params;
283 }
284
285 // TODO(german77): Replace this with an input profile or something better
286 virtual_button_params[Settings::NativeButton::A].Set("button", 0);
287 virtual_button_params[Settings::NativeButton::B].Set("button", 1);
288 virtual_button_params[Settings::NativeButton::X].Set("button", 2);
289 virtual_button_params[Settings::NativeButton::Y].Set("button", 3);
290 virtual_button_params[Settings::NativeButton::LStick].Set("button", 4);
291 virtual_button_params[Settings::NativeButton::RStick].Set("button", 5);
292 virtual_button_params[Settings::NativeButton::L].Set("button", 6);
293 virtual_button_params[Settings::NativeButton::R].Set("button", 7);
294 virtual_button_params[Settings::NativeButton::ZL].Set("button", 8);
295 virtual_button_params[Settings::NativeButton::ZR].Set("button", 9);
296 virtual_button_params[Settings::NativeButton::Plus].Set("button", 10);
297 virtual_button_params[Settings::NativeButton::Minus].Set("button", 11);
298 virtual_button_params[Settings::NativeButton::DLeft].Set("button", 12);
299 virtual_button_params[Settings::NativeButton::DUp].Set("button", 13);
300 virtual_button_params[Settings::NativeButton::DRight].Set("button", 14);
301 virtual_button_params[Settings::NativeButton::DDown].Set("button", 15);
302 virtual_button_params[Settings::NativeButton::SLLeft].Set("button", 16);
303 virtual_button_params[Settings::NativeButton::SRLeft].Set("button", 17);
304 virtual_button_params[Settings::NativeButton::Home].Set("button", 18);
305 virtual_button_params[Settings::NativeButton::Screenshot].Set("button", 19);
306 virtual_button_params[Settings::NativeButton::SLRight].Set("button", 20);
307 virtual_button_params[Settings::NativeButton::SRRight].Set("button", 21);
308
309 virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0);
310 virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
311 virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_x", 2);
312 virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3);
313 virtual_stick_params[Settings::NativeAnalog::LStick].Set("deadzone", 0.0f);
314 virtual_stick_params[Settings::NativeAnalog::LStick].Set("range", 1.0f);
315 virtual_stick_params[Settings::NativeAnalog::RStick].Set("deadzone", 0.0f);
316 virtual_stick_params[Settings::NativeAnalog::RStick].Set("range", 1.0f);
317
318 virtual_motion_params[Settings::NativeMotion::MotionLeft].Set("motion", 0);
319 virtual_motion_params[Settings::NativeMotion::MotionRight].Set("motion", 0);
320}
321
322void EmulatedController::ReloadInput() {
323 // If you load any device here add the equivalent to the UnloadInput() function
324 LoadDevices();
325 for (std::size_t index = 0; index < button_devices.size(); ++index) {
326 if (!button_devices[index]) {
327 continue;
328 }
329 const auto uuid = Common::UUID{button_params[index].Get("guid", "")};
330 button_devices[index]->SetCallback({
331 .on_change =
332 [this, index, uuid](const Common::Input::CallbackStatus& callback) {
333 SetButton(callback, index, uuid);
334 },
335 });
336 button_devices[index]->ForceUpdate();
337 }
338
339 for (std::size_t index = 0; index < stick_devices.size(); ++index) {
340 if (!stick_devices[index]) {
341 continue;
342 }
343 const auto uuid = Common::UUID{stick_params[index].Get("guid", "")};
344 stick_devices[index]->SetCallback({
345 .on_change =
346 [this, index, uuid](const Common::Input::CallbackStatus& callback) {
347 SetStick(callback, index, uuid);
348 },
349 });
350 stick_devices[index]->ForceUpdate();
351 }
352
353 for (std::size_t index = 0; index < trigger_devices.size(); ++index) {
354 if (!trigger_devices[index]) {
355 continue;
356 }
357 const auto uuid = Common::UUID{trigger_params[index].Get("guid", "")};
358 trigger_devices[index]->SetCallback({
359 .on_change =
360 [this, index, uuid](const Common::Input::CallbackStatus& callback) {
361 SetTrigger(callback, index, uuid);
362 },
363 });
364 trigger_devices[index]->ForceUpdate();
365 }
366
367 for (std::size_t index = 0; index < battery_devices.size(); ++index) {
368 if (!battery_devices[index]) {
369 continue;
370 }
371 battery_devices[index]->SetCallback({
372 .on_change =
373 [this, index](const Common::Input::CallbackStatus& callback) {
374 SetBattery(callback, index);
375 },
376 });
377 battery_devices[index]->ForceUpdate();
378 }
379
380 for (std::size_t index = 0; index < color_devices.size(); ++index) {
381 if (!color_devices[index]) {
382 continue;
383 }
384 color_devices[index]->SetCallback({
385 .on_change =
386 [this, index](const Common::Input::CallbackStatus& callback) {
387 SetColors(callback, index);
388 },
389 });
390 color_devices[index]->ForceUpdate();
391 }
392
393 for (std::size_t index = 0; index < motion_devices.size(); ++index) {
394 if (!motion_devices[index]) {
395 continue;
396 }
397 motion_devices[index]->SetCallback({
398 .on_change =
399 [this, index](const Common::Input::CallbackStatus& callback) {
400 SetMotion(callback, index);
401 },
402 });
403
404 // Restore motion state
405 auto& emulated_motion = controller.motion_values[index].emulated;
406 auto& motion = controller.motion_state[index];
407 emulated_motion.ResetRotations();
408 emulated_motion.ResetQuaternion();
409 motion.accel = emulated_motion.GetAcceleration();
410 motion.gyro = emulated_motion.GetGyroscope();
411 motion.rotation = emulated_motion.GetRotations();
412 motion.euler = emulated_motion.GetEulerAngles();
413 motion.orientation = emulated_motion.GetOrientation();
414 motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity);
415 }
416
417 for (std::size_t index = 0; index < camera_devices.size(); ++index) {
418 if (!camera_devices[index]) {
419 continue;
420 }
421 camera_devices[index]->SetCallback({
422 .on_change =
423 [this](const Common::Input::CallbackStatus& callback) { SetCamera(callback); },
424 });
425 camera_devices[index]->ForceUpdate();
426 }
427
428 for (std::size_t index = 0; index < ring_analog_devices.size(); ++index) {
429 if (!ring_analog_devices[index]) {
430 continue;
431 }
432 ring_analog_devices[index]->SetCallback({
433 .on_change =
434 [this](const Common::Input::CallbackStatus& callback) { SetRingAnalog(callback); },
435 });
436 ring_analog_devices[index]->ForceUpdate();
437 }
438
439 for (std::size_t index = 0; index < nfc_devices.size(); ++index) {
440 if (!nfc_devices[index]) {
441 continue;
442 }
443 nfc_devices[index]->SetCallback({
444 .on_change =
445 [this](const Common::Input::CallbackStatus& callback) { SetNfc(callback); },
446 });
447 nfc_devices[index]->ForceUpdate();
448 }
449
450 // Register TAS devices. No need to force update
451 for (std::size_t index = 0; index < tas_button_devices.size(); ++index) {
452 if (!tas_button_devices[index]) {
453 continue;
454 }
455 tas_button_devices[index]->SetCallback({
456 .on_change =
457 [this, index](const Common::Input::CallbackStatus& callback) {
458 SetButton(callback, index, TAS_UUID);
459 },
460 });
461 }
462
463 for (std::size_t index = 0; index < tas_stick_devices.size(); ++index) {
464 if (!tas_stick_devices[index]) {
465 continue;
466 }
467 tas_stick_devices[index]->SetCallback({
468 .on_change =
469 [this, index](const Common::Input::CallbackStatus& callback) {
470 SetStick(callback, index, TAS_UUID);
471 },
472 });
473 }
474
475 // Register virtual devices. No need to force update
476 for (std::size_t index = 0; index < virtual_button_devices.size(); ++index) {
477 if (!virtual_button_devices[index]) {
478 continue;
479 }
480 virtual_button_devices[index]->SetCallback({
481 .on_change =
482 [this, index](const Common::Input::CallbackStatus& callback) {
483 SetButton(callback, index, VIRTUAL_UUID);
484 },
485 });
486 }
487
488 for (std::size_t index = 0; index < virtual_stick_devices.size(); ++index) {
489 if (!virtual_stick_devices[index]) {
490 continue;
491 }
492 virtual_stick_devices[index]->SetCallback({
493 .on_change =
494 [this, index](const Common::Input::CallbackStatus& callback) {
495 SetStick(callback, index, VIRTUAL_UUID);
496 },
497 });
498 }
499
500 for (std::size_t index = 0; index < virtual_motion_devices.size(); ++index) {
501 if (!virtual_motion_devices[index]) {
502 continue;
503 }
504 virtual_motion_devices[index]->SetCallback({
505 .on_change =
506 [this, index](const Common::Input::CallbackStatus& callback) {
507 SetMotion(callback, index);
508 },
509 });
510 }
511 turbo_button_state = 0;
512 is_initalized = true;
513}
514
515void EmulatedController::UnloadInput() {
516 is_initalized = false;
517 for (auto& button : button_devices) {
518 button.reset();
519 }
520 for (auto& stick : stick_devices) {
521 stick.reset();
522 }
523 for (auto& motion : motion_devices) {
524 motion.reset();
525 }
526 for (auto& trigger : trigger_devices) {
527 trigger.reset();
528 }
529 for (auto& battery : battery_devices) {
530 battery.reset();
531 }
532 for (auto& color : color_devices) {
533 color.reset();
534 }
535 for (auto& output : output_devices) {
536 output.reset();
537 }
538 for (auto& button : tas_button_devices) {
539 button.reset();
540 }
541 for (auto& stick : tas_stick_devices) {
542 stick.reset();
543 }
544 for (auto& button : virtual_button_devices) {
545 button.reset();
546 }
547 for (auto& stick : virtual_stick_devices) {
548 stick.reset();
549 }
550 for (auto& motion : virtual_motion_devices) {
551 motion.reset();
552 }
553 for (auto& camera : camera_devices) {
554 camera.reset();
555 }
556 for (auto& ring : ring_analog_devices) {
557 ring.reset();
558 }
559 for (auto& nfc : nfc_devices) {
560 nfc.reset();
561 }
562}
563
564void EmulatedController::EnableConfiguration() {
565 std::scoped_lock lock{connect_mutex, npad_mutex};
566 is_configuring = true;
567 tmp_is_connected = is_connected;
568 tmp_npad_type = npad_type;
569}
570
571void EmulatedController::DisableConfiguration() {
572 is_configuring = false;
573
574 // Get Joycon colors before turning on the controller
575 for (const auto& color_device : color_devices) {
576 color_device->ForceUpdate();
577 }
578
579 // Apply temporary npad type to the real controller
580 if (tmp_npad_type != npad_type) {
581 if (is_connected) {
582 Disconnect();
583 }
584 SetNpadStyleIndex(tmp_npad_type);
585 original_npad_type = tmp_npad_type;
586 }
587
588 // Apply temporary connected status to the real controller
589 if (tmp_is_connected != is_connected) {
590 if (tmp_is_connected) {
591 Connect();
592 return;
593 }
594 Disconnect();
595 }
596}
597
598void EmulatedController::EnableSystemButtons() {
599 std::scoped_lock lock{mutex};
600 system_buttons_enabled = true;
601}
602
603void EmulatedController::DisableSystemButtons() {
604 std::scoped_lock lock{mutex};
605 system_buttons_enabled = false;
606 controller.home_button_state.raw = 0;
607 controller.capture_button_state.raw = 0;
608}
609
610void EmulatedController::ResetSystemButtons() {
611 std::scoped_lock lock{mutex};
612 controller.home_button_state.home.Assign(false);
613 controller.capture_button_state.capture.Assign(false);
614}
615
616bool EmulatedController::IsConfiguring() const {
617 return is_configuring;
618}
619
620void EmulatedController::SaveCurrentConfig() {
621 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
622 auto& player = Settings::values.players.GetValue()[player_index];
623 player.connected = is_connected;
624 player.controller_type = MapNPadToSettingsType(npad_type);
625 for (std::size_t index = 0; index < player.buttons.size(); ++index) {
626 player.buttons[index] = button_params[index].Serialize();
627 }
628 for (std::size_t index = 0; index < player.analogs.size(); ++index) {
629 player.analogs[index] = stick_params[index].Serialize();
630 }
631 for (std::size_t index = 0; index < player.motions.size(); ++index) {
632 player.motions[index] = motion_params[index].Serialize();
633 }
634 if (npad_id_type == NpadIdType::Player1) {
635 Settings::values.ringcon_analogs = ring_params[0].Serialize();
636 }
637}
638
639void EmulatedController::RestoreConfig() {
640 if (!is_configuring) {
641 return;
642 }
643 ReloadFromSettings();
644}
645
646std::vector<Common::ParamPackage> EmulatedController::GetMappedDevices() const {
647 std::vector<Common::ParamPackage> devices;
648 for (const auto& param : button_params) {
649 if (!param.Has("engine")) {
650 continue;
651 }
652 const auto devices_it = std::find_if(
653 devices.begin(), devices.end(), [&param](const Common::ParamPackage& param_) {
654 return param.Get("engine", "") == param_.Get("engine", "") &&
655 param.Get("guid", "") == param_.Get("guid", "") &&
656 param.Get("port", 0) == param_.Get("port", 0) &&
657 param.Get("pad", 0) == param_.Get("pad", 0);
658 });
659 if (devices_it != devices.end()) {
660 continue;
661 }
662
663 auto& device = devices.emplace_back();
664 device.Set("engine", param.Get("engine", ""));
665 device.Set("guid", param.Get("guid", ""));
666 device.Set("port", param.Get("port", 0));
667 device.Set("pad", param.Get("pad", 0));
668 }
669
670 for (const auto& param : stick_params) {
671 if (!param.Has("engine")) {
672 continue;
673 }
674 if (param.Get("engine", "") == "analog_from_button") {
675 continue;
676 }
677 const auto devices_it = std::find_if(
678 devices.begin(), devices.end(), [&param](const Common::ParamPackage& param_) {
679 return param.Get("engine", "") == param_.Get("engine", "") &&
680 param.Get("guid", "") == param_.Get("guid", "") &&
681 param.Get("port", 0) == param_.Get("port", 0) &&
682 param.Get("pad", 0) == param_.Get("pad", 0);
683 });
684 if (devices_it != devices.end()) {
685 continue;
686 }
687
688 auto& device = devices.emplace_back();
689 device.Set("engine", param.Get("engine", ""));
690 device.Set("guid", param.Get("guid", ""));
691 device.Set("port", param.Get("port", 0));
692 device.Set("pad", param.Get("pad", 0));
693 }
694 return devices;
695}
696
697Common::ParamPackage EmulatedController::GetButtonParam(std::size_t index) const {
698 if (index >= button_params.size()) {
699 return {};
700 }
701 return button_params[index];
702}
703
704Common::ParamPackage EmulatedController::GetStickParam(std::size_t index) const {
705 if (index >= stick_params.size()) {
706 return {};
707 }
708 return stick_params[index];
709}
710
711Common::ParamPackage EmulatedController::GetMotionParam(std::size_t index) const {
712 if (index >= motion_params.size()) {
713 return {};
714 }
715 return motion_params[index];
716}
717
718void EmulatedController::SetButtonParam(std::size_t index, Common::ParamPackage param) {
719 if (index >= button_params.size()) {
720 return;
721 }
722 button_params[index] = std::move(param);
723 ReloadInput();
724}
725
726void EmulatedController::SetStickParam(std::size_t index, Common::ParamPackage param) {
727 if (index >= stick_params.size()) {
728 return;
729 }
730 stick_params[index] = std::move(param);
731 ReloadInput();
732}
733
734void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage param) {
735 if (index >= motion_params.size()) {
736 return;
737 }
738 motion_params[index] = std::move(param);
739 ReloadInput();
740}
741
742void EmulatedController::StartMotionCalibration() {
743 for (ControllerMotionInfo& motion : controller.motion_values) {
744 motion.emulated.Calibrate();
745 }
746}
747
748void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
749 Common::UUID uuid) {
750 if (index >= controller.button_values.size()) {
751 return;
752 }
753 std::unique_lock lock{mutex};
754 bool value_changed = false;
755 const auto new_status = TransformToButton(callback);
756 auto& current_status = controller.button_values[index];
757
758 // Only read button values that have the same uuid or are pressed once
759 if (current_status.uuid != uuid) {
760 if (!new_status.value) {
761 return;
762 }
763 }
764
765 current_status.toggle = new_status.toggle;
766 current_status.turbo = new_status.turbo;
767 current_status.uuid = uuid;
768
769 // Update button status with current
770 if (!current_status.toggle) {
771 current_status.locked = false;
772 if (current_status.value != new_status.value) {
773 current_status.value = new_status.value;
774 value_changed = true;
775 }
776 } else {
777 // Toggle button and lock status
778 if (new_status.value && !current_status.locked) {
779 current_status.locked = true;
780 current_status.value = !current_status.value;
781 value_changed = true;
782 }
783
784 // Unlock button ready for next press
785 if (!new_status.value && current_status.locked) {
786 current_status.locked = false;
787 }
788 }
789
790 if (!value_changed) {
791 return;
792 }
793
794 if (is_configuring) {
795 controller.npad_button_state.raw = NpadButton::None;
796 controller.debug_pad_button_state.raw = 0;
797 controller.home_button_state.raw = 0;
798 controller.capture_button_state.raw = 0;
799 lock.unlock();
800 TriggerOnChange(ControllerTriggerType::Button, false);
801 return;
802 }
803
804 // GC controllers have triggers not buttons
805 if (npad_type == NpadStyleIndex::GameCube) {
806 if (index == Settings::NativeButton::ZR) {
807 return;
808 }
809 if (index == Settings::NativeButton::ZL) {
810 return;
811 }
812 }
813
814 switch (index) {
815 case Settings::NativeButton::A:
816 controller.npad_button_state.a.Assign(current_status.value);
817 controller.debug_pad_button_state.a.Assign(current_status.value);
818 break;
819 case Settings::NativeButton::B:
820 controller.npad_button_state.b.Assign(current_status.value);
821 controller.debug_pad_button_state.b.Assign(current_status.value);
822 break;
823 case Settings::NativeButton::X:
824 controller.npad_button_state.x.Assign(current_status.value);
825 controller.debug_pad_button_state.x.Assign(current_status.value);
826 break;
827 case Settings::NativeButton::Y:
828 controller.npad_button_state.y.Assign(current_status.value);
829 controller.debug_pad_button_state.y.Assign(current_status.value);
830 break;
831 case Settings::NativeButton::LStick:
832 controller.npad_button_state.stick_l.Assign(current_status.value);
833 break;
834 case Settings::NativeButton::RStick:
835 controller.npad_button_state.stick_r.Assign(current_status.value);
836 break;
837 case Settings::NativeButton::L:
838 controller.npad_button_state.l.Assign(current_status.value);
839 controller.debug_pad_button_state.l.Assign(current_status.value);
840 break;
841 case Settings::NativeButton::R:
842 controller.npad_button_state.r.Assign(current_status.value);
843 controller.debug_pad_button_state.r.Assign(current_status.value);
844 break;
845 case Settings::NativeButton::ZL:
846 controller.npad_button_state.zl.Assign(current_status.value);
847 controller.debug_pad_button_state.zl.Assign(current_status.value);
848 break;
849 case Settings::NativeButton::ZR:
850 controller.npad_button_state.zr.Assign(current_status.value);
851 controller.debug_pad_button_state.zr.Assign(current_status.value);
852 break;
853 case Settings::NativeButton::Plus:
854 controller.npad_button_state.plus.Assign(current_status.value);
855 controller.debug_pad_button_state.plus.Assign(current_status.value);
856 break;
857 case Settings::NativeButton::Minus:
858 controller.npad_button_state.minus.Assign(current_status.value);
859 controller.debug_pad_button_state.minus.Assign(current_status.value);
860 break;
861 case Settings::NativeButton::DLeft:
862 controller.npad_button_state.left.Assign(current_status.value);
863 controller.debug_pad_button_state.d_left.Assign(current_status.value);
864 break;
865 case Settings::NativeButton::DUp:
866 controller.npad_button_state.up.Assign(current_status.value);
867 controller.debug_pad_button_state.d_up.Assign(current_status.value);
868 break;
869 case Settings::NativeButton::DRight:
870 controller.npad_button_state.right.Assign(current_status.value);
871 controller.debug_pad_button_state.d_right.Assign(current_status.value);
872 break;
873 case Settings::NativeButton::DDown:
874 controller.npad_button_state.down.Assign(current_status.value);
875 controller.debug_pad_button_state.d_down.Assign(current_status.value);
876 break;
877 case Settings::NativeButton::SLLeft:
878 controller.npad_button_state.left_sl.Assign(current_status.value);
879 break;
880 case Settings::NativeButton::SLRight:
881 controller.npad_button_state.right_sl.Assign(current_status.value);
882 break;
883 case Settings::NativeButton::SRLeft:
884 controller.npad_button_state.left_sr.Assign(current_status.value);
885 break;
886 case Settings::NativeButton::SRRight:
887 controller.npad_button_state.right_sr.Assign(current_status.value);
888 break;
889 case Settings::NativeButton::Home:
890 if (!system_buttons_enabled) {
891 break;
892 }
893 controller.home_button_state.home.Assign(current_status.value);
894 break;
895 case Settings::NativeButton::Screenshot:
896 if (!system_buttons_enabled) {
897 break;
898 }
899 controller.capture_button_state.capture.Assign(current_status.value);
900 break;
901 }
902
903 lock.unlock();
904
905 if (!is_connected) {
906 if (npad_id_type == NpadIdType::Player1 && npad_type != NpadStyleIndex::Handheld) {
907 Connect();
908 }
909 if (npad_id_type == NpadIdType::Handheld && npad_type == NpadStyleIndex::Handheld) {
910 Connect();
911 }
912 }
913 TriggerOnChange(ControllerTriggerType::Button, true);
914}
915
916void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
917 Common::UUID uuid) {
918 if (index >= controller.stick_values.size()) {
919 return;
920 }
921 auto trigger_guard =
922 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); });
923 std::scoped_lock lock{mutex};
924 const auto stick_value = TransformToStick(callback);
925
926 // Only read stick values that have the same uuid or are over the threshold to avoid flapping
927 if (controller.stick_values[index].uuid != uuid) {
928 const bool is_tas = uuid == TAS_UUID;
929 if (is_tas && stick_value.x.value == 0 && stick_value.y.value == 0) {
930 trigger_guard.Cancel();
931 return;
932 }
933 if (!is_tas && !stick_value.down && !stick_value.up && !stick_value.left &&
934 !stick_value.right) {
935 trigger_guard.Cancel();
936 return;
937 }
938 }
939
940 controller.stick_values[index] = stick_value;
941 controller.stick_values[index].uuid = uuid;
942
943 if (is_configuring) {
944 controller.analog_stick_state.left = {};
945 controller.analog_stick_state.right = {};
946 return;
947 }
948
949 const AnalogStickState stick{
950 .x = static_cast<s32>(controller.stick_values[index].x.value * HID_JOYSTICK_MAX),
951 .y = static_cast<s32>(controller.stick_values[index].y.value * HID_JOYSTICK_MAX),
952 };
953
954 switch (index) {
955 case Settings::NativeAnalog::LStick:
956 controller.analog_stick_state.left = stick;
957 controller.npad_button_state.stick_l_left.Assign(controller.stick_values[index].left);
958 controller.npad_button_state.stick_l_up.Assign(controller.stick_values[index].up);
959 controller.npad_button_state.stick_l_right.Assign(controller.stick_values[index].right);
960 controller.npad_button_state.stick_l_down.Assign(controller.stick_values[index].down);
961 break;
962 case Settings::NativeAnalog::RStick:
963 controller.analog_stick_state.right = stick;
964 controller.npad_button_state.stick_r_left.Assign(controller.stick_values[index].left);
965 controller.npad_button_state.stick_r_up.Assign(controller.stick_values[index].up);
966 controller.npad_button_state.stick_r_right.Assign(controller.stick_values[index].right);
967 controller.npad_button_state.stick_r_down.Assign(controller.stick_values[index].down);
968 break;
969 }
970}
971
972void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callback,
973 std::size_t index, Common::UUID uuid) {
974 if (index >= controller.trigger_values.size()) {
975 return;
976 }
977 auto trigger_guard =
978 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); });
979 std::scoped_lock lock{mutex};
980 const auto trigger_value = TransformToTrigger(callback);
981
982 // Only read trigger values that have the same uuid or are pressed once
983 if (controller.trigger_values[index].uuid != uuid) {
984 if (!trigger_value.pressed.value) {
985 return;
986 }
987 }
988
989 controller.trigger_values[index] = trigger_value;
990 controller.trigger_values[index].uuid = uuid;
991
992 if (is_configuring) {
993 controller.gc_trigger_state.left = 0;
994 controller.gc_trigger_state.right = 0;
995 return;
996 }
997
998 // Only GC controllers have analog triggers
999 if (npad_type != NpadStyleIndex::GameCube) {
1000 trigger_guard.Cancel();
1001 return;
1002 }
1003
1004 const auto& trigger = controller.trigger_values[index];
1005
1006 switch (index) {
1007 case Settings::NativeTrigger::LTrigger:
1008 controller.gc_trigger_state.left = static_cast<s32>(trigger.analog.value * HID_TRIGGER_MAX);
1009 controller.npad_button_state.zl.Assign(trigger.pressed.value);
1010 break;
1011 case Settings::NativeTrigger::RTrigger:
1012 controller.gc_trigger_state.right =
1013 static_cast<s32>(trigger.analog.value * HID_TRIGGER_MAX);
1014 controller.npad_button_state.zr.Assign(trigger.pressed.value);
1015 break;
1016 }
1017}
1018
1019void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback,
1020 std::size_t index) {
1021 if (index >= controller.motion_values.size()) {
1022 return;
1023 }
1024 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); });
1025 std::scoped_lock lock{mutex};
1026 auto& raw_status = controller.motion_values[index].raw_status;
1027 auto& emulated = controller.motion_values[index].emulated;
1028
1029 raw_status = TransformToMotion(callback);
1030 emulated.SetAcceleration(Common::Vec3f{
1031 raw_status.accel.x.value,
1032 raw_status.accel.y.value,
1033 raw_status.accel.z.value,
1034 });
1035 emulated.SetGyroscope(Common::Vec3f{
1036 raw_status.gyro.x.value,
1037 raw_status.gyro.y.value,
1038 raw_status.gyro.z.value,
1039 });
1040 emulated.SetUserGyroThreshold(raw_status.gyro.x.properties.threshold);
1041 emulated.UpdateRotation(raw_status.delta_timestamp);
1042 emulated.UpdateOrientation(raw_status.delta_timestamp);
1043
1044 auto& motion = controller.motion_state[index];
1045 motion.accel = emulated.GetAcceleration();
1046 motion.gyro = emulated.GetGyroscope();
1047 motion.rotation = emulated.GetRotations();
1048 motion.euler = emulated.GetEulerAngles();
1049 motion.orientation = emulated.GetOrientation();
1050 motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
1051}
1052
1053void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback,
1054 std::size_t index) {
1055 if (index >= controller.color_values.size()) {
1056 return;
1057 }
1058 auto trigger_guard =
1059 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color, !is_configuring); });
1060 std::scoped_lock lock{mutex};
1061 controller.color_values[index] = TransformToColor(callback);
1062
1063 if (is_configuring) {
1064 return;
1065 }
1066
1067 if (controller.color_values[index].body == 0) {
1068 trigger_guard.Cancel();
1069 return;
1070 }
1071
1072 controller.colors_state.fullkey = {
1073 .body = GetNpadColor(controller.color_values[index].body),
1074 .button = GetNpadColor(controller.color_values[index].buttons),
1075 };
1076 if (npad_type == NpadStyleIndex::ProController) {
1077 controller.colors_state.left = {
1078 .body = GetNpadColor(controller.color_values[index].left_grip),
1079 .button = GetNpadColor(controller.color_values[index].buttons),
1080 };
1081 controller.colors_state.right = {
1082 .body = GetNpadColor(controller.color_values[index].right_grip),
1083 .button = GetNpadColor(controller.color_values[index].buttons),
1084 };
1085 } else {
1086 switch (index) {
1087 case LeftIndex:
1088 controller.colors_state.left = {
1089 .body = GetNpadColor(controller.color_values[index].body),
1090 .button = GetNpadColor(controller.color_values[index].buttons),
1091 };
1092 break;
1093 case RightIndex:
1094 controller.colors_state.right = {
1095 .body = GetNpadColor(controller.color_values[index].body),
1096 .button = GetNpadColor(controller.color_values[index].buttons),
1097 };
1098 break;
1099 }
1100 }
1101}
1102
1103void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback,
1104 std::size_t index) {
1105 if (index >= controller.battery_values.size()) {
1106 return;
1107 }
1108 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); });
1109 std::scoped_lock lock{mutex};
1110 controller.battery_values[index] = TransformToBattery(callback);
1111
1112 if (is_configuring) {
1113 return;
1114 }
1115
1116 bool is_charging = false;
1117 bool is_powered = false;
1118 NpadBatteryLevel battery_level = NpadBatteryLevel::Empty;
1119 switch (controller.battery_values[index]) {
1120 case Common::Input::BatteryLevel::Charging:
1121 is_charging = true;
1122 is_powered = true;
1123 battery_level = NpadBatteryLevel::Full;
1124 break;
1125 case Common::Input::BatteryLevel::Medium:
1126 battery_level = NpadBatteryLevel::High;
1127 break;
1128 case Common::Input::BatteryLevel::Low:
1129 battery_level = NpadBatteryLevel::Low;
1130 break;
1131 case Common::Input::BatteryLevel::Critical:
1132 battery_level = NpadBatteryLevel::Critical;
1133 break;
1134 case Common::Input::BatteryLevel::Empty:
1135 battery_level = NpadBatteryLevel::Empty;
1136 break;
1137 case Common::Input::BatteryLevel::None:
1138 case Common::Input::BatteryLevel::Full:
1139 default:
1140 is_powered = true;
1141 battery_level = NpadBatteryLevel::Full;
1142 break;
1143 }
1144
1145 switch (index) {
1146 case LeftIndex:
1147 controller.battery_state.left = {
1148 .is_powered = is_powered,
1149 .is_charging = is_charging,
1150 .battery_level = battery_level,
1151 };
1152 break;
1153 case RightIndex:
1154 controller.battery_state.right = {
1155 .is_powered = is_powered,
1156 .is_charging = is_charging,
1157 .battery_level = battery_level,
1158 };
1159 break;
1160 case DualIndex:
1161 controller.battery_state.dual = {
1162 .is_powered = is_powered,
1163 .is_charging = is_charging,
1164 .battery_level = battery_level,
1165 };
1166 break;
1167 }
1168}
1169
1170void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) {
1171 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); });
1172 std::scoped_lock lock{mutex};
1173 controller.camera_values = TransformToCamera(callback);
1174
1175 if (is_configuring) {
1176 return;
1177 }
1178
1179 controller.camera_state.sample++;
1180 controller.camera_state.format =
1181 static_cast<Core::IrSensor::ImageTransferProcessorFormat>(controller.camera_values.format);
1182 controller.camera_state.data = controller.camera_values.data;
1183}
1184
1185void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) {
1186 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); });
1187 std::scoped_lock lock{mutex};
1188 const auto force_value = TransformToStick(callback);
1189
1190 controller.ring_analog_value = force_value.x;
1191
1192 if (is_configuring) {
1193 return;
1194 }
1195
1196 controller.ring_analog_state.force = force_value.x.value;
1197}
1198
1199void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
1200 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); });
1201 std::scoped_lock lock{mutex};
1202 controller.nfc_values = TransformToNfc(callback);
1203
1204 if (is_configuring) {
1205 return;
1206 }
1207
1208 controller.nfc_state = controller.nfc_values;
1209}
1210
1211bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) {
1212 if (!is_initalized) {
1213 return false;
1214 }
1215 if (device_index >= output_devices.size()) {
1216 return false;
1217 }
1218 if (!output_devices[device_index]) {
1219 return false;
1220 }
1221 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
1222 const auto& player = Settings::values.players.GetValue()[player_index];
1223 const f32 strength = static_cast<f32>(player.vibration_strength) / 100.0f;
1224
1225 if (!player.vibration_enabled) {
1226 return false;
1227 }
1228
1229 // Exponential amplification is too strong at low amplitudes. Switch to a linear
1230 // amplification if strength is set below 0.7f
1231 const Common::Input::VibrationAmplificationType type =
1232 strength > 0.7f ? Common::Input::VibrationAmplificationType::Exponential
1233 : Common::Input::VibrationAmplificationType::Linear;
1234
1235 const Common::Input::VibrationStatus status = {
1236 .low_amplitude = std::min(vibration.low_amplitude * strength, 1.0f),
1237 .low_frequency = vibration.low_frequency,
1238 .high_amplitude = std::min(vibration.high_amplitude * strength, 1.0f),
1239 .high_frequency = vibration.high_frequency,
1240 .type = type,
1241 };
1242 return output_devices[device_index]->SetVibration(status) ==
1243 Common::Input::DriverResult::Success;
1244}
1245
1246bool EmulatedController::IsVibrationEnabled(std::size_t device_index) {
1247 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
1248 const auto& player = Settings::values.players.GetValue()[player_index];
1249
1250 if (!is_initalized) {
1251 return false;
1252 }
1253
1254 if (!player.vibration_enabled) {
1255 return false;
1256 }
1257
1258 if (device_index >= output_devices.size()) {
1259 return false;
1260 }
1261
1262 if (!output_devices[device_index]) {
1263 return false;
1264 }
1265
1266 return output_devices[device_index]->IsVibrationEnabled();
1267}
1268
1269Common::Input::DriverResult EmulatedController::SetPollingMode(
1270 EmulatedDeviceIndex device_index, Common::Input::PollingMode polling_mode) {
1271 LOG_INFO(Service_HID, "Set polling mode {}, device_index={}", polling_mode, device_index);
1272
1273 if (!is_initalized) {
1274 return Common::Input::DriverResult::InvalidHandle;
1275 }
1276
1277 auto& left_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Left)];
1278 auto& right_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
1279 auto& nfc_output_device = output_devices[3];
1280
1281 if (device_index == EmulatedDeviceIndex::LeftIndex) {
1282 controller.left_polling_mode = polling_mode;
1283 return left_output_device->SetPollingMode(polling_mode);
1284 }
1285
1286 if (device_index == EmulatedDeviceIndex::RightIndex) {
1287 controller.right_polling_mode = polling_mode;
1288 const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode);
1289 const auto mapped_nfc_result = right_output_device->SetPollingMode(polling_mode);
1290
1291 // Restore previous state
1292 if (mapped_nfc_result != Common::Input::DriverResult::Success) {
1293 right_output_device->SetPollingMode(Common::Input::PollingMode::Active);
1294 }
1295
1296 if (virtual_nfc_result == Common::Input::DriverResult::Success) {
1297 return virtual_nfc_result;
1298 }
1299 return mapped_nfc_result;
1300 }
1301
1302 controller.left_polling_mode = polling_mode;
1303 controller.right_polling_mode = polling_mode;
1304 left_output_device->SetPollingMode(polling_mode);
1305 right_output_device->SetPollingMode(polling_mode);
1306 nfc_output_device->SetPollingMode(polling_mode);
1307 return Common::Input::DriverResult::Success;
1308}
1309
1310Common::Input::PollingMode EmulatedController::GetPollingMode(
1311 EmulatedDeviceIndex device_index) const {
1312 if (device_index == EmulatedDeviceIndex::LeftIndex) {
1313 return controller.left_polling_mode;
1314 }
1315 return controller.right_polling_mode;
1316}
1317
1318bool EmulatedController::SetCameraFormat(
1319 Core::IrSensor::ImageTransferProcessorFormat camera_format) {
1320 LOG_INFO(Service_HID, "Set camera format {}", camera_format);
1321
1322 if (!is_initalized) {
1323 return false;
1324 }
1325
1326 auto& right_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
1327 auto& camera_output_device = output_devices[2];
1328
1329 if (right_output_device->SetCameraFormat(static_cast<Common::Input::CameraFormat>(
1330 camera_format)) == Common::Input::DriverResult::Success) {
1331 return true;
1332 }
1333
1334 // Fallback to Qt camera if native device doesn't have support
1335 return camera_output_device->SetCameraFormat(static_cast<Common::Input::CameraFormat>(
1336 camera_format)) == Common::Input::DriverResult::Success;
1337}
1338
1339Common::ParamPackage EmulatedController::GetRingParam() const {
1340 return ring_params[0];
1341}
1342
1343void EmulatedController::SetRingParam(Common::ParamPackage param) {
1344 ring_params[0] = std::move(param);
1345 ReloadInput();
1346}
1347
1348bool EmulatedController::HasNfc() const {
1349
1350 if (!is_initalized) {
1351 return false;
1352 }
1353
1354 const auto& nfc_output_device = output_devices[3];
1355
1356 switch (npad_type) {
1357 case NpadStyleIndex::JoyconRight:
1358 case NpadStyleIndex::JoyconDual:
1359 case NpadStyleIndex::ProController:
1360 case NpadStyleIndex::Handheld:
1361 break;
1362 default:
1363 return false;
1364 }
1365
1366 const bool has_virtual_nfc =
1367 npad_id_type == NpadIdType::Player1 || npad_id_type == NpadIdType::Handheld;
1368 const bool is_virtual_nfc_supported =
1369 nfc_output_device->SupportsNfc() != Common::Input::NfcState::NotSupported;
1370
1371 return is_connected && (has_virtual_nfc && is_virtual_nfc_supported);
1372}
1373
1374bool EmulatedController::AddNfcHandle() {
1375 nfc_handles++;
1376 return SetPollingMode(EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::NFC) ==
1377 Common::Input::DriverResult::Success;
1378}
1379
1380bool EmulatedController::RemoveNfcHandle() {
1381 nfc_handles--;
1382 if (nfc_handles <= 0) {
1383 return SetPollingMode(EmulatedDeviceIndex::RightIndex,
1384 Common::Input::PollingMode::Active) ==
1385 Common::Input::DriverResult::Success;
1386 }
1387 return true;
1388}
1389
1390bool EmulatedController::StartNfcPolling() {
1391 if (!is_initalized) {
1392 return false;
1393 }
1394
1395 auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
1396 auto& nfc_virtual_output_device = output_devices[3];
1397
1398 const auto device_result = nfc_output_device->StartNfcPolling();
1399 const auto virtual_device_result = nfc_virtual_output_device->StartNfcPolling();
1400
1401 return device_result == Common::Input::NfcState::Success ||
1402 virtual_device_result == Common::Input::NfcState::Success;
1403}
1404
1405bool EmulatedController::StopNfcPolling() {
1406 if (!is_initalized) {
1407 return false;
1408 }
1409
1410 auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
1411 auto& nfc_virtual_output_device = output_devices[3];
1412
1413 const auto device_result = nfc_output_device->StopNfcPolling();
1414 const auto virtual_device_result = nfc_virtual_output_device->StopNfcPolling();
1415
1416 return device_result == Common::Input::NfcState::Success ||
1417 virtual_device_result == Common::Input::NfcState::Success;
1418}
1419
1420bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) {
1421 if (!is_initalized) {
1422 return false;
1423 }
1424
1425 auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
1426 auto& nfc_virtual_output_device = output_devices[3];
1427
1428 if (nfc_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success) {
1429 return true;
1430 }
1431
1432 return nfc_virtual_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success;
1433}
1434
1435bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& request,
1436 Common::Input::MifareRequest& out_data) {
1437 if (!is_initalized) {
1438 return false;
1439 }
1440
1441 auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
1442 auto& nfc_virtual_output_device = output_devices[3];
1443
1444 if (nfc_output_device->ReadMifareData(request, out_data) == Common::Input::NfcState::Success) {
1445 return true;
1446 }
1447
1448 return nfc_virtual_output_device->ReadMifareData(request, out_data) ==
1449 Common::Input::NfcState::Success;
1450}
1451
1452bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& request) {
1453 if (!is_initalized) {
1454 return false;
1455 }
1456
1457 auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
1458 auto& nfc_virtual_output_device = output_devices[3];
1459
1460 if (nfc_output_device->WriteMifareData(request) == Common::Input::NfcState::Success) {
1461 return true;
1462 }
1463
1464 return nfc_virtual_output_device->WriteMifareData(request) == Common::Input::NfcState::Success;
1465}
1466
1467bool EmulatedController::WriteNfc(const std::vector<u8>& data) {
1468 if (!is_initalized) {
1469 return false;
1470 }
1471
1472 auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
1473 auto& nfc_virtual_output_device = output_devices[3];
1474
1475 if (nfc_output_device->SupportsNfc() != Common::Input::NfcState::NotSupported) {
1476 return nfc_output_device->WriteNfcData(data) == Common::Input::NfcState::Success;
1477 }
1478
1479 return nfc_virtual_output_device->WriteNfcData(data) == Common::Input::NfcState::Success;
1480}
1481
1482void EmulatedController::SetLedPattern() {
1483 if (!is_initalized) {
1484 return;
1485 }
1486
1487 for (auto& device : output_devices) {
1488 if (!device) {
1489 continue;
1490 }
1491
1492 const LedPattern pattern = GetLedPattern();
1493 const Common::Input::LedStatus status = {
1494 .led_1 = pattern.position1 != 0,
1495 .led_2 = pattern.position2 != 0,
1496 .led_3 = pattern.position3 != 0,
1497 .led_4 = pattern.position4 != 0,
1498 };
1499 device->SetLED(status);
1500 }
1501}
1502
1503void EmulatedController::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode mode) {
1504 for (auto& motion : controller.motion_values) {
1505 switch (mode) {
1506 case GyroscopeZeroDriftMode::Loose:
1507 motion_sensitivity = motion.emulated.IsAtRestLoose;
1508 motion.emulated.SetGyroThreshold(motion.emulated.ThresholdLoose);
1509 break;
1510 case GyroscopeZeroDriftMode::Tight:
1511 motion_sensitivity = motion.emulated.IsAtRestThight;
1512 motion.emulated.SetGyroThreshold(motion.emulated.ThresholdThight);
1513 break;
1514 case GyroscopeZeroDriftMode::Standard:
1515 default:
1516 motion_sensitivity = motion.emulated.IsAtRestStandard;
1517 motion.emulated.SetGyroThreshold(motion.emulated.ThresholdStandard);
1518 break;
1519 }
1520 }
1521}
1522
1523void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) {
1524 supported_style_tag = supported_styles;
1525 if (!is_connected) {
1526 return;
1527 }
1528
1529 // Attempt to reconnect with the original type
1530 if (npad_type != original_npad_type) {
1531 Disconnect();
1532 const auto current_npad_type = npad_type;
1533 SetNpadStyleIndex(original_npad_type);
1534 if (IsControllerSupported()) {
1535 Connect();
1536 return;
1537 }
1538 SetNpadStyleIndex(current_npad_type);
1539 Connect();
1540 }
1541
1542 if (IsControllerSupported()) {
1543 return;
1544 }
1545
1546 Disconnect();
1547
1548 // Fallback Fullkey controllers to Pro controllers
1549 if (IsControllerFullkey() && supported_style_tag.fullkey) {
1550 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
1551 SetNpadStyleIndex(NpadStyleIndex::ProController);
1552 Connect();
1553 return;
1554 }
1555
1556 // Fallback Dual joycon controllers to Pro controllers
1557 if (npad_type == NpadStyleIndex::JoyconDual && supported_style_tag.fullkey) {
1558 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
1559 SetNpadStyleIndex(NpadStyleIndex::ProController);
1560 Connect();
1561 return;
1562 }
1563
1564 // Fallback Pro controllers to Dual joycon
1565 if (npad_type == NpadStyleIndex::ProController && supported_style_tag.joycon_dual) {
1566 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Dual Joycons", npad_type);
1567 SetNpadStyleIndex(NpadStyleIndex::JoyconDual);
1568 Connect();
1569 return;
1570 }
1571
1572 LOG_ERROR(Service_HID, "Controller type {} is not supported. Disconnecting controller",
1573 npad_type);
1574}
1575
1576bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
1577 std::scoped_lock lock{mutex};
1578 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
1579 switch (type) {
1580 case NpadStyleIndex::ProController:
1581 case NpadStyleIndex::GameCube:
1582 case NpadStyleIndex::NES:
1583 case NpadStyleIndex::SNES:
1584 case NpadStyleIndex::N64:
1585 case NpadStyleIndex::SegaGenesis:
1586 return true;
1587 default:
1588 return false;
1589 }
1590}
1591
1592bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
1593 std::scoped_lock lock{mutex};
1594 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
1595 switch (type) {
1596 case NpadStyleIndex::ProController:
1597 return supported_style_tag.fullkey.As<bool>();
1598 case NpadStyleIndex::Handheld:
1599 return supported_style_tag.handheld.As<bool>();
1600 case NpadStyleIndex::JoyconDual:
1601 return supported_style_tag.joycon_dual.As<bool>();
1602 case NpadStyleIndex::JoyconLeft:
1603 return supported_style_tag.joycon_left.As<bool>();
1604 case NpadStyleIndex::JoyconRight:
1605 return supported_style_tag.joycon_right.As<bool>();
1606 case NpadStyleIndex::GameCube:
1607 return supported_style_tag.gamecube.As<bool>();
1608 case NpadStyleIndex::Pokeball:
1609 return supported_style_tag.palma.As<bool>();
1610 case NpadStyleIndex::NES:
1611 return supported_style_tag.lark.As<bool>();
1612 case NpadStyleIndex::SNES:
1613 return supported_style_tag.lucia.As<bool>();
1614 case NpadStyleIndex::N64:
1615 return supported_style_tag.lagoon.As<bool>();
1616 case NpadStyleIndex::SegaGenesis:
1617 return supported_style_tag.lager.As<bool>();
1618 default:
1619 return false;
1620 }
1621}
1622
1623void EmulatedController::Connect(bool use_temporary_value) {
1624 if (!IsControllerSupported(use_temporary_value)) {
1625 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
1626 LOG_ERROR(Service_HID, "Controller type {} is not supported", type);
1627 return;
1628 }
1629
1630 auto trigger_guard =
1631 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); });
1632 std::scoped_lock lock{connect_mutex, mutex};
1633 if (is_configuring) {
1634 tmp_is_connected = true;
1635 return;
1636 }
1637
1638 if (is_connected) {
1639 trigger_guard.Cancel();
1640 return;
1641 }
1642 is_connected = true;
1643}
1644
1645void EmulatedController::Disconnect() {
1646 auto trigger_guard =
1647 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); });
1648 std::scoped_lock lock{connect_mutex, mutex};
1649 if (is_configuring) {
1650 tmp_is_connected = false;
1651 return;
1652 }
1653
1654 if (!is_connected) {
1655 trigger_guard.Cancel();
1656 return;
1657 }
1658 is_connected = false;
1659}
1660
1661bool EmulatedController::IsConnected(bool get_temporary_value) const {
1662 std::scoped_lock lock{connect_mutex};
1663 if (get_temporary_value && is_configuring) {
1664 return tmp_is_connected;
1665 }
1666 return is_connected;
1667}
1668
1669NpadIdType EmulatedController::GetNpadIdType() const {
1670 std::scoped_lock lock{mutex};
1671 return npad_id_type;
1672}
1673
1674NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const {
1675 std::scoped_lock lock{npad_mutex};
1676 if (get_temporary_value && is_configuring) {
1677 return tmp_npad_type;
1678 }
1679 return npad_type;
1680}
1681
1682void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
1683 auto trigger_guard =
1684 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); });
1685 std::scoped_lock lock{mutex, npad_mutex};
1686
1687 if (is_configuring) {
1688 if (tmp_npad_type == npad_type_) {
1689 trigger_guard.Cancel();
1690 return;
1691 }
1692 tmp_npad_type = npad_type_;
1693 return;
1694 }
1695
1696 if (npad_type == npad_type_) {
1697 trigger_guard.Cancel();
1698 return;
1699 }
1700 if (is_connected) {
1701 LOG_WARNING(Service_HID, "Controller {} type changed while it's connected",
1702 Service::HID::NpadIdTypeToIndex(npad_id_type));
1703 }
1704 npad_type = npad_type_;
1705}
1706
1707LedPattern EmulatedController::GetLedPattern() const {
1708 switch (npad_id_type) {
1709 case NpadIdType::Player1:
1710 return LedPattern{1, 0, 0, 0};
1711 case NpadIdType::Player2:
1712 return LedPattern{1, 1, 0, 0};
1713 case NpadIdType::Player3:
1714 return LedPattern{1, 1, 1, 0};
1715 case NpadIdType::Player4:
1716 return LedPattern{1, 1, 1, 1};
1717 case NpadIdType::Player5:
1718 return LedPattern{1, 0, 0, 1};
1719 case NpadIdType::Player6:
1720 return LedPattern{1, 0, 1, 0};
1721 case NpadIdType::Player7:
1722 return LedPattern{1, 0, 1, 1};
1723 case NpadIdType::Player8:
1724 return LedPattern{0, 1, 1, 0};
1725 default:
1726 return LedPattern{0, 0, 0, 0};
1727 }
1728}
1729
1730ButtonValues EmulatedController::GetButtonsValues() const {
1731 std::scoped_lock lock{mutex};
1732 return controller.button_values;
1733}
1734
1735SticksValues EmulatedController::GetSticksValues() const {
1736 std::scoped_lock lock{mutex};
1737 return controller.stick_values;
1738}
1739
1740TriggerValues EmulatedController::GetTriggersValues() const {
1741 std::scoped_lock lock{mutex};
1742 return controller.trigger_values;
1743}
1744
1745ControllerMotionValues EmulatedController::GetMotionValues() const {
1746 std::scoped_lock lock{mutex};
1747 return controller.motion_values;
1748}
1749
1750ColorValues EmulatedController::GetColorsValues() const {
1751 std::scoped_lock lock{mutex};
1752 return controller.color_values;
1753}
1754
1755BatteryValues EmulatedController::GetBatteryValues() const {
1756 std::scoped_lock lock{mutex};
1757 return controller.battery_values;
1758}
1759
1760CameraValues EmulatedController::GetCameraValues() const {
1761 std::scoped_lock lock{mutex};
1762 return controller.camera_values;
1763}
1764
1765RingAnalogValue EmulatedController::GetRingSensorValues() const {
1766 return controller.ring_analog_value;
1767}
1768
1769HomeButtonState EmulatedController::GetHomeButtons() const {
1770 std::scoped_lock lock{mutex};
1771 if (is_configuring) {
1772 return {};
1773 }
1774 return controller.home_button_state;
1775}
1776
1777CaptureButtonState EmulatedController::GetCaptureButtons() const {
1778 std::scoped_lock lock{mutex};
1779 if (is_configuring) {
1780 return {};
1781 }
1782 return controller.capture_button_state;
1783}
1784
1785NpadButtonState EmulatedController::GetNpadButtons() const {
1786 std::scoped_lock lock{mutex};
1787 if (is_configuring) {
1788 return {};
1789 }
1790 return {controller.npad_button_state.raw & GetTurboButtonMask()};
1791}
1792
1793DebugPadButton EmulatedController::GetDebugPadButtons() const {
1794 std::scoped_lock lock{mutex};
1795 if (is_configuring) {
1796 return {};
1797 }
1798 return controller.debug_pad_button_state;
1799}
1800
1801AnalogSticks EmulatedController::GetSticks() const {
1802 std::scoped_lock lock{mutex};
1803
1804 if (is_configuring) {
1805 return {};
1806 }
1807
1808 return controller.analog_stick_state;
1809}
1810
1811NpadGcTriggerState EmulatedController::GetTriggers() const {
1812 std::scoped_lock lock{mutex};
1813 if (is_configuring) {
1814 return {};
1815 }
1816 return controller.gc_trigger_state;
1817}
1818
1819MotionState EmulatedController::GetMotions() const {
1820 std::unique_lock lock{mutex};
1821 return controller.motion_state;
1822}
1823
1824ControllerColors EmulatedController::GetColors() const {
1825 std::scoped_lock lock{mutex};
1826 return controller.colors_state;
1827}
1828
1829BatteryLevelState EmulatedController::GetBattery() const {
1830 std::scoped_lock lock{mutex};
1831 return controller.battery_state;
1832}
1833
1834const CameraState& EmulatedController::GetCamera() const {
1835 std::scoped_lock lock{mutex};
1836 return controller.camera_state;
1837}
1838
1839RingSensorForce EmulatedController::GetRingSensorForce() const {
1840 return controller.ring_analog_state;
1841}
1842
1843const NfcState& EmulatedController::GetNfc() const {
1844 std::scoped_lock lock{mutex};
1845 return controller.nfc_state;
1846}
1847
1848NpadColor EmulatedController::GetNpadColor(u32 color) {
1849 return {
1850 .r = static_cast<u8>((color >> 16) & 0xFF),
1851 .g = static_cast<u8>((color >> 8) & 0xFF),
1852 .b = static_cast<u8>(color & 0xFF),
1853 .a = 0xff,
1854 };
1855}
1856
1857void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) {
1858 std::scoped_lock lock{callback_mutex};
1859 for (const auto& poller_pair : callback_list) {
1860 const ControllerUpdateCallback& poller = poller_pair.second;
1861 if (!is_npad_service_update && poller.is_npad_service) {
1862 continue;
1863 }
1864 if (poller.on_change) {
1865 poller.on_change(type);
1866 }
1867 }
1868}
1869
1870int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) {
1871 std::scoped_lock lock{callback_mutex};
1872 callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
1873 return last_callback_key++;
1874}
1875
1876void EmulatedController::DeleteCallback(int key) {
1877 std::scoped_lock lock{callback_mutex};
1878 const auto& iterator = callback_list.find(key);
1879 if (iterator == callback_list.end()) {
1880 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
1881 return;
1882 }
1883 callback_list.erase(iterator);
1884}
1885
1886void EmulatedController::StatusUpdate() {
1887 turbo_button_state = (turbo_button_state + 1) % (TURBO_BUTTON_DELAY * 2);
1888
1889 // Some drivers like key motion need constant refreshing
1890 for (std::size_t index = 0; index < motion_devices.size(); ++index) {
1891 const auto& raw_status = controller.motion_values[index].raw_status;
1892 auto& device = motion_devices[index];
1893 if (!raw_status.force_update) {
1894 continue;
1895 }
1896 if (!device) {
1897 continue;
1898 }
1899 device->ForceUpdate();
1900 }
1901}
1902
1903NpadButton EmulatedController::GetTurboButtonMask() const {
1904 // Apply no mask when disabled
1905 if (turbo_button_state < TURBO_BUTTON_DELAY) {
1906 return {NpadButton::All};
1907 }
1908
1909 NpadButtonState button_mask{};
1910 for (std::size_t index = 0; index < controller.button_values.size(); ++index) {
1911 if (!controller.button_values[index].turbo) {
1912 continue;
1913 }
1914
1915 switch (index) {
1916 case Settings::NativeButton::A:
1917 button_mask.a.Assign(1);
1918 break;
1919 case Settings::NativeButton::B:
1920 button_mask.b.Assign(1);
1921 break;
1922 case Settings::NativeButton::X:
1923 button_mask.x.Assign(1);
1924 break;
1925 case Settings::NativeButton::Y:
1926 button_mask.y.Assign(1);
1927 break;
1928 case Settings::NativeButton::L:
1929 button_mask.l.Assign(1);
1930 break;
1931 case Settings::NativeButton::R:
1932 button_mask.r.Assign(1);
1933 break;
1934 case Settings::NativeButton::ZL:
1935 button_mask.zl.Assign(1);
1936 break;
1937 case Settings::NativeButton::ZR:
1938 button_mask.zr.Assign(1);
1939 break;
1940 case Settings::NativeButton::DLeft:
1941 button_mask.left.Assign(1);
1942 break;
1943 case Settings::NativeButton::DUp:
1944 button_mask.up.Assign(1);
1945 break;
1946 case Settings::NativeButton::DRight:
1947 button_mask.right.Assign(1);
1948 break;
1949 case Settings::NativeButton::DDown:
1950 button_mask.down.Assign(1);
1951 break;
1952 case Settings::NativeButton::SLLeft:
1953 button_mask.left_sl.Assign(1);
1954 break;
1955 case Settings::NativeButton::SLRight:
1956 button_mask.right_sl.Assign(1);
1957 break;
1958 case Settings::NativeButton::SRLeft:
1959 button_mask.left_sr.Assign(1);
1960 break;
1961 case Settings::NativeButton::SRRight:
1962 button_mask.right_sr.Assign(1);
1963 break;
1964 default:
1965 break;
1966 }
1967 }
1968
1969 return static_cast<NpadButton>(~button_mask.raw);
1970}
1971
1972} // namespace Core::HID
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
deleted file mode 100644
index d6e20ab66..000000000
--- a/src/core/hid/emulated_controller.h
+++ /dev/null
@@ -1,619 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <functional>
8#include <memory>
9#include <mutex>
10#include <unordered_map>
11#include <vector>
12
13#include "common/common_types.h"
14#include "common/input.h"
15#include "common/param_package.h"
16#include "common/settings.h"
17#include "common/vector_math.h"
18#include "core/hid/hid_types.h"
19#include "core/hid/irs_types.h"
20#include "core/hid/motion_input.h"
21
22namespace Core::HID {
23const std::size_t max_emulated_controllers = 2;
24const std::size_t output_devices_size = 4;
25struct ControllerMotionInfo {
26 Common::Input::MotionStatus raw_status{};
27 MotionInput emulated{};
28};
29
30using ButtonDevices =
31 std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeButton::NumButtons>;
32using StickDevices =
33 std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeAnalog::NumAnalogs>;
34using ControllerMotionDevices =
35 std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeMotion::NumMotions>;
36using TriggerDevices =
37 std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeTrigger::NumTriggers>;
38using ColorDevices =
39 std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
40using BatteryDevices =
41 std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
42using CameraDevices =
43 std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
44using RingAnalogDevices =
45 std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
46using NfcDevices =
47 std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
48using OutputDevices = std::array<std::unique_ptr<Common::Input::OutputDevice>, output_devices_size>;
49
50using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>;
51using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
52using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>;
53using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>;
54using ColorParams = std::array<Common::ParamPackage, max_emulated_controllers>;
55using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>;
56using CameraParams = std::array<Common::ParamPackage, max_emulated_controllers>;
57using RingAnalogParams = std::array<Common::ParamPackage, max_emulated_controllers>;
58using NfcParams = std::array<Common::ParamPackage, max_emulated_controllers>;
59using OutputParams = std::array<Common::ParamPackage, output_devices_size>;
60
61using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>;
62using SticksValues = std::array<Common::Input::StickStatus, Settings::NativeAnalog::NumAnalogs>;
63using TriggerValues =
64 std::array<Common::Input::TriggerStatus, Settings::NativeTrigger::NumTriggers>;
65using ControllerMotionValues = std::array<ControllerMotionInfo, Settings::NativeMotion::NumMotions>;
66using ColorValues = std::array<Common::Input::BodyColorStatus, max_emulated_controllers>;
67using BatteryValues = std::array<Common::Input::BatteryStatus, max_emulated_controllers>;
68using CameraValues = Common::Input::CameraStatus;
69using RingAnalogValue = Common::Input::AnalogStatus;
70using NfcValues = Common::Input::NfcStatus;
71using VibrationValues = std::array<Common::Input::VibrationStatus, max_emulated_controllers>;
72
73struct AnalogSticks {
74 AnalogStickState left{};
75 AnalogStickState right{};
76};
77
78struct ControllerColors {
79 NpadControllerColor fullkey{};
80 NpadControllerColor left{};
81 NpadControllerColor right{};
82};
83
84struct BatteryLevelState {
85 NpadPowerInfo dual{};
86 NpadPowerInfo left{};
87 NpadPowerInfo right{};
88};
89
90struct CameraState {
91 Core::IrSensor::ImageTransferProcessorFormat format{};
92 std::vector<u8> data{};
93 std::size_t sample{};
94};
95
96struct RingSensorForce {
97 f32 force;
98};
99
100using NfcState = Common::Input::NfcStatus;
101
102struct ControllerMotion {
103 Common::Vec3f accel{};
104 Common::Vec3f gyro{};
105 Common::Vec3f rotation{};
106 Common::Vec3f euler{};
107 std::array<Common::Vec3f, 3> orientation{};
108 bool is_at_rest{};
109};
110
111enum EmulatedDeviceIndex : u8 {
112 LeftIndex,
113 RightIndex,
114 DualIndex,
115 AllDevices,
116};
117
118using MotionState = std::array<ControllerMotion, 2>;
119
120struct ControllerStatus {
121 // Data from input_common
122 ButtonValues button_values{};
123 SticksValues stick_values{};
124 ControllerMotionValues motion_values{};
125 TriggerValues trigger_values{};
126 ColorValues color_values{};
127 BatteryValues battery_values{};
128 VibrationValues vibration_values{};
129 CameraValues camera_values{};
130 RingAnalogValue ring_analog_value{};
131 NfcValues nfc_values{};
132
133 // Data for HID services
134 HomeButtonState home_button_state{};
135 CaptureButtonState capture_button_state{};
136 NpadButtonState npad_button_state{};
137 DebugPadButton debug_pad_button_state{};
138 AnalogSticks analog_stick_state{};
139 MotionState motion_state{};
140 NpadGcTriggerState gc_trigger_state{};
141 ControllerColors colors_state{};
142 BatteryLevelState battery_state{};
143 CameraState camera_state{};
144 RingSensorForce ring_analog_state{};
145 NfcState nfc_state{};
146 Common::Input::PollingMode left_polling_mode{};
147 Common::Input::PollingMode right_polling_mode{};
148};
149
150enum class ControllerTriggerType {
151 Button,
152 Stick,
153 Trigger,
154 Motion,
155 Color,
156 Battery,
157 Vibration,
158 IrSensor,
159 RingController,
160 Nfc,
161 Connected,
162 Disconnected,
163 Type,
164 All,
165};
166
167struct ControllerUpdateCallback {
168 std::function<void(ControllerTriggerType)> on_change;
169 bool is_npad_service;
170};
171
172class EmulatedController {
173public:
174 /**
175 * Contains all input data (buttons, joysticks, vibration, and motion) within this controller.
176 * @param npad_id_type npad id type for this specific controller
177 */
178 explicit EmulatedController(NpadIdType npad_id_type_);
179 ~EmulatedController();
180
181 YUZU_NON_COPYABLE(EmulatedController);
182 YUZU_NON_MOVEABLE(EmulatedController);
183
184 /// Converts the controller type from settings to npad type
185 static NpadStyleIndex MapSettingsTypeToNPad(Settings::ControllerType type);
186
187 /// Converts npad type to the equivalent of controller type from settings
188 static Settings::ControllerType MapNPadToSettingsType(NpadStyleIndex type);
189
190 /// Gets the NpadIdType for this controller
191 NpadIdType GetNpadIdType() const;
192
193 /// Sets the NpadStyleIndex for this controller
194 void SetNpadStyleIndex(NpadStyleIndex npad_type_);
195
196 /**
197 * Gets the NpadStyleIndex for this controller
198 * @param get_temporary_value If true tmp_npad_type will be returned
199 * @return NpadStyleIndex set on the controller
200 */
201 NpadStyleIndex GetNpadStyleIndex(bool get_temporary_value = false) const;
202
203 /**
204 * Sets the supported controller types. Disconnects the controller if current type is not
205 * supported
206 * @param supported_styles bitflag with supported types
207 */
208 void SetSupportedNpadStyleTag(NpadStyleTag supported_styles);
209
210 /**
211 * Sets the connected status to true
212 * @param use_temporary_value If true tmp_npad_type will be used
213 */
214 void Connect(bool use_temporary_value = false);
215
216 /// Sets the connected status to false
217 void Disconnect();
218
219 /**
220 * Is the emulated connected
221 * @param get_temporary_value If true tmp_is_connected will be returned
222 * @return true if the controller has the connected status
223 */
224 bool IsConnected(bool get_temporary_value = false) const;
225
226 /// Removes all callbacks created from input devices
227 void UnloadInput();
228
229 /**
230 * Sets the emulated controller into configuring mode
231 * This prevents the modification of the HID state of the emulated controller by input commands
232 */
233 void EnableConfiguration();
234
235 /// Returns the emulated controller into normal mode, allowing the modification of the HID state
236 void DisableConfiguration();
237
238 /// Enables Home and Screenshot buttons
239 void EnableSystemButtons();
240
241 /// Disables Home and Screenshot buttons
242 void DisableSystemButtons();
243
244 /// Sets Home and Screenshot buttons to false
245 void ResetSystemButtons();
246
247 /// Returns true if the emulated controller is in configuring mode
248 bool IsConfiguring() const;
249
250 /// Reload all input devices
251 void ReloadInput();
252
253 /// Overrides current mapped devices with the stored configuration and reloads all input devices
254 void ReloadFromSettings();
255
256 /// Updates current colors with the ones stored in the configuration
257 void ReloadColorsFromSettings();
258
259 /// Saves the current mapped configuration
260 void SaveCurrentConfig();
261
262 /// Reverts any mapped changes made that weren't saved
263 void RestoreConfig();
264
265 /// Returns a vector of mapped devices from the mapped button and stick parameters
266 std::vector<Common::ParamPackage> GetMappedDevices() const;
267
268 // Returns the current mapped button device
269 Common::ParamPackage GetButtonParam(std::size_t index) const;
270
271 // Returns the current mapped stick device
272 Common::ParamPackage GetStickParam(std::size_t index) const;
273
274 // Returns the current mapped motion device
275 Common::ParamPackage GetMotionParam(std::size_t index) const;
276
277 /**
278 * Updates the current mapped button device
279 * @param param ParamPackage with controller data to be mapped
280 */
281 void SetButtonParam(std::size_t index, Common::ParamPackage param);
282
283 /**
284 * Updates the current mapped stick device
285 * @param param ParamPackage with controller data to be mapped
286 */
287 void SetStickParam(std::size_t index, Common::ParamPackage param);
288
289 /**
290 * Updates the current mapped motion device
291 * @param param ParamPackage with controller data to be mapped
292 */
293 void SetMotionParam(std::size_t index, Common::ParamPackage param);
294
295 /// Auto calibrates the current motion devices
296 void StartMotionCalibration();
297
298 /// Returns the latest button status from the controller with parameters
299 ButtonValues GetButtonsValues() const;
300
301 /// Returns the latest analog stick status from the controller with parameters
302 SticksValues GetSticksValues() const;
303
304 /// Returns the latest trigger status from the controller with parameters
305 TriggerValues GetTriggersValues() const;
306
307 /// Returns the latest motion status from the controller with parameters
308 ControllerMotionValues GetMotionValues() const;
309
310 /// Returns the latest color status from the controller with parameters
311 ColorValues GetColorsValues() const;
312
313 /// Returns the latest battery status from the controller with parameters
314 BatteryValues GetBatteryValues() const;
315
316 /// Returns the latest camera status from the controller with parameters
317 CameraValues GetCameraValues() const;
318
319 /// Returns the latest status of analog input from the ring sensor with parameters
320 RingAnalogValue GetRingSensorValues() const;
321
322 /// Returns the latest status of button input for the hid::HomeButton service
323 HomeButtonState GetHomeButtons() const;
324
325 /// Returns the latest status of button input for the hid::CaptureButton service
326 CaptureButtonState GetCaptureButtons() const;
327
328 /// Returns the latest status of button input for the hid::Npad service
329 NpadButtonState GetNpadButtons() const;
330
331 /// Returns the latest status of button input for the debug pad service
332 DebugPadButton GetDebugPadButtons() const;
333
334 /// Returns the latest status of stick input from the mouse
335 AnalogSticks GetSticks() const;
336
337 /// Returns the latest status of trigger input from the mouse
338 NpadGcTriggerState GetTriggers() const;
339
340 /// Returns the latest status of motion input from the mouse
341 MotionState GetMotions() const;
342
343 /// Returns the latest color value from the controller
344 ControllerColors GetColors() const;
345
346 /// Returns the latest battery status from the controller
347 BatteryLevelState GetBattery() const;
348
349 /// Returns the latest camera status from the controller
350 const CameraState& GetCamera() const;
351
352 /// Returns the latest ringcon force sensor value
353 RingSensorForce GetRingSensorForce() const;
354
355 /// Returns the latest ntag status from the controller
356 const NfcState& GetNfc() const;
357
358 /**
359 * Sends a specific vibration to the output device
360 * @return true if vibration had no errors
361 */
362 bool SetVibration(std::size_t device_index, VibrationValue vibration);
363
364 /**
365 * Sends a small vibration to the output device
366 * @return true if SetVibration was successful
367 */
368 bool IsVibrationEnabled(std::size_t device_index);
369
370 /**
371 * Sets the desired data to be polled from a controller
372 * @param device_index index of the controller to set the polling mode
373 * @param polling_mode type of input desired buttons, gyro, nfc, ir, etc.
374 * @return driver result from this command
375 */
376 Common::Input::DriverResult SetPollingMode(EmulatedDeviceIndex device_index,
377 Common::Input::PollingMode polling_mode);
378 /**
379 * Get the current polling mode from a controller
380 * @param device_index index of the controller to set the polling mode
381 * @return current polling mode
382 */
383 Common::Input::PollingMode GetPollingMode(EmulatedDeviceIndex device_index) const;
384
385 /**
386 * Sets the desired camera format to be polled from a controller
387 * @param camera_format size of each frame
388 * @return true if SetCameraFormat was successful
389 */
390 bool SetCameraFormat(Core::IrSensor::ImageTransferProcessorFormat camera_format);
391
392 // Returns the current mapped ring device
393 Common::ParamPackage GetRingParam() const;
394
395 /**
396 * Updates the current mapped ring device
397 * @param param ParamPackage with ring sensor data to be mapped
398 */
399 void SetRingParam(Common::ParamPackage param);
400
401 /// Returns true if the device has nfc support
402 bool HasNfc() const;
403
404 /// Sets the joycon in nfc mode and increments the handle count
405 bool AddNfcHandle();
406
407 /// Decrements the handle count if zero sets the joycon in active mode
408 bool RemoveNfcHandle();
409
410 /// Start searching for nfc tags
411 bool StartNfcPolling();
412
413 /// Stop searching for nfc tags
414 bool StopNfcPolling();
415
416 /// Returns true if the nfc tag was readable
417 bool ReadAmiiboData(std::vector<u8>& data);
418
419 /// Returns true if the nfc tag was written
420 bool WriteNfc(const std::vector<u8>& data);
421
422 /// Returns true if the nfc tag was readable
423 bool ReadMifareData(const Common::Input::MifareRequest& request,
424 Common::Input::MifareRequest& out_data);
425
426 /// Returns true if the nfc tag was written
427 bool WriteMifareData(const Common::Input::MifareRequest& request);
428
429 /// Returns the led pattern corresponding to this emulated controller
430 LedPattern GetLedPattern() const;
431
432 /// Asks the output device to change the player led pattern
433 void SetLedPattern();
434
435 /// Changes sensitivity of the motion sensor
436 void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode mode);
437
438 /**
439 * Adds a callback to the list of events
440 * @param update_callback A ConsoleUpdateCallback that will be triggered
441 * @return an unique key corresponding to the callback index in the list
442 */
443 int SetCallback(ControllerUpdateCallback update_callback);
444
445 /**
446 * Removes a callback from the list stopping any future events to this object
447 * @param key Key corresponding to the callback index in the list
448 */
449 void DeleteCallback(int key);
450
451 /// Swaps the state of the turbo buttons and updates motion input
452 void StatusUpdate();
453
454private:
455 /// creates input devices from params
456 void LoadDevices();
457
458 /// Set the params for TAS devices
459 void LoadTASParams();
460
461 /// Set the params for virtual pad devices
462 void LoadVirtualGamepadParams();
463
464 /**
465 * @param use_temporary_value If true tmp_npad_type will be used
466 * @return true if the controller style is fullkey
467 */
468 bool IsControllerFullkey(bool use_temporary_value = false) const;
469
470 /**
471 * Checks the current controller type against the supported_style_tag
472 * @param use_temporary_value If true tmp_npad_type will be used
473 * @return true if the controller is supported
474 */
475 bool IsControllerSupported(bool use_temporary_value = false) const;
476
477 /**
478 * Updates the button status of the controller
479 * @param callback A CallbackStatus containing the button status
480 * @param index Button ID of the to be updated
481 */
482 void SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
483 Common::UUID uuid);
484
485 /**
486 * Updates the analog stick status of the controller
487 * @param callback A CallbackStatus containing the analog stick status
488 * @param index stick ID of the to be updated
489 */
490 void SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
491 Common::UUID uuid);
492
493 /**
494 * Updates the trigger status of the controller
495 * @param callback A CallbackStatus containing the trigger status
496 * @param index trigger ID of the to be updated
497 */
498 void SetTrigger(const Common::Input::CallbackStatus& callback, std::size_t index,
499 Common::UUID uuid);
500
501 /**
502 * Updates the motion status of the controller
503 * @param callback A CallbackStatus containing gyro and accelerometer data
504 * @param index motion ID of the to be updated
505 */
506 void SetMotion(const Common::Input::CallbackStatus& callback, std::size_t index);
507
508 /**
509 * Updates the color status of the controller
510 * @param callback A CallbackStatus containing the color status
511 * @param index color ID of the to be updated
512 */
513 void SetColors(const Common::Input::CallbackStatus& callback, std::size_t index);
514
515 /**
516 * Updates the battery status of the controller
517 * @param callback A CallbackStatus containing the battery status
518 * @param index battery ID of the to be updated
519 */
520 void SetBattery(const Common::Input::CallbackStatus& callback, std::size_t index);
521
522 /**
523 * Updates the camera status of the controller
524 * @param callback A CallbackStatus containing the camera status
525 */
526 void SetCamera(const Common::Input::CallbackStatus& callback);
527
528 /**
529 * Updates the ring analog sensor status of the ring controller
530 * @param callback A CallbackStatus containing the force status
531 */
532 void SetRingAnalog(const Common::Input::CallbackStatus& callback);
533
534 /**
535 * Updates the nfc status of the controller
536 * @param callback A CallbackStatus containing the nfc status
537 */
538 void SetNfc(const Common::Input::CallbackStatus& callback);
539
540 /**
541 * Converts a color format from bgra to rgba
542 * @param color in bgra format
543 * @return NpadColor in rgba format
544 */
545 NpadColor GetNpadColor(u32 color);
546
547 /**
548 * Triggers a callback that something has changed on the controller status
549 * @param type Input type of the event to trigger
550 * @param is_service_update indicates if this event should only be sent to HID services
551 */
552 void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
553
554 NpadButton GetTurboButtonMask() const;
555
556 const NpadIdType npad_id_type;
557 NpadStyleIndex npad_type{NpadStyleIndex::None};
558 NpadStyleIndex original_npad_type{NpadStyleIndex::None};
559 NpadStyleTag supported_style_tag{NpadStyleSet::All};
560 bool is_connected{false};
561 bool is_configuring{false};
562 bool is_initalized{false};
563 bool system_buttons_enabled{true};
564 f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
565 u32 turbo_button_state{0};
566 std::size_t nfc_handles{0};
567
568 // Temporary values to avoid doing changes while the controller is in configuring mode
569 NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};
570 bool tmp_is_connected{false};
571
572 ButtonParams button_params;
573 StickParams stick_params;
574 ControllerMotionParams motion_params;
575 TriggerParams trigger_params;
576 BatteryParams battery_params;
577 ColorParams color_params;
578 CameraParams camera_params;
579 RingAnalogParams ring_params;
580 NfcParams nfc_params;
581 OutputParams output_params;
582
583 ButtonDevices button_devices;
584 StickDevices stick_devices;
585 ControllerMotionDevices motion_devices;
586 TriggerDevices trigger_devices;
587 BatteryDevices battery_devices;
588 ColorDevices color_devices;
589 CameraDevices camera_devices;
590 RingAnalogDevices ring_analog_devices;
591 NfcDevices nfc_devices;
592 OutputDevices output_devices;
593
594 // TAS related variables
595 ButtonParams tas_button_params;
596 StickParams tas_stick_params;
597 ButtonDevices tas_button_devices;
598 StickDevices tas_stick_devices;
599
600 // Virtual gamepad related variables
601 ButtonParams virtual_button_params;
602 StickParams virtual_stick_params;
603 ControllerMotionParams virtual_motion_params;
604 ButtonDevices virtual_button_devices;
605 StickDevices virtual_stick_devices;
606 ControllerMotionDevices virtual_motion_devices;
607
608 mutable std::mutex mutex;
609 mutable std::mutex callback_mutex;
610 mutable std::mutex npad_mutex;
611 mutable std::mutex connect_mutex;
612 std::unordered_map<int, ControllerUpdateCallback> callback_list;
613 int last_callback_key = 0;
614
615 // Stores the current status of all controller input
616 ControllerStatus controller;
617};
618
619} // namespace Core::HID
diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp
deleted file mode 100644
index 8e165dded..000000000
--- a/src/core/hid/emulated_devices.cpp
+++ /dev/null
@@ -1,483 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <fmt/format.h>
6
7#include "core/hid/emulated_devices.h"
8#include "core/hid/input_converter.h"
9
10namespace Core::HID {
11
12EmulatedDevices::EmulatedDevices() = default;
13
14EmulatedDevices::~EmulatedDevices() = default;
15
16void EmulatedDevices::ReloadFromSettings() {
17 ReloadInput();
18}
19
20void EmulatedDevices::ReloadInput() {
21 // If you load any device here add the equivalent to the UnloadInput() function
22
23 // Native Mouse is mapped on port 1, pad 0
24 const Common::ParamPackage mouse_params{"engine:mouse,port:1,pad:0"};
25
26 // Keyboard keys is mapped on port 1, pad 0 for normal keys, pad 1 for moddifier keys
27 const Common::ParamPackage keyboard_params{"engine:keyboard,port:1"};
28
29 std::size_t key_index = 0;
30 for (auto& mouse_device : mouse_button_devices) {
31 Common::ParamPackage mouse_button_params = mouse_params;
32 mouse_button_params.Set("button", static_cast<int>(key_index));
33 mouse_device = Common::Input::CreateInputDevice(mouse_button_params);
34 key_index++;
35 }
36
37 Common::ParamPackage mouse_position_params = mouse_params;
38 mouse_position_params.Set("axis_x", 0);
39 mouse_position_params.Set("axis_y", 1);
40 mouse_position_params.Set("deadzone", 0.0f);
41 mouse_position_params.Set("range", 1.0f);
42 mouse_position_params.Set("threshold", 0.0f);
43 mouse_stick_device = Common::Input::CreateInputDevice(mouse_position_params);
44
45 // First two axis are reserved for mouse position
46 key_index = 2;
47 for (auto& mouse_device : mouse_wheel_devices) {
48 Common::ParamPackage mouse_wheel_params = mouse_params;
49 mouse_wheel_params.Set("axis", static_cast<int>(key_index));
50 mouse_device = Common::Input::CreateInputDevice(mouse_wheel_params);
51 key_index++;
52 }
53
54 key_index = 0;
55 for (auto& keyboard_device : keyboard_devices) {
56 Common::ParamPackage keyboard_key_params = keyboard_params;
57 keyboard_key_params.Set("button", static_cast<int>(key_index));
58 keyboard_key_params.Set("pad", 0);
59 keyboard_device = Common::Input::CreateInputDevice(keyboard_key_params);
60 key_index++;
61 }
62
63 key_index = 0;
64 for (auto& keyboard_device : keyboard_modifier_devices) {
65 Common::ParamPackage keyboard_moddifier_params = keyboard_params;
66 keyboard_moddifier_params.Set("button", static_cast<int>(key_index));
67 keyboard_moddifier_params.Set("pad", 1);
68 keyboard_device = Common::Input::CreateInputDevice(keyboard_moddifier_params);
69 key_index++;
70 }
71
72 for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) {
73 if (!mouse_button_devices[index]) {
74 continue;
75 }
76 mouse_button_devices[index]->SetCallback({
77 .on_change =
78 [this, index](const Common::Input::CallbackStatus& callback) {
79 SetMouseButton(callback, index);
80 },
81 });
82 }
83
84 for (std::size_t index = 0; index < mouse_wheel_devices.size(); ++index) {
85 if (!mouse_wheel_devices[index]) {
86 continue;
87 }
88 mouse_wheel_devices[index]->SetCallback({
89 .on_change =
90 [this, index](const Common::Input::CallbackStatus& callback) {
91 SetMouseWheel(callback, index);
92 },
93 });
94 }
95
96 if (mouse_stick_device) {
97 mouse_stick_device->SetCallback({
98 .on_change =
99 [this](const Common::Input::CallbackStatus& callback) {
100 SetMousePosition(callback);
101 },
102 });
103 }
104
105 for (std::size_t index = 0; index < keyboard_devices.size(); ++index) {
106 if (!keyboard_devices[index]) {
107 continue;
108 }
109 keyboard_devices[index]->SetCallback({
110 .on_change =
111 [this, index](const Common::Input::CallbackStatus& callback) {
112 SetKeyboardButton(callback, index);
113 },
114 });
115 }
116
117 for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) {
118 if (!keyboard_modifier_devices[index]) {
119 continue;
120 }
121 keyboard_modifier_devices[index]->SetCallback({
122 .on_change =
123 [this, index](const Common::Input::CallbackStatus& callback) {
124 SetKeyboardModifier(callback, index);
125 },
126 });
127 }
128}
129
130void EmulatedDevices::UnloadInput() {
131 for (auto& button : mouse_button_devices) {
132 button.reset();
133 }
134 for (auto& analog : mouse_wheel_devices) {
135 analog.reset();
136 }
137 mouse_stick_device.reset();
138 for (auto& button : keyboard_devices) {
139 button.reset();
140 }
141 for (auto& button : keyboard_modifier_devices) {
142 button.reset();
143 }
144}
145
146void EmulatedDevices::EnableConfiguration() {
147 is_configuring = true;
148 SaveCurrentConfig();
149}
150
151void EmulatedDevices::DisableConfiguration() {
152 is_configuring = false;
153}
154
155bool EmulatedDevices::IsConfiguring() const {
156 return is_configuring;
157}
158
159void EmulatedDevices::SaveCurrentConfig() {
160 if (!is_configuring) {
161 return;
162 }
163}
164
165void EmulatedDevices::RestoreConfig() {
166 if (!is_configuring) {
167 return;
168 }
169 ReloadFromSettings();
170}
171
172void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& callback,
173 std::size_t index) {
174 if (index >= device_status.keyboard_values.size()) {
175 return;
176 }
177 std::unique_lock lock{mutex};
178 bool value_changed = false;
179 const auto new_status = TransformToButton(callback);
180 auto& current_status = device_status.keyboard_values[index];
181 current_status.toggle = new_status.toggle;
182
183 // Update button status with current status
184 if (!current_status.toggle) {
185 current_status.locked = false;
186 if (current_status.value != new_status.value) {
187 current_status.value = new_status.value;
188 value_changed = true;
189 }
190 } else {
191 // Toggle button and lock status
192 if (new_status.value && !current_status.locked) {
193 current_status.locked = true;
194 current_status.value = !current_status.value;
195 value_changed = true;
196 }
197
198 // Unlock button, ready for next press
199 if (!new_status.value && current_status.locked) {
200 current_status.locked = false;
201 }
202 }
203
204 if (!value_changed) {
205 return;
206 }
207
208 if (is_configuring) {
209 lock.unlock();
210 TriggerOnChange(DeviceTriggerType::Keyboard);
211 return;
212 }
213
214 // Index should be converted from NativeKeyboard to KeyboardKeyIndex
215 UpdateKey(index, current_status.value);
216
217 lock.unlock();
218 TriggerOnChange(DeviceTriggerType::Keyboard);
219}
220
221void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) {
222 constexpr std::size_t KEYS_PER_BYTE = 8;
223 auto& entry = device_status.keyboard_state.key[key_index / KEYS_PER_BYTE];
224 const u8 mask = static_cast<u8>(1 << (key_index % KEYS_PER_BYTE));
225 if (status) {
226 entry = entry | mask;
227 } else {
228 entry = static_cast<u8>(entry & ~mask);
229 }
230}
231
232void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& callback,
233 std::size_t index) {
234 if (index >= device_status.keyboard_moddifier_values.size()) {
235 return;
236 }
237 std::unique_lock lock{mutex};
238 bool value_changed = false;
239 const auto new_status = TransformToButton(callback);
240 auto& current_status = device_status.keyboard_moddifier_values[index];
241 current_status.toggle = new_status.toggle;
242
243 // Update button status with current
244 if (!current_status.toggle) {
245 current_status.locked = false;
246 if (current_status.value != new_status.value) {
247 current_status.value = new_status.value;
248 value_changed = true;
249 }
250 } else {
251 // Toggle button and lock status
252 if (new_status.value && !current_status.locked) {
253 current_status.locked = true;
254 current_status.value = !current_status.value;
255 value_changed = true;
256 }
257
258 // Unlock button ready for next press
259 if (!new_status.value && current_status.locked) {
260 current_status.locked = false;
261 }
262 }
263
264 if (!value_changed) {
265 return;
266 }
267
268 if (is_configuring) {
269 lock.unlock();
270 TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
271 return;
272 }
273
274 switch (index) {
275 case Settings::NativeKeyboard::LeftControl:
276 case Settings::NativeKeyboard::RightControl:
277 device_status.keyboard_moddifier_state.control.Assign(current_status.value);
278 break;
279 case Settings::NativeKeyboard::LeftShift:
280 case Settings::NativeKeyboard::RightShift:
281 device_status.keyboard_moddifier_state.shift.Assign(current_status.value);
282 break;
283 case Settings::NativeKeyboard::LeftAlt:
284 device_status.keyboard_moddifier_state.left_alt.Assign(current_status.value);
285 break;
286 case Settings::NativeKeyboard::RightAlt:
287 device_status.keyboard_moddifier_state.right_alt.Assign(current_status.value);
288 break;
289 case Settings::NativeKeyboard::CapsLock:
290 device_status.keyboard_moddifier_state.caps_lock.Assign(current_status.value);
291 break;
292 case Settings::NativeKeyboard::ScrollLock:
293 device_status.keyboard_moddifier_state.scroll_lock.Assign(current_status.value);
294 break;
295 case Settings::NativeKeyboard::NumLock:
296 device_status.keyboard_moddifier_state.num_lock.Assign(current_status.value);
297 break;
298 }
299
300 lock.unlock();
301 TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
302}
303
304void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callback,
305 std::size_t index) {
306 if (index >= device_status.mouse_button_values.size()) {
307 return;
308 }
309 std::unique_lock lock{mutex};
310 bool value_changed = false;
311 const auto new_status = TransformToButton(callback);
312 auto& current_status = device_status.mouse_button_values[index];
313 current_status.toggle = new_status.toggle;
314
315 // Update button status with current
316 if (!current_status.toggle) {
317 current_status.locked = false;
318 if (current_status.value != new_status.value) {
319 current_status.value = new_status.value;
320 value_changed = true;
321 }
322 } else {
323 // Toggle button and lock status
324 if (new_status.value && !current_status.locked) {
325 current_status.locked = true;
326 current_status.value = !current_status.value;
327 value_changed = true;
328 }
329
330 // Unlock button ready for next press
331 if (!new_status.value && current_status.locked) {
332 current_status.locked = false;
333 }
334 }
335
336 if (!value_changed) {
337 return;
338 }
339
340 if (is_configuring) {
341 lock.unlock();
342 TriggerOnChange(DeviceTriggerType::Mouse);
343 return;
344 }
345
346 switch (index) {
347 case Settings::NativeMouseButton::Left:
348 device_status.mouse_button_state.left.Assign(current_status.value);
349 break;
350 case Settings::NativeMouseButton::Right:
351 device_status.mouse_button_state.right.Assign(current_status.value);
352 break;
353 case Settings::NativeMouseButton::Middle:
354 device_status.mouse_button_state.middle.Assign(current_status.value);
355 break;
356 case Settings::NativeMouseButton::Forward:
357 device_status.mouse_button_state.forward.Assign(current_status.value);
358 break;
359 case Settings::NativeMouseButton::Back:
360 device_status.mouse_button_state.back.Assign(current_status.value);
361 break;
362 }
363
364 lock.unlock();
365 TriggerOnChange(DeviceTriggerType::Mouse);
366}
367
368void EmulatedDevices::SetMouseWheel(const Common::Input::CallbackStatus& callback,
369 std::size_t index) {
370 if (index >= device_status.mouse_wheel_values.size()) {
371 return;
372 }
373 std::unique_lock lock{mutex};
374 const auto analog_value = TransformToAnalog(callback);
375
376 device_status.mouse_wheel_values[index] = analog_value;
377
378 if (is_configuring) {
379 device_status.mouse_wheel_state = {};
380 lock.unlock();
381 TriggerOnChange(DeviceTriggerType::Mouse);
382 return;
383 }
384
385 switch (index) {
386 case Settings::NativeMouseWheel::X:
387 device_status.mouse_wheel_state.x = static_cast<s32>(analog_value.value);
388 break;
389 case Settings::NativeMouseWheel::Y:
390 device_status.mouse_wheel_state.y = static_cast<s32>(analog_value.value);
391 break;
392 }
393
394 lock.unlock();
395 TriggerOnChange(DeviceTriggerType::Mouse);
396}
397
398void EmulatedDevices::SetMousePosition(const Common::Input::CallbackStatus& callback) {
399 std::unique_lock lock{mutex};
400 const auto touch_value = TransformToTouch(callback);
401
402 device_status.mouse_stick_value = touch_value;
403
404 if (is_configuring) {
405 device_status.mouse_position_state = {};
406 lock.unlock();
407 TriggerOnChange(DeviceTriggerType::Mouse);
408 return;
409 }
410
411 device_status.mouse_position_state.x = touch_value.x.value;
412 device_status.mouse_position_state.y = touch_value.y.value;
413
414 lock.unlock();
415 TriggerOnChange(DeviceTriggerType::Mouse);
416}
417
418KeyboardValues EmulatedDevices::GetKeyboardValues() const {
419 std::scoped_lock lock{mutex};
420 return device_status.keyboard_values;
421}
422
423KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const {
424 std::scoped_lock lock{mutex};
425 return device_status.keyboard_moddifier_values;
426}
427
428MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const {
429 std::scoped_lock lock{mutex};
430 return device_status.mouse_button_values;
431}
432
433KeyboardKey EmulatedDevices::GetKeyboard() const {
434 std::scoped_lock lock{mutex};
435 return device_status.keyboard_state;
436}
437
438KeyboardModifier EmulatedDevices::GetKeyboardModifier() const {
439 std::scoped_lock lock{mutex};
440 return device_status.keyboard_moddifier_state;
441}
442
443MouseButton EmulatedDevices::GetMouseButtons() const {
444 std::scoped_lock lock{mutex};
445 return device_status.mouse_button_state;
446}
447
448MousePosition EmulatedDevices::GetMousePosition() const {
449 std::scoped_lock lock{mutex};
450 return device_status.mouse_position_state;
451}
452
453AnalogStickState EmulatedDevices::GetMouseWheel() const {
454 std::scoped_lock lock{mutex};
455 return device_status.mouse_wheel_state;
456}
457
458void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
459 std::scoped_lock lock{callback_mutex};
460 for (const auto& poller_pair : callback_list) {
461 const InterfaceUpdateCallback& poller = poller_pair.second;
462 if (poller.on_change) {
463 poller.on_change(type);
464 }
465 }
466}
467
468int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) {
469 std::scoped_lock lock{callback_mutex};
470 callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
471 return last_callback_key++;
472}
473
474void EmulatedDevices::DeleteCallback(int key) {
475 std::scoped_lock lock{callback_mutex};
476 const auto& iterator = callback_list.find(key);
477 if (iterator == callback_list.end()) {
478 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
479 return;
480 }
481 callback_list.erase(iterator);
482}
483} // namespace Core::HID
diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h
deleted file mode 100644
index 5eab693e4..000000000
--- a/src/core/hid/emulated_devices.h
+++ /dev/null
@@ -1,212 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <functional>
8#include <memory>
9#include <mutex>
10#include <unordered_map>
11#include <vector>
12
13#include "common/common_types.h"
14#include "common/input.h"
15#include "common/param_package.h"
16#include "common/settings.h"
17#include "core/hid/hid_types.h"
18
19namespace Core::HID {
20using KeyboardDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
21 Settings::NativeKeyboard::NumKeyboardKeys>;
22using KeyboardModifierDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
23 Settings::NativeKeyboard::NumKeyboardMods>;
24using MouseButtonDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
25 Settings::NativeMouseButton::NumMouseButtons>;
26using MouseWheelDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
27 Settings::NativeMouseWheel::NumMouseWheels>;
28using MouseStickDevice = std::unique_ptr<Common::Input::InputDevice>;
29
30using MouseButtonParams =
31 std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons>;
32
33using KeyboardValues =
34 std::array<Common::Input::ButtonStatus, Settings::NativeKeyboard::NumKeyboardKeys>;
35using KeyboardModifierValues =
36 std::array<Common::Input::ButtonStatus, Settings::NativeKeyboard::NumKeyboardMods>;
37using MouseButtonValues =
38 std::array<Common::Input::ButtonStatus, Settings::NativeMouseButton::NumMouseButtons>;
39using MouseWheelValues =
40 std::array<Common::Input::AnalogStatus, Settings::NativeMouseWheel::NumMouseWheels>;
41using MouseStickValue = Common::Input::TouchStatus;
42
43struct MousePosition {
44 f32 x;
45 f32 y;
46};
47
48struct DeviceStatus {
49 // Data from input_common
50 KeyboardValues keyboard_values{};
51 KeyboardModifierValues keyboard_moddifier_values{};
52 MouseButtonValues mouse_button_values{};
53 MouseWheelValues mouse_wheel_values{};
54 MouseStickValue mouse_stick_value{};
55
56 // Data for HID services
57 KeyboardKey keyboard_state{};
58 KeyboardModifier keyboard_moddifier_state{};
59 MouseButton mouse_button_state{};
60 MousePosition mouse_position_state{};
61 AnalogStickState mouse_wheel_state{};
62};
63
64enum class DeviceTriggerType {
65 Keyboard,
66 KeyboardModdifier,
67 Mouse,
68 RingController,
69};
70
71struct InterfaceUpdateCallback {
72 std::function<void(DeviceTriggerType)> on_change;
73};
74
75class EmulatedDevices {
76public:
77 /**
78 * Contains all input data related to external devices that aren't necessarily a controller
79 * This includes devices such as the keyboard or mouse
80 */
81 explicit EmulatedDevices();
82 ~EmulatedDevices();
83
84 YUZU_NON_COPYABLE(EmulatedDevices);
85 YUZU_NON_MOVEABLE(EmulatedDevices);
86
87 /// Removes all callbacks created from input devices
88 void UnloadInput();
89
90 /**
91 * Sets the emulated devices into configuring mode
92 * This prevents the modification of the HID state of the emulated devices by input commands
93 */
94 void EnableConfiguration();
95
96 /// Returns the emulated devices into normal mode, allowing the modification of the HID state
97 void DisableConfiguration();
98
99 /// Returns true if the emulated device is in configuring mode
100 bool IsConfiguring() const;
101
102 /// Reload all input devices
103 void ReloadInput();
104
105 /// Overrides current mapped devices with the stored configuration and reloads all input devices
106 void ReloadFromSettings();
107
108 /// Saves the current mapped configuration
109 void SaveCurrentConfig();
110
111 /// Reverts any mapped changes made that weren't saved
112 void RestoreConfig();
113
114 /// Returns the latest status of button input from the keyboard with parameters
115 KeyboardValues GetKeyboardValues() const;
116
117 /// Returns the latest status of button input from the keyboard modifiers with parameters
118 KeyboardModifierValues GetKeyboardModdifierValues() const;
119
120 /// Returns the latest status of button input from the mouse with parameters
121 MouseButtonValues GetMouseButtonsValues() const;
122
123 /// Returns the latest status of button input from the keyboard
124 KeyboardKey GetKeyboard() const;
125
126 /// Returns the latest status of button input from the keyboard modifiers
127 KeyboardModifier GetKeyboardModifier() const;
128
129 /// Returns the latest status of button input from the mouse
130 MouseButton GetMouseButtons() const;
131
132 /// Returns the latest mouse coordinates
133 MousePosition GetMousePosition() const;
134
135 /// Returns the latest mouse wheel change
136 AnalogStickState GetMouseWheel() const;
137
138 /**
139 * Adds a callback to the list of events
140 * @param update_callback InterfaceUpdateCallback that will be triggered
141 * @return an unique key corresponding to the callback index in the list
142 */
143 int SetCallback(InterfaceUpdateCallback update_callback);
144
145 /**
146 * Removes a callback from the list stopping any future events to this object
147 * @param key Key corresponding to the callback index in the list
148 */
149 void DeleteCallback(int key);
150
151private:
152 /// Helps assigning a value to keyboard_state
153 void UpdateKey(std::size_t key_index, bool status);
154
155 /**
156 * Updates the touch status of the keyboard device
157 * @param callback A CallbackStatus containing the key status
158 * @param index key ID to be updated
159 */
160 void SetKeyboardButton(const Common::Input::CallbackStatus& callback, std::size_t index);
161
162 /**
163 * Updates the keyboard status of the keyboard device
164 * @param callback A CallbackStatus containing the modifier key status
165 * @param index modifier key ID to be updated
166 */
167 void SetKeyboardModifier(const Common::Input::CallbackStatus& callback, std::size_t index);
168
169 /**
170 * Updates the mouse button status of the mouse device
171 * @param callback A CallbackStatus containing the button status
172 * @param index Button ID to be updated
173 */
174 void SetMouseButton(const Common::Input::CallbackStatus& callback, std::size_t index);
175
176 /**
177 * Updates the mouse wheel status of the mouse device
178 * @param callback A CallbackStatus containing the wheel status
179 * @param index wheel ID to be updated
180 */
181 void SetMouseWheel(const Common::Input::CallbackStatus& callback, std::size_t index);
182
183 /**
184 * Updates the mouse position status of the mouse device
185 * @param callback A CallbackStatus containing the position status
186 */
187 void SetMousePosition(const Common::Input::CallbackStatus& callback);
188
189 /**
190 * Triggers a callback that something has changed on the device status
191 * @param type Input type of the event to trigger
192 */
193 void TriggerOnChange(DeviceTriggerType type);
194
195 bool is_configuring{false};
196
197 KeyboardDevices keyboard_devices;
198 KeyboardModifierDevices keyboard_modifier_devices;
199 MouseButtonDevices mouse_button_devices;
200 MouseWheelDevices mouse_wheel_devices;
201 MouseStickDevice mouse_stick_device;
202
203 mutable std::mutex mutex;
204 mutable std::mutex callback_mutex;
205 std::unordered_map<int, InterfaceUpdateCallback> callback_list;
206 int last_callback_key = 0;
207
208 // Stores the current status of all external device input
209 DeviceStatus device_status;
210};
211
212} // namespace Core::HID
diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp
deleted file mode 100644
index 2cf25a870..000000000
--- a/src/core/hid/hid_core.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/assert.h"
5#include "core/hid/emulated_console.h"
6#include "core/hid/emulated_controller.h"
7#include "core/hid/emulated_devices.h"
8#include "core/hid/hid_core.h"
9#include "core/hle/service/hid/hid_util.h"
10
11namespace Core::HID {
12
13HIDCore::HIDCore()
14 : player_1{std::make_unique<EmulatedController>(NpadIdType::Player1)},
15 player_2{std::make_unique<EmulatedController>(NpadIdType::Player2)},
16 player_3{std::make_unique<EmulatedController>(NpadIdType::Player3)},
17 player_4{std::make_unique<EmulatedController>(NpadIdType::Player4)},
18 player_5{std::make_unique<EmulatedController>(NpadIdType::Player5)},
19 player_6{std::make_unique<EmulatedController>(NpadIdType::Player6)},
20 player_7{std::make_unique<EmulatedController>(NpadIdType::Player7)},
21 player_8{std::make_unique<EmulatedController>(NpadIdType::Player8)},
22 other{std::make_unique<EmulatedController>(NpadIdType::Other)},
23 handheld{std::make_unique<EmulatedController>(NpadIdType::Handheld)},
24 console{std::make_unique<EmulatedConsole>()}, devices{std::make_unique<EmulatedDevices>()} {}
25
26HIDCore::~HIDCore() = default;
27
28EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type) {
29 switch (npad_id_type) {
30 case NpadIdType::Player1:
31 return player_1.get();
32 case NpadIdType::Player2:
33 return player_2.get();
34 case NpadIdType::Player3:
35 return player_3.get();
36 case NpadIdType::Player4:
37 return player_4.get();
38 case NpadIdType::Player5:
39 return player_5.get();
40 case NpadIdType::Player6:
41 return player_6.get();
42 case NpadIdType::Player7:
43 return player_7.get();
44 case NpadIdType::Player8:
45 return player_8.get();
46 case NpadIdType::Other:
47 return other.get();
48 case NpadIdType::Handheld:
49 return handheld.get();
50 case NpadIdType::Invalid:
51 default:
52 ASSERT_MSG(false, "Invalid NpadIdType={}", npad_id_type);
53 return nullptr;
54 }
55}
56
57const EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type) const {
58 switch (npad_id_type) {
59 case NpadIdType::Player1:
60 return player_1.get();
61 case NpadIdType::Player2:
62 return player_2.get();
63 case NpadIdType::Player3:
64 return player_3.get();
65 case NpadIdType::Player4:
66 return player_4.get();
67 case NpadIdType::Player5:
68 return player_5.get();
69 case NpadIdType::Player6:
70 return player_6.get();
71 case NpadIdType::Player7:
72 return player_7.get();
73 case NpadIdType::Player8:
74 return player_8.get();
75 case NpadIdType::Other:
76 return other.get();
77 case NpadIdType::Handheld:
78 return handheld.get();
79 case NpadIdType::Invalid:
80 default:
81 ASSERT_MSG(false, "Invalid NpadIdType={}", npad_id_type);
82 return nullptr;
83 }
84}
85EmulatedConsole* HIDCore::GetEmulatedConsole() {
86 return console.get();
87}
88
89const EmulatedConsole* HIDCore::GetEmulatedConsole() const {
90 return console.get();
91}
92
93EmulatedDevices* HIDCore::GetEmulatedDevices() {
94 return devices.get();
95}
96
97const EmulatedDevices* HIDCore::GetEmulatedDevices() const {
98 return devices.get();
99}
100
101EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t index) {
102 return GetEmulatedController(Service::HID::IndexToNpadIdType(index));
103}
104
105const EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t index) const {
106 return GetEmulatedController(Service::HID::IndexToNpadIdType(index));
107}
108
109void HIDCore::SetSupportedStyleTag(NpadStyleTag style_tag) {
110 supported_style_tag.raw = style_tag.raw;
111 player_1->SetSupportedNpadStyleTag(supported_style_tag);
112 player_2->SetSupportedNpadStyleTag(supported_style_tag);
113 player_3->SetSupportedNpadStyleTag(supported_style_tag);
114 player_4->SetSupportedNpadStyleTag(supported_style_tag);
115 player_5->SetSupportedNpadStyleTag(supported_style_tag);
116 player_6->SetSupportedNpadStyleTag(supported_style_tag);
117 player_7->SetSupportedNpadStyleTag(supported_style_tag);
118 player_8->SetSupportedNpadStyleTag(supported_style_tag);
119 other->SetSupportedNpadStyleTag(supported_style_tag);
120 handheld->SetSupportedNpadStyleTag(supported_style_tag);
121}
122
123NpadStyleTag HIDCore::GetSupportedStyleTag() const {
124 return supported_style_tag;
125}
126
127s8 HIDCore::GetPlayerCount() const {
128 s8 active_players = 0;
129 for (std::size_t player_index = 0; player_index < available_controllers - 2; ++player_index) {
130 const auto* const controller = GetEmulatedControllerByIndex(player_index);
131 if (controller->IsConnected()) {
132 active_players++;
133 }
134 }
135 return active_players;
136}
137
138NpadIdType HIDCore::GetFirstNpadId() const {
139 for (std::size_t player_index = 0; player_index < available_controllers; ++player_index) {
140 const auto* const controller = GetEmulatedControllerByIndex(player_index);
141 if (controller->IsConnected()) {
142 return controller->GetNpadIdType();
143 }
144 }
145 return NpadIdType::Player1;
146}
147
148NpadIdType HIDCore::GetFirstDisconnectedNpadId() const {
149 for (std::size_t player_index = 0; player_index < available_controllers; ++player_index) {
150 const auto* const controller = GetEmulatedControllerByIndex(player_index);
151 if (!controller->IsConnected()) {
152 return controller->GetNpadIdType();
153 }
154 }
155 return NpadIdType::Player1;
156}
157
158void HIDCore::SetLastActiveController(NpadIdType npad_id) {
159 last_active_controller = npad_id;
160}
161
162NpadIdType HIDCore::GetLastActiveController() const {
163 return last_active_controller;
164}
165
166void HIDCore::EnableAllControllerConfiguration() {
167 player_1->EnableConfiguration();
168 player_2->EnableConfiguration();
169 player_3->EnableConfiguration();
170 player_4->EnableConfiguration();
171 player_5->EnableConfiguration();
172 player_6->EnableConfiguration();
173 player_7->EnableConfiguration();
174 player_8->EnableConfiguration();
175 other->EnableConfiguration();
176 handheld->EnableConfiguration();
177}
178
179void HIDCore::DisableAllControllerConfiguration() {
180 player_1->DisableConfiguration();
181 player_2->DisableConfiguration();
182 player_3->DisableConfiguration();
183 player_4->DisableConfiguration();
184 player_5->DisableConfiguration();
185 player_6->DisableConfiguration();
186 player_7->DisableConfiguration();
187 player_8->DisableConfiguration();
188 other->DisableConfiguration();
189 handheld->DisableConfiguration();
190}
191
192void HIDCore::ReloadInputDevices() {
193 player_1->ReloadFromSettings();
194 player_2->ReloadFromSettings();
195 player_3->ReloadFromSettings();
196 player_4->ReloadFromSettings();
197 player_5->ReloadFromSettings();
198 player_6->ReloadFromSettings();
199 player_7->ReloadFromSettings();
200 player_8->ReloadFromSettings();
201 other->ReloadFromSettings();
202 handheld->ReloadFromSettings();
203 console->ReloadFromSettings();
204 devices->ReloadFromSettings();
205}
206
207void HIDCore::UnloadInputDevices() {
208 player_1->UnloadInput();
209 player_2->UnloadInput();
210 player_3->UnloadInput();
211 player_4->UnloadInput();
212 player_5->UnloadInput();
213 player_6->UnloadInput();
214 player_7->UnloadInput();
215 player_8->UnloadInput();
216 other->UnloadInput();
217 handheld->UnloadInput();
218 console->UnloadInput();
219 devices->UnloadInput();
220}
221
222} // namespace Core::HID
diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h
deleted file mode 100644
index 80abab18b..000000000
--- a/src/core/hid/hid_core.h
+++ /dev/null
@@ -1,89 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7
8#include "common/common_funcs.h"
9#include "core/hid/hid_types.h"
10
11namespace Core::HID {
12class EmulatedConsole;
13class EmulatedController;
14class EmulatedDevices;
15} // namespace Core::HID
16
17namespace Core::HID {
18
19class HIDCore {
20public:
21 explicit HIDCore();
22 ~HIDCore();
23
24 YUZU_NON_COPYABLE(HIDCore);
25 YUZU_NON_MOVEABLE(HIDCore);
26
27 EmulatedController* GetEmulatedController(NpadIdType npad_id_type);
28 const EmulatedController* GetEmulatedController(NpadIdType npad_id_type) const;
29
30 EmulatedController* GetEmulatedControllerByIndex(std::size_t index);
31 const EmulatedController* GetEmulatedControllerByIndex(std::size_t index) const;
32
33 EmulatedConsole* GetEmulatedConsole();
34 const EmulatedConsole* GetEmulatedConsole() const;
35
36 EmulatedDevices* GetEmulatedDevices();
37 const EmulatedDevices* GetEmulatedDevices() const;
38
39 void SetSupportedStyleTag(NpadStyleTag style_tag);
40 NpadStyleTag GetSupportedStyleTag() const;
41
42 /// Counts the connected players from P1-P8
43 s8 GetPlayerCount() const;
44
45 /// Returns the first connected npad id
46 NpadIdType GetFirstNpadId() const;
47
48 /// Returns the first disconnected npad id
49 NpadIdType GetFirstDisconnectedNpadId() const;
50
51 /// Sets the npad id of the last active controller
52 void SetLastActiveController(NpadIdType npad_id);
53
54 /// Returns the npad id of the last controller that pushed a button
55 NpadIdType GetLastActiveController() const;
56
57 /// Sets all emulated controllers into configuring mode.
58 void EnableAllControllerConfiguration();
59
60 /// Sets all emulated controllers into normal mode.
61 void DisableAllControllerConfiguration();
62
63 /// Reloads all input devices from settings
64 void ReloadInputDevices();
65
66 /// Removes all callbacks from input common
67 void UnloadInputDevices();
68
69 /// Number of emulated controllers
70 static constexpr std::size_t available_controllers{10};
71
72private:
73 std::unique_ptr<EmulatedController> player_1;
74 std::unique_ptr<EmulatedController> player_2;
75 std::unique_ptr<EmulatedController> player_3;
76 std::unique_ptr<EmulatedController> player_4;
77 std::unique_ptr<EmulatedController> player_5;
78 std::unique_ptr<EmulatedController> player_6;
79 std::unique_ptr<EmulatedController> player_7;
80 std::unique_ptr<EmulatedController> player_8;
81 std::unique_ptr<EmulatedController> other;
82 std::unique_ptr<EmulatedController> handheld;
83 std::unique_ptr<EmulatedConsole> console;
84 std::unique_ptr<EmulatedDevices> devices;
85 NpadStyleTag supported_style_tag{NpadStyleSet::All};
86 NpadIdType last_active_controller{NpadIdType::Handheld};
87};
88
89} // namespace Core::HID
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
deleted file mode 100644
index a81ed6af0..000000000
--- a/src/core/hid/hid_types.h
+++ /dev/null
@@ -1,736 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/bit_field.h"
7#include "common/common_funcs.h"
8#include "common/common_types.h"
9#include "common/point.h"
10#include "common/uuid.h"
11#include "common/vector_math.h"
12
13namespace Core::HID {
14
15enum class DeviceIndex : u8 {
16 Left = 0,
17 Right = 1,
18 None = 2,
19 MaxDeviceIndex = 3,
20};
21
22// This is nn::hid::NpadButton
23enum class NpadButton : u64 {
24 None = 0,
25 A = 1U << 0,
26 B = 1U << 1,
27 X = 1U << 2,
28 Y = 1U << 3,
29 StickL = 1U << 4,
30 StickR = 1U << 5,
31 L = 1U << 6,
32 R = 1U << 7,
33 ZL = 1U << 8,
34 ZR = 1U << 9,
35 Plus = 1U << 10,
36 Minus = 1U << 11,
37
38 Left = 1U << 12,
39 Up = 1U << 13,
40 Right = 1U << 14,
41 Down = 1U << 15,
42
43 StickLLeft = 1U << 16,
44 StickLUp = 1U << 17,
45 StickLRight = 1U << 18,
46 StickLDown = 1U << 19,
47
48 StickRLeft = 1U << 20,
49 StickRUp = 1U << 21,
50 StickRRight = 1U << 22,
51 StickRDown = 1U << 23,
52
53 LeftSL = 1U << 24,
54 LeftSR = 1U << 25,
55
56 RightSL = 1U << 26,
57 RightSR = 1U << 27,
58
59 Palma = 1U << 28,
60 Verification = 1U << 29,
61 HandheldLeftB = 1U << 30,
62 LagonCLeft = 1U << 31,
63 LagonCUp = 1ULL << 32,
64 LagonCRight = 1ULL << 33,
65 LagonCDown = 1ULL << 34,
66
67 All = 0xFFFFFFFFFFFFFFFFULL,
68};
69DECLARE_ENUM_FLAG_OPERATORS(NpadButton);
70
71enum class KeyboardKeyIndex : u32 {
72 A = 4,
73 B = 5,
74 C = 6,
75 D = 7,
76 E = 8,
77 F = 9,
78 G = 10,
79 H = 11,
80 I = 12,
81 J = 13,
82 K = 14,
83 L = 15,
84 M = 16,
85 N = 17,
86 O = 18,
87 P = 19,
88 Q = 20,
89 R = 21,
90 S = 22,
91 T = 23,
92 U = 24,
93 V = 25,
94 W = 26,
95 X = 27,
96 Y = 28,
97 Z = 29,
98 D1 = 30,
99 D2 = 31,
100 D3 = 32,
101 D4 = 33,
102 D5 = 34,
103 D6 = 35,
104 D7 = 36,
105 D8 = 37,
106 D9 = 38,
107 D0 = 39,
108 Return = 40,
109 Escape = 41,
110 Backspace = 42,
111 Tab = 43,
112 Space = 44,
113 Minus = 45,
114 Plus = 46,
115 OpenBracket = 47,
116 CloseBracket = 48,
117 Pipe = 49,
118 Tilde = 50,
119 Semicolon = 51,
120 Quote = 52,
121 Backquote = 53,
122 Comma = 54,
123 Period = 55,
124 Slash = 56,
125 CapsLock = 57,
126 F1 = 58,
127 F2 = 59,
128 F3 = 60,
129 F4 = 61,
130 F5 = 62,
131 F6 = 63,
132 F7 = 64,
133 F8 = 65,
134 F9 = 66,
135 F10 = 67,
136 F11 = 68,
137 F12 = 69,
138 PrintScreen = 70,
139 ScrollLock = 71,
140 Pause = 72,
141 Insert = 73,
142 Home = 74,
143 PageUp = 75,
144 Delete = 76,
145 End = 77,
146 PageDown = 78,
147 RightArrow = 79,
148 LeftArrow = 80,
149 DownArrow = 81,
150 UpArrow = 82,
151 NumLock = 83,
152 NumPadDivide = 84,
153 NumPadMultiply = 85,
154 NumPadSubtract = 86,
155 NumPadAdd = 87,
156 NumPadEnter = 88,
157 NumPad1 = 89,
158 NumPad2 = 90,
159 NumPad3 = 91,
160 NumPad4 = 92,
161 NumPad5 = 93,
162 NumPad6 = 94,
163 NumPad7 = 95,
164 NumPad8 = 96,
165 NumPad9 = 97,
166 NumPad0 = 98,
167 NumPadDot = 99,
168 Backslash = 100,
169 Application = 101,
170 Power = 102,
171 NumPadEquals = 103,
172 F13 = 104,
173 F14 = 105,
174 F15 = 106,
175 F16 = 107,
176 F17 = 108,
177 F18 = 109,
178 F19 = 110,
179 F20 = 111,
180 F21 = 112,
181 F22 = 113,
182 F23 = 114,
183 F24 = 115,
184 NumPadComma = 133,
185 Ro = 135,
186 KatakanaHiragana = 136,
187 Yen = 137,
188 Henkan = 138,
189 Muhenkan = 139,
190 NumPadCommaPc98 = 140,
191 HangulEnglish = 144,
192 Hanja = 145,
193 Katakana = 146,
194 Hiragana = 147,
195 ZenkakuHankaku = 148,
196 LeftControl = 224,
197 LeftShift = 225,
198 LeftAlt = 226,
199 LeftGui = 227,
200 RightControl = 228,
201 RightShift = 229,
202 RightAlt = 230,
203 RightGui = 231,
204};
205
206// This is nn::hid::NpadIdType
207enum class NpadIdType : u32 {
208 Player1 = 0x0,
209 Player2 = 0x1,
210 Player3 = 0x2,
211 Player4 = 0x3,
212 Player5 = 0x4,
213 Player6 = 0x5,
214 Player7 = 0x6,
215 Player8 = 0x7,
216 Other = 0x10,
217 Handheld = 0x20,
218
219 Invalid = 0xFFFFFFFF,
220};
221
222enum class NpadInterfaceType : u8 {
223 Bluetooth = 1,
224 Rail = 2,
225 Usb = 3,
226 Embedded = 4,
227};
228
229// This is nn::hid::NpadStyleIndex
230enum class NpadStyleIndex : u8 {
231 None = 0,
232 ProController = 3,
233 Handheld = 4,
234 HandheldNES = 4,
235 JoyconDual = 5,
236 JoyconLeft = 6,
237 JoyconRight = 7,
238 GameCube = 8,
239 Pokeball = 9,
240 NES = 10,
241 SNES = 12,
242 N64 = 13,
243 SegaGenesis = 14,
244 SystemExt = 32,
245 System = 33,
246 MaxNpadType = 34,
247};
248
249// This is nn::hid::NpadStyleSet
250enum class NpadStyleSet : u32 {
251 None = 0,
252 Fullkey = 1U << 0,
253 Handheld = 1U << 1,
254 JoyDual = 1U << 2,
255 JoyLeft = 1U << 3,
256 JoyRight = 1U << 4,
257 Gc = 1U << 5,
258 Palma = 1U << 6,
259 Lark = 1U << 7,
260 HandheldLark = 1U << 8,
261 Lucia = 1U << 9,
262 Lagoon = 1U << 10,
263 Lager = 1U << 11,
264 SystemExt = 1U << 29,
265 System = 1U << 30,
266
267 All = 0xFFFFFFFFU,
268};
269static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
270DECLARE_ENUM_FLAG_OPERATORS(NpadStyleSet)
271
272// This is nn::hid::VibrationDevicePosition
273enum class VibrationDevicePosition : u32 {
274 None = 0,
275 Left = 1,
276 Right = 2,
277};
278
279// This is nn::hid::VibrationDeviceType
280enum class VibrationDeviceType : u32 {
281 Unknown = 0,
282 LinearResonantActuator = 1,
283 GcErm = 2,
284 N64 = 3,
285};
286
287// This is nn::hid::VibrationGcErmCommand
288enum class VibrationGcErmCommand : u64 {
289 Stop = 0,
290 Start = 1,
291 StopHard = 2,
292};
293
294// This is nn::hid::GyroscopeZeroDriftMode
295enum class GyroscopeZeroDriftMode : u32 {
296 Loose = 0,
297 Standard = 1,
298 Tight = 2,
299};
300
301// This is nn::settings::system::TouchScreenMode
302enum class TouchScreenMode : u32 {
303 Stylus = 0,
304 Standard = 1,
305};
306
307// This is nn::hid::TouchScreenModeForNx
308enum class TouchScreenModeForNx : u8 {
309 UseSystemSetting,
310 Finger,
311 Heat2,
312};
313
314// This is nn::hid::system::NpadBatteryLevel
315enum class NpadBatteryLevel : u32 {
316 Empty,
317 Critical,
318 Low,
319 High,
320 Full,
321};
322
323// This is nn::hid::NpadStyleTag
324struct NpadStyleTag {
325 union {
326 NpadStyleSet raw{};
327
328 BitField<0, 1, u32> fullkey;
329 BitField<1, 1, u32> handheld;
330 BitField<2, 1, u32> joycon_dual;
331 BitField<3, 1, u32> joycon_left;
332 BitField<4, 1, u32> joycon_right;
333 BitField<5, 1, u32> gamecube;
334 BitField<6, 1, u32> palma;
335 BitField<7, 1, u32> lark;
336 BitField<8, 1, u32> handheld_lark;
337 BitField<9, 1, u32> lucia;
338 BitField<10, 1, u32> lagoon;
339 BitField<11, 1, u32> lager;
340 BitField<29, 1, u32> system_ext;
341 BitField<30, 1, u32> system;
342 };
343};
344static_assert(sizeof(NpadStyleTag) == 4, "NpadStyleTag is an invalid size");
345
346// This is nn::hid::TouchAttribute
347struct TouchAttribute {
348 union {
349 u32 raw{};
350 BitField<0, 1, u32> start_touch;
351 BitField<1, 1, u32> end_touch;
352 };
353};
354static_assert(sizeof(TouchAttribute) == 0x4, "TouchAttribute is an invalid size");
355
356// This is nn::hid::TouchState
357struct TouchState {
358 u64 delta_time{};
359 TouchAttribute attribute{};
360 u32 finger{};
361 Common::Point<u32> position{};
362 u32 diameter_x{};
363 u32 diameter_y{};
364 u32 rotation_angle{};
365};
366static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
367
368struct TouchFinger {
369 u64 last_touch{};
370 Common::Point<float> position{};
371 u32 id{};
372 TouchAttribute attribute{};
373 bool pressed{};
374};
375
376// This is nn::hid::TouchScreenConfigurationForNx
377struct TouchScreenConfigurationForNx {
378 TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting};
379 INSERT_PADDING_BYTES(0xF);
380};
381static_assert(sizeof(TouchScreenConfigurationForNx) == 0x10,
382 "TouchScreenConfigurationForNx is an invalid size");
383
384struct NpadColor {
385 u8 r{};
386 u8 g{};
387 u8 b{};
388 u8 a{};
389};
390static_assert(sizeof(NpadColor) == 4, "NpadColor is an invalid size");
391
392// This is nn::hid::NpadControllerColor
393struct NpadControllerColor {
394 NpadColor body{};
395 NpadColor button{};
396};
397static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size");
398
399// This is nn::hid::AnalogStickState
400struct AnalogStickState {
401 s32 x{};
402 s32 y{};
403};
404static_assert(sizeof(AnalogStickState) == 8, "AnalogStickState is an invalid size");
405
406// This is nn::hid::server::NpadGcTriggerState
407struct NpadGcTriggerState {
408 s64 sampling_number{};
409 s32 left{};
410 s32 right{};
411};
412static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
413
414// This is nn::hid::system::NpadPowerInfo
415struct NpadPowerInfo {
416 bool is_powered{};
417 bool is_charging{};
418 INSERT_PADDING_BYTES(0x6);
419 NpadBatteryLevel battery_level{NpadBatteryLevel::Full};
420};
421static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size");
422
423struct LedPattern {
424 explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
425 position1.Assign(light1);
426 position2.Assign(light2);
427 position3.Assign(light3);
428 position4.Assign(light4);
429 }
430 union {
431 u64 raw{};
432 BitField<0, 1, u64> position1;
433 BitField<1, 1, u64> position2;
434 BitField<2, 1, u64> position3;
435 BitField<3, 1, u64> position4;
436 };
437};
438
439struct HomeButtonState {
440 union {
441 u64 raw{};
442
443 // Buttons
444 BitField<0, 1, u64> home;
445 };
446};
447static_assert(sizeof(HomeButtonState) == 0x8, "HomeButtonState has incorrect size.");
448
449struct CaptureButtonState {
450 union {
451 u64 raw{};
452
453 // Buttons
454 BitField<0, 1, u64> capture;
455 };
456};
457static_assert(sizeof(CaptureButtonState) == 0x8, "CaptureButtonState has incorrect size.");
458
459struct NpadButtonState {
460 union {
461 NpadButton raw{};
462
463 // Buttons
464 BitField<0, 1, u64> a;
465 BitField<1, 1, u64> b;
466 BitField<2, 1, u64> x;
467 BitField<3, 1, u64> y;
468 BitField<4, 1, u64> stick_l;
469 BitField<5, 1, u64> stick_r;
470 BitField<6, 1, u64> l;
471 BitField<7, 1, u64> r;
472 BitField<8, 1, u64> zl;
473 BitField<9, 1, u64> zr;
474 BitField<10, 1, u64> plus;
475 BitField<11, 1, u64> minus;
476
477 // D-Pad
478 BitField<12, 1, u64> left;
479 BitField<13, 1, u64> up;
480 BitField<14, 1, u64> right;
481 BitField<15, 1, u64> down;
482
483 // Left JoyStick
484 BitField<16, 1, u64> stick_l_left;
485 BitField<17, 1, u64> stick_l_up;
486 BitField<18, 1, u64> stick_l_right;
487 BitField<19, 1, u64> stick_l_down;
488
489 // Right JoyStick
490 BitField<20, 1, u64> stick_r_left;
491 BitField<21, 1, u64> stick_r_up;
492 BitField<22, 1, u64> stick_r_right;
493 BitField<23, 1, u64> stick_r_down;
494
495 BitField<24, 1, u64> left_sl;
496 BitField<25, 1, u64> left_sr;
497
498 BitField<26, 1, u64> right_sl;
499 BitField<27, 1, u64> right_sr;
500
501 BitField<28, 1, u64> palma;
502 BitField<29, 1, u64> verification;
503 BitField<30, 1, u64> handheld_left_b;
504 BitField<31, 1, u64> lagon_c_left;
505 BitField<32, 1, u64> lagon_c_up;
506 BitField<33, 1, u64> lagon_c_right;
507 BitField<34, 1, u64> lagon_c_down;
508 };
509};
510static_assert(sizeof(NpadButtonState) == 0x8, "NpadButtonState has incorrect size.");
511
512// This is nn::hid::DebugPadButton
513struct DebugPadButton {
514 union {
515 u32 raw{};
516 BitField<0, 1, u32> a;
517 BitField<1, 1, u32> b;
518 BitField<2, 1, u32> x;
519 BitField<3, 1, u32> y;
520 BitField<4, 1, u32> l;
521 BitField<5, 1, u32> r;
522 BitField<6, 1, u32> zl;
523 BitField<7, 1, u32> zr;
524 BitField<8, 1, u32> plus;
525 BitField<9, 1, u32> minus;
526 BitField<10, 1, u32> d_left;
527 BitField<11, 1, u32> d_up;
528 BitField<12, 1, u32> d_right;
529 BitField<13, 1, u32> d_down;
530 };
531};
532static_assert(sizeof(DebugPadButton) == 0x4, "DebugPadButton is an invalid size");
533
534// This is nn::hid::ConsoleSixAxisSensorHandle
535struct ConsoleSixAxisSensorHandle {
536 u8 unknown_1{};
537 u8 unknown_2{};
538 INSERT_PADDING_BYTES_NOINIT(2);
539};
540static_assert(sizeof(ConsoleSixAxisSensorHandle) == 4,
541 "ConsoleSixAxisSensorHandle is an invalid size");
542
543// This is nn::hid::SixAxisSensorHandle
544struct SixAxisSensorHandle {
545 NpadStyleIndex npad_type{NpadStyleIndex::None};
546 u8 npad_id{};
547 DeviceIndex device_index{DeviceIndex::None};
548 INSERT_PADDING_BYTES_NOINIT(1);
549};
550static_assert(sizeof(SixAxisSensorHandle) == 4, "SixAxisSensorHandle is an invalid size");
551
552// These parameters seem related to how much gyro/accelerometer is used
553struct SixAxisSensorFusionParameters {
554 f32 parameter1{0.03f}; // Range 0.0 to 1.0, default 0.03
555 f32 parameter2{0.4f}; // Default 0.4
556};
557static_assert(sizeof(SixAxisSensorFusionParameters) == 8,
558 "SixAxisSensorFusionParameters is an invalid size");
559
560// This is nn::hid::server::SixAxisSensorProperties
561struct SixAxisSensorProperties {
562 union {
563 u8 raw{};
564 BitField<0, 1, u8> is_newly_assigned;
565 BitField<1, 1, u8> is_firmware_update_available;
566 };
567};
568static_assert(sizeof(SixAxisSensorProperties) == 1, "SixAxisSensorProperties is an invalid size");
569
570// This is nn::hid::SixAxisSensorCalibrationParameter
571struct SixAxisSensorCalibrationParameter {
572 std::array<u8, 0x744> unknown_data{};
573};
574static_assert(sizeof(SixAxisSensorCalibrationParameter) == 0x744,
575 "SixAxisSensorCalibrationParameter is an invalid size");
576
577// This is nn::hid::SixAxisSensorIcInformation
578struct SixAxisSensorIcInformation {
579 f32 angular_rate{2000.0f}; // dps
580 std::array<f32, 6> unknown_gyro_data1{
581 -10.0f, -10.0f, -10.0f, 10.0f, 10.0f, 10.0f,
582 }; // dps
583 std::array<f32, 9> unknown_gyro_data2{
584 0.95f, -0.003f, -0.003f, -0.003f, 0.95f, -0.003f, -0.003f, -0.003f, 0.95f,
585 };
586 std::array<f32, 9> unknown_gyro_data3{
587 1.05f, 0.003f, 0.003f, 0.003f, 1.05f, 0.003f, 0.003f, 0.003f, 1.05f,
588 };
589 f32 acceleration_range{8.0f}; // g force
590 std::array<f32, 6> unknown_accel_data1{
591 -0.0612f, -0.0612f, -0.0612f, 0.0612f, 0.0612f, 0.0612f,
592 }; // g force
593 std::array<f32, 9> unknown_accel_data2{
594 0.95f, -0.003f, -0.003f, -0.003f, 0.95f, -0.003f, -0.003f, -0.003f, 0.95f,
595 };
596 std::array<f32, 9> unknown_accel_data3{
597 1.05f, 0.003f, 0.003f, 0.003f, 1.05f, 0.003f, 0.003f, 0.003f, 1.05f,
598 };
599};
600static_assert(sizeof(SixAxisSensorIcInformation) == 0xC8,
601 "SixAxisSensorIcInformation is an invalid size");
602
603// This is nn::hid::SixAxisSensorAttribute
604struct SixAxisSensorAttribute {
605 union {
606 u32 raw{};
607 BitField<0, 1, u32> is_connected;
608 BitField<1, 1, u32> is_interpolated;
609 };
610};
611static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size");
612
613// This is nn::hid::SixAxisSensorState
614struct SixAxisSensorState {
615 s64 delta_time{};
616 s64 sampling_number{};
617 Common::Vec3f accel{};
618 Common::Vec3f gyro{};
619 Common::Vec3f rotation{};
620 std::array<Common::Vec3f, 3> orientation{};
621 SixAxisSensorAttribute attribute{};
622 INSERT_PADDING_BYTES(4); // Reserved
623};
624static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size");
625
626// This is nn::hid::VibrationDeviceHandle
627struct VibrationDeviceHandle {
628 NpadStyleIndex npad_type{NpadStyleIndex::None};
629 u8 npad_id{};
630 DeviceIndex device_index{DeviceIndex::None};
631 INSERT_PADDING_BYTES_NOINIT(1);
632};
633static_assert(sizeof(VibrationDeviceHandle) == 4, "SixAxisSensorHandle is an invalid size");
634
635// This is nn::hid::VibrationValue
636struct VibrationValue {
637 f32 low_amplitude{};
638 f32 low_frequency{};
639 f32 high_amplitude{};
640 f32 high_frequency{};
641};
642static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size.");
643
644constexpr VibrationValue DEFAULT_VIBRATION_VALUE{
645 .low_amplitude = 0.0f,
646 .low_frequency = 160.0f,
647 .high_amplitude = 0.0f,
648 .high_frequency = 320.0f,
649};
650
651// This is nn::hid::VibrationDeviceInfo
652struct VibrationDeviceInfo {
653 VibrationDeviceType type{};
654 VibrationDevicePosition position{};
655};
656static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size.");
657
658// This is nn::hid::KeyboardModifier
659struct KeyboardModifier {
660 union {
661 u32 raw{};
662 BitField<0, 1, u32> control;
663 BitField<1, 1, u32> shift;
664 BitField<2, 1, u32> left_alt;
665 BitField<3, 1, u32> right_alt;
666 BitField<4, 1, u32> gui;
667 BitField<8, 1, u32> caps_lock;
668 BitField<9, 1, u32> scroll_lock;
669 BitField<10, 1, u32> num_lock;
670 BitField<11, 1, u32> katakana;
671 BitField<12, 1, u32> hiragana;
672 };
673};
674
675static_assert(sizeof(KeyboardModifier) == 0x4, "KeyboardModifier is an invalid size");
676
677// This is nn::hid::KeyboardAttribute
678struct KeyboardAttribute {
679 union {
680 u32 raw{};
681 BitField<0, 1, u32> is_connected;
682 };
683};
684static_assert(sizeof(KeyboardAttribute) == 0x4, "KeyboardAttribute is an invalid size");
685
686// This is nn::hid::KeyboardKey
687struct KeyboardKey {
688 // This should be a 256 bit flag
689 std::array<u8, 32> key{};
690};
691static_assert(sizeof(KeyboardKey) == 0x20, "KeyboardKey is an invalid size");
692
693// This is nn::hid::MouseButton
694struct MouseButton {
695 union {
696 u32_le raw{};
697 BitField<0, 1, u32> left;
698 BitField<1, 1, u32> right;
699 BitField<2, 1, u32> middle;
700 BitField<3, 1, u32> forward;
701 BitField<4, 1, u32> back;
702 };
703};
704static_assert(sizeof(MouseButton) == 0x4, "MouseButton is an invalid size");
705
706// This is nn::hid::MouseAttribute
707struct MouseAttribute {
708 union {
709 u32 raw{};
710 BitField<0, 1, u32> transferable;
711 BitField<1, 1, u32> is_connected;
712 };
713};
714static_assert(sizeof(MouseAttribute) == 0x4, "MouseAttribute is an invalid size");
715
716// This is nn::hid::detail::MouseState
717struct MouseState {
718 s64 sampling_number{};
719 s32 x{};
720 s32 y{};
721 s32 delta_x{};
722 s32 delta_y{};
723 // Axis Order in HW is switched for the wheel
724 s32 delta_wheel_y{};
725 s32 delta_wheel_x{};
726 MouseButton button{};
727 MouseAttribute attribute{};
728};
729static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size");
730
731struct UniquePadId {
732 u64 id;
733};
734static_assert(sizeof(UniquePadId) == 0x8, "UniquePadId is an invalid size");
735
736} // namespace Core::HID
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp
deleted file mode 100644
index a05716fd8..000000000
--- a/src/core/hid/input_converter.cpp
+++ /dev/null
@@ -1,436 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <random>
6
7#include "common/input.h"
8#include "core/hid/input_converter.h"
9
10namespace Core::HID {
11
12Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackStatus& callback) {
13 Common::Input::BatteryStatus battery{Common::Input::BatteryStatus::None};
14 switch (callback.type) {
15 case Common::Input::InputType::Analog:
16 case Common::Input::InputType::Trigger: {
17 const auto value = TransformToTrigger(callback).analog.value;
18 battery = Common::Input::BatteryLevel::Empty;
19 if (value > 0.2f) {
20 battery = Common::Input::BatteryLevel::Critical;
21 }
22 if (value > 0.4f) {
23 battery = Common::Input::BatteryLevel::Low;
24 }
25 if (value > 0.6f) {
26 battery = Common::Input::BatteryLevel::Medium;
27 }
28 if (value > 0.8f) {
29 battery = Common::Input::BatteryLevel::Full;
30 }
31 if (value >= 0.95f) {
32 battery = Common::Input::BatteryLevel::Charging;
33 }
34 break;
35 }
36 case Common::Input::InputType::Button:
37 battery = callback.button_status.value ? Common::Input::BatteryLevel::Charging
38 : Common::Input::BatteryLevel::Critical;
39 break;
40 case Common::Input::InputType::Battery:
41 battery = callback.battery_status;
42 break;
43 default:
44 LOG_ERROR(Input, "Conversion from type {} to battery not implemented", callback.type);
45 break;
46 }
47
48 return battery;
49}
50
51Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatus& callback) {
52 Common::Input::ButtonStatus status{};
53 switch (callback.type) {
54 case Common::Input::InputType::Analog:
55 status.value = TransformToTrigger(callback).pressed.value;
56 status.toggle = callback.analog_status.properties.toggle;
57 status.inverted = callback.analog_status.properties.inverted_button;
58 break;
59 case Common::Input::InputType::Trigger:
60 status.value = TransformToTrigger(callback).pressed.value;
61 break;
62 case Common::Input::InputType::Button:
63 status = callback.button_status;
64 break;
65 case Common::Input::InputType::Motion:
66 status.value = std::abs(callback.motion_status.gyro.x.raw_value) > 1.0f;
67 break;
68 default:
69 LOG_ERROR(Input, "Conversion from type {} to button not implemented", callback.type);
70 break;
71 }
72
73 if (status.inverted) {
74 status.value = !status.value;
75 }
76
77 return status;
78}
79
80Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatus& callback) {
81 Common::Input::MotionStatus status{};
82 switch (callback.type) {
83 case Common::Input::InputType::Button: {
84 Common::Input::AnalogProperties properties{
85 .deadzone = 0.0f,
86 .range = 1.0f,
87 .offset = 0.0f,
88 };
89 status.delta_timestamp = 1000;
90 status.force_update = true;
91 status.accel.x = {
92 .value = 0.0f,
93 .raw_value = 0.0f,
94 .properties = properties,
95 };
96 status.accel.y = {
97 .value = 0.0f,
98 .raw_value = 0.0f,
99 .properties = properties,
100 };
101 status.accel.z = {
102 .value = 0.0f,
103 .raw_value = -1.0f,
104 .properties = properties,
105 };
106 status.gyro.x = {
107 .value = 0.0f,
108 .raw_value = 0.0f,
109 .properties = properties,
110 };
111 status.gyro.y = {
112 .value = 0.0f,
113 .raw_value = 0.0f,
114 .properties = properties,
115 };
116 status.gyro.z = {
117 .value = 0.0f,
118 .raw_value = 0.0f,
119 .properties = properties,
120 };
121 if (TransformToButton(callback).value) {
122 std::random_device device;
123 std::mt19937 gen(device());
124 std::uniform_int_distribution<s16> distribution(-5000, 5000);
125 status.accel.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
126 status.accel.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
127 status.accel.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
128 status.gyro.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
129 status.gyro.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
130 status.gyro.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
131 }
132 break;
133 }
134 case Common::Input::InputType::Motion:
135 status = callback.motion_status;
136 break;
137 default:
138 LOG_ERROR(Input, "Conversion from type {} to motion not implemented", callback.type);
139 break;
140 }
141 SanitizeAnalog(status.accel.x, false);
142 SanitizeAnalog(status.accel.y, false);
143 SanitizeAnalog(status.accel.z, false);
144 SanitizeAnalog(status.gyro.x, false);
145 SanitizeAnalog(status.gyro.y, false);
146 SanitizeAnalog(status.gyro.z, false);
147
148 return status;
149}
150
151Common::Input::StickStatus TransformToStick(const Common::Input::CallbackStatus& callback) {
152 Common::Input::StickStatus status{};
153
154 switch (callback.type) {
155 case Common::Input::InputType::Stick:
156 status = callback.stick_status;
157 break;
158 default:
159 LOG_ERROR(Input, "Conversion from type {} to stick not implemented", callback.type);
160 break;
161 }
162
163 SanitizeStick(status.x, status.y, true);
164 const auto& properties_x = status.x.properties;
165 const auto& properties_y = status.y.properties;
166 const float x = status.x.value;
167 const float y = status.y.value;
168
169 // Set directional buttons
170 status.right = x > properties_x.threshold;
171 status.left = x < -properties_x.threshold;
172 status.up = y > properties_y.threshold;
173 status.down = y < -properties_y.threshold;
174
175 return status;
176}
177
178Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& callback) {
179 Common::Input::TouchStatus status{};
180
181 switch (callback.type) {
182 case Common::Input::InputType::Touch:
183 status = callback.touch_status;
184 break;
185 case Common::Input::InputType::Stick:
186 status.x = callback.stick_status.x;
187 status.y = callback.stick_status.y;
188 break;
189 default:
190 LOG_ERROR(Input, "Conversion from type {} to touch not implemented", callback.type);
191 break;
192 }
193
194 SanitizeAnalog(status.x, true);
195 SanitizeAnalog(status.y, true);
196 float& x = status.x.value;
197 float& y = status.y.value;
198
199 // Adjust if value is inverted
200 x = status.x.properties.inverted ? 1.0f + x : x;
201 y = status.y.properties.inverted ? 1.0f + y : y;
202
203 // clamp value
204 x = std::clamp(x, 0.0f, 1.0f);
205 y = std::clamp(y, 0.0f, 1.0f);
206
207 if (status.pressed.inverted) {
208 status.pressed.value = !status.pressed.value;
209 }
210
211 return status;
212}
213
214Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback) {
215 Common::Input::TriggerStatus status{};
216 float& raw_value = status.analog.raw_value;
217 bool calculate_button_value = true;
218
219 switch (callback.type) {
220 case Common::Input::InputType::Analog:
221 status.analog.properties = callback.analog_status.properties;
222 raw_value = callback.analog_status.raw_value;
223 break;
224 case Common::Input::InputType::Button:
225 status.analog.properties.range = 1.0f;
226 status.analog.properties.inverted = callback.button_status.inverted;
227 raw_value = callback.button_status.value ? 1.0f : 0.0f;
228 break;
229 case Common::Input::InputType::Trigger:
230 status = callback.trigger_status;
231 calculate_button_value = false;
232 break;
233 case Common::Input::InputType::Motion:
234 status.analog.properties.range = 1.0f;
235 raw_value = callback.motion_status.accel.x.raw_value;
236 break;
237 default:
238 LOG_ERROR(Input, "Conversion from type {} to trigger not implemented", callback.type);
239 break;
240 }
241
242 SanitizeAnalog(status.analog, true);
243 const auto& properties = status.analog.properties;
244 float& value = status.analog.value;
245
246 // Set button status
247 if (calculate_button_value) {
248 status.pressed.value = value > properties.threshold;
249 }
250
251 // Adjust if value is inverted
252 value = properties.inverted ? 1.0f + value : value;
253
254 // clamp value
255 value = std::clamp(value, 0.0f, 1.0f);
256
257 return status;
258}
259
260Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback) {
261 Common::Input::AnalogStatus status{};
262
263 switch (callback.type) {
264 case Common::Input::InputType::Analog:
265 status.properties = callback.analog_status.properties;
266 status.raw_value = callback.analog_status.raw_value;
267 break;
268 default:
269 LOG_ERROR(Input, "Conversion from type {} to analog not implemented", callback.type);
270 break;
271 }
272
273 SanitizeAnalog(status, false);
274
275 // Adjust if value is inverted
276 status.value = status.properties.inverted ? -status.value : status.value;
277
278 return status;
279}
280
281Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatus& callback) {
282 Common::Input::CameraStatus camera{};
283 switch (callback.type) {
284 case Common::Input::InputType::IrSensor:
285 camera = {
286 .format = callback.camera_status,
287 .data = callback.raw_data,
288 };
289 break;
290 default:
291 LOG_ERROR(Input, "Conversion from type {} to camera not implemented", callback.type);
292 break;
293 }
294
295 return camera;
296}
297
298Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& callback) {
299 Common::Input::NfcStatus nfc{};
300 switch (callback.type) {
301 case Common::Input::InputType::Nfc:
302 return callback.nfc_status;
303 default:
304 LOG_ERROR(Input, "Conversion from type {} to NFC not implemented", callback.type);
305 break;
306 }
307
308 return nfc;
309}
310
311Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback) {
312 switch (callback.type) {
313 case Common::Input::InputType::Color:
314 return callback.color_status;
315 break;
316 default:
317 LOG_ERROR(Input, "Conversion from type {} to color not implemented", callback.type);
318 return {};
319 break;
320 }
321}
322
323void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) {
324 const auto& properties = analog.properties;
325 float& raw_value = analog.raw_value;
326 float& value = analog.value;
327
328 if (!std::isnormal(raw_value)) {
329 raw_value = 0;
330 }
331
332 // Apply center offset
333 raw_value -= properties.offset;
334
335 // Set initial values to be formatted
336 value = raw_value;
337
338 // Calculate vector size
339 const float r = std::abs(value);
340
341 // Return zero if value is smaller than the deadzone
342 if (r <= properties.deadzone || properties.deadzone == 1.0f) {
343 analog.value = 0;
344 return;
345 }
346
347 // Adjust range of value
348 const float deadzone_factor =
349 1.0f / r * (r - properties.deadzone) / (1.0f - properties.deadzone);
350 value = value * deadzone_factor / properties.range;
351
352 // Invert direction if needed
353 if (properties.inverted) {
354 value = -value;
355 }
356
357 // Clamp value
358 if (clamp_value) {
359 value = std::clamp(value, -1.0f, 1.0f);
360 }
361}
362
363void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y,
364 bool clamp_value) {
365 const auto& properties_x = analog_x.properties;
366 const auto& properties_y = analog_y.properties;
367 float& raw_x = analog_x.raw_value;
368 float& raw_y = analog_y.raw_value;
369 float& x = analog_x.value;
370 float& y = analog_y.value;
371
372 if (!std::isnormal(raw_x)) {
373 raw_x = 0;
374 }
375 if (!std::isnormal(raw_y)) {
376 raw_y = 0;
377 }
378
379 // Apply center offset
380 raw_x += properties_x.offset;
381 raw_y += properties_y.offset;
382
383 // Apply X scale correction from offset
384 if (std::abs(properties_x.offset) < 0.75f) {
385 if (raw_x > 0) {
386 raw_x /= 1 + properties_x.offset;
387 } else {
388 raw_x /= 1 - properties_x.offset;
389 }
390 }
391
392 // Apply Y scale correction from offset
393 if (std::abs(properties_y.offset) < 0.75f) {
394 if (raw_y > 0) {
395 raw_y /= 1 + properties_y.offset;
396 } else {
397 raw_y /= 1 - properties_y.offset;
398 }
399 }
400
401 // Invert direction if needed
402 raw_x = properties_x.inverted ? -raw_x : raw_x;
403 raw_y = properties_y.inverted ? -raw_y : raw_y;
404
405 // Set initial values to be formatted
406 x = raw_x;
407 y = raw_y;
408
409 // Calculate vector size
410 float r = x * x + y * y;
411 r = std::sqrt(r);
412
413 // TODO(German77): Use deadzone and range of both axis
414
415 // Return zero if values are smaller than the deadzone
416 if (r <= properties_x.deadzone || properties_x.deadzone >= 1.0f) {
417 x = 0;
418 y = 0;
419 return;
420 }
421
422 // Adjust range of joystick
423 const float deadzone_factor =
424 1.0f / r * (r - properties_x.deadzone) / (1.0f - properties_x.deadzone);
425 x = x * deadzone_factor / properties_x.range;
426 y = y * deadzone_factor / properties_x.range;
427 r = r * deadzone_factor / properties_x.range;
428
429 // Normalize joystick
430 if (clamp_value && r > 1.0f) {
431 x /= r;
432 y /= r;
433 }
434}
435
436} // namespace Core::HID
diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h
deleted file mode 100644
index c51c03e57..000000000
--- a/src/core/hid/input_converter.h
+++ /dev/null
@@ -1,119 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6namespace Common::Input {
7struct CallbackStatus;
8enum class BatteryLevel : u32;
9using BatteryStatus = BatteryLevel;
10struct AnalogStatus;
11struct ButtonStatus;
12struct MotionStatus;
13struct StickStatus;
14struct TouchStatus;
15struct TriggerStatus;
16}; // namespace Common::Input
17
18namespace Core::HID {
19
20/**
21 * Converts raw input data into a valid battery status.
22 *
23 * @param callback Supported callbacks: Analog, Battery, Trigger.
24 * @return A valid BatteryStatus object.
25 */
26Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackStatus& callback);
27
28/**
29 * Converts raw input data into a valid button status. Applies invert properties to the output.
30 *
31 * @param callback Supported callbacks: Analog, Button, Trigger.
32 * @return A valid TouchStatus object.
33 */
34Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatus& callback);
35
36/**
37 * Converts raw input data into a valid motion status.
38 *
39 * @param callback Supported callbacks: Motion.
40 * @return A valid TouchStatus object.
41 */
42Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatus& callback);
43
44/**
45 * Converts raw input data into a valid stick status. Applies offset, deadzone, range and invert
46 * properties to the output.
47 *
48 * @param callback Supported callbacks: Stick.
49 * @return A valid StickStatus object.
50 */
51Common::Input::StickStatus TransformToStick(const Common::Input::CallbackStatus& callback);
52
53/**
54 * Converts raw input data into a valid touch status.
55 *
56 * @param callback Supported callbacks: Touch.
57 * @return A valid TouchStatus object.
58 */
59Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& callback);
60
61/**
62 * Converts raw input data into a valid trigger status. Applies offset, deadzone, range and
63 * invert properties to the output. Button status uses the threshold property if necessary.
64 *
65 * @param callback Supported callbacks: Analog, Button, Trigger.
66 * @return A valid TriggerStatus object.
67 */
68Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback);
69
70/**
71 * Converts raw input data into a valid analog status. Applies offset, deadzone, range and
72 * invert properties to the output.
73 *
74 * @param callback Supported callbacks: Analog.
75 * @return A valid AnalogStatus object.
76 */
77Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback);
78
79/**
80 * Converts raw input data into a valid camera status.
81 *
82 * @param callback Supported callbacks: Camera.
83 * @return A valid CameraObject object.
84 */
85Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatus& callback);
86
87/**
88 * Converts raw input data into a valid nfc status.
89 *
90 * @param callback Supported callbacks: Nfc.
91 * @return A valid data tag vector.
92 */
93Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& callback);
94
95/**
96 * Converts raw input data into a valid color status.
97 *
98 * @param callback Supported callbacks: Color.
99 * @return A valid Color object.
100 */
101Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback);
102
103/**
104 * Converts raw analog data into a valid analog value
105 * @param analog An analog object containing raw data and properties
106 * @param clamp_value determines if the value needs to be clamped between -1.0f and 1.0f.
107 */
108void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value);
109
110/**
111 * Converts raw stick data into a valid stick value
112 * @param analog_x raw analog data and properties for the x-axis
113 * @param analog_y raw analog data and properties for the y-axis
114 * @param clamp_value bool that determines if the value needs to be clamped into the unit circle.
115 */
116void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y,
117 bool clamp_value);
118
119} // namespace Core::HID
diff --git a/src/core/hid/input_interpreter.cpp b/src/core/hid/input_interpreter.cpp
deleted file mode 100644
index 072f38a68..000000000
--- a/src/core/hid/input_interpreter.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hid/hid_types.h"
6#include "core/hid/input_interpreter.h"
7#include "core/hle/service/hid/controllers/npad.h"
8#include "core/hle/service/hid/hid_server.h"
9#include "core/hle/service/hid/resource_manager.h"
10#include "core/hle/service/sm/sm.h"
11
12InputInterpreter::InputInterpreter(Core::System& system)
13 : npad{system.ServiceManager()
14 .GetService<Service::HID::IHidServer>("hid")
15 ->GetResourceManager()
16 ->GetNpad()} {
17 ResetButtonStates();
18}
19
20InputInterpreter::~InputInterpreter() = default;
21
22void InputInterpreter::PollInput() {
23 if (npad == nullptr) {
24 return;
25 }
26 const auto button_state = npad->GetAndResetPressState();
27
28 previous_index = current_index;
29 current_index = (current_index + 1) % button_states.size();
30
31 button_states[current_index] = button_state;
32}
33
34void InputInterpreter::ResetButtonStates() {
35 previous_index = 0;
36 current_index = 0;
37
38 button_states[0] = Core::HID::NpadButton::All;
39
40 for (std::size_t i = 1; i < button_states.size(); ++i) {
41 button_states[i] = Core::HID::NpadButton::None;
42 }
43}
44
45bool InputInterpreter::IsButtonPressed(Core::HID::NpadButton button) const {
46 return True(button_states[current_index] & button);
47}
48
49bool InputInterpreter::IsButtonPressedOnce(Core::HID::NpadButton button) const {
50 const bool current_press = True(button_states[current_index] & button);
51 const bool previous_press = True(button_states[previous_index] & button);
52
53 return current_press && !previous_press;
54}
55
56bool InputInterpreter::IsButtonHeld(Core::HID::NpadButton button) const {
57 Core::HID::NpadButton held_buttons{button_states[0]};
58
59 for (std::size_t i = 1; i < button_states.size(); ++i) {
60 held_buttons &= button_states[i];
61 }
62
63 return True(held_buttons & button);
64}
diff --git a/src/core/hid/input_interpreter.h b/src/core/hid/input_interpreter.h
deleted file mode 100644
index 3569aac93..000000000
--- a/src/core/hid/input_interpreter.h
+++ /dev/null
@@ -1,111 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "common/common_types.h"
9
10namespace Core {
11class System;
12}
13
14namespace Core::HID {
15enum class NpadButton : u64;
16}
17
18namespace Service::HID {
19class NPad;
20}
21
22/**
23 * The InputInterpreter class interfaces with HID to retrieve button press states.
24 * Input is intended to be polled every 50ms so that a button is considered to be
25 * held down after 400ms has elapsed since the initial button press and subsequent
26 * repeated presses occur every 50ms.
27 */
28class InputInterpreter {
29public:
30 explicit InputInterpreter(Core::System& system);
31 virtual ~InputInterpreter();
32
33 /// Gets a button state from HID and inserts it into the array of button states.
34 void PollInput();
35
36 /// Resets all the button states to their defaults.
37 void ResetButtonStates();
38
39 /**
40 * Checks whether the button is pressed.
41 *
42 * @param button The button to check.
43 *
44 * @returns True when the button is pressed.
45 */
46 [[nodiscard]] bool IsButtonPressed(Core::HID::NpadButton button) const;
47
48 /**
49 * Checks whether any of the buttons in the parameter list is pressed.
50 *
51 * @tparam HIDButton The buttons to check.
52 *
53 * @returns True when at least one of the buttons is pressed.
54 */
55 template <Core::HID::NpadButton... T>
56 [[nodiscard]] bool IsAnyButtonPressed() {
57 return (IsButtonPressed(T) || ...);
58 }
59
60 /**
61 * The specified button is considered to be pressed once
62 * if it is currently pressed and not pressed previously.
63 *
64 * @param button The button to check.
65 *
66 * @returns True when the button is pressed once.
67 */
68 [[nodiscard]] bool IsButtonPressedOnce(Core::HID::NpadButton button) const;
69
70 /**
71 * Checks whether any of the buttons in the parameter list is pressed once.
72 *
73 * @tparam T The buttons to check.
74 *
75 * @returns True when at least one of the buttons is pressed once.
76 */
77 template <Core::HID::NpadButton... T>
78 [[nodiscard]] bool IsAnyButtonPressedOnce() const {
79 return (IsButtonPressedOnce(T) || ...);
80 }
81
82 /**
83 * The specified button is considered to be held down if it is pressed in all 9 button states.
84 *
85 * @param button The button to check.
86 *
87 * @returns True when the button is held down.
88 */
89 [[nodiscard]] bool IsButtonHeld(Core::HID::NpadButton button) const;
90
91 /**
92 * Checks whether any of the buttons in the parameter list is held down.
93 *
94 * @tparam T The buttons to check.
95 *
96 * @returns True when at least one of the buttons is held down.
97 */
98 template <Core::HID::NpadButton... T>
99 [[nodiscard]] bool IsAnyButtonHeld() const {
100 return (IsButtonHeld(T) || ...);
101 }
102
103private:
104 std::shared_ptr<Service::HID::NPad> npad;
105
106 /// Stores 9 consecutive button states polled from HID.
107 std::array<Core::HID::NpadButton, 9> button_states{};
108
109 std::size_t previous_index{};
110 std::size_t current_index{};
111};
diff --git a/src/core/hid/irs_types.h b/src/core/hid/irs_types.h
deleted file mode 100644
index 0d1bfe53f..000000000
--- a/src/core/hid/irs_types.h
+++ /dev/null
@@ -1,301 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8#include "core/hid/hid_types.h"
9
10namespace Core::IrSensor {
11
12// This is nn::irsensor::CameraAmbientNoiseLevel
13enum class CameraAmbientNoiseLevel : u32 {
14 Low,
15 Medium,
16 High,
17 Unknown3, // This level can't be reached
18};
19
20// This is nn::irsensor::CameraLightTarget
21enum class CameraLightTarget : u32 {
22 AllLeds,
23 BrightLeds,
24 DimLeds,
25 None,
26};
27
28// This is nn::irsensor::PackedCameraLightTarget
29enum class PackedCameraLightTarget : u8 {
30 AllLeds,
31 BrightLeds,
32 DimLeds,
33 None,
34};
35
36// This is nn::irsensor::AdaptiveClusteringMode
37enum class AdaptiveClusteringMode : u32 {
38 StaticFov,
39 DynamicFov,
40};
41
42// This is nn::irsensor::AdaptiveClusteringTargetDistance
43enum class AdaptiveClusteringTargetDistance : u32 {
44 Near,
45 Middle,
46 Far,
47};
48
49// This is nn::irsensor::ImageTransferProcessorFormat
50enum class ImageTransferProcessorFormat : u32 {
51 Size320x240,
52 Size160x120,
53 Size80x60,
54 Size40x30,
55 Size20x15,
56};
57
58// This is nn::irsensor::PackedImageTransferProcessorFormat
59enum class PackedImageTransferProcessorFormat : u8 {
60 Size320x240,
61 Size160x120,
62 Size80x60,
63 Size40x30,
64 Size20x15,
65};
66
67// This is nn::irsensor::IrCameraStatus
68enum class IrCameraStatus : u32 {
69 Available,
70 Unsupported,
71 Unconnected,
72};
73
74// This is nn::irsensor::IrCameraInternalStatus
75enum class IrCameraInternalStatus : u32 {
76 Stopped,
77 FirmwareUpdateNeeded,
78 Unknown2,
79 Unknown3,
80 Unknown4,
81 FirmwareVersionRequested,
82 FirmwareVersionIsInvalid,
83 Ready,
84 Setting,
85};
86
87// This is nn::irsensor::detail::StatusManager::IrSensorMode
88enum class IrSensorMode : u64 {
89 None,
90 MomentProcessor,
91 ClusteringProcessor,
92 ImageTransferProcessor,
93 PointingProcessorMarker,
94 TeraPluginProcessor,
95 IrLedProcessor,
96};
97
98// This is nn::irsensor::ImageProcessorStatus
99enum ImageProcessorStatus : u32 {
100 Stopped,
101 Running,
102};
103
104// This is nn::irsensor::HandAnalysisMode
105enum class HandAnalysisMode : u32 {
106 None,
107 Silhouette,
108 Image,
109 SilhoueteAndImage,
110 SilhuetteOnly,
111};
112
113// This is nn::irsensor::IrSensorFunctionLevel
114enum class IrSensorFunctionLevel : u8 {
115 unknown0,
116 unknown1,
117 unknown2,
118 unknown3,
119 unknown4,
120};
121
122// This is nn::irsensor::MomentProcessorPreprocess
123enum class MomentProcessorPreprocess : u32 {
124 Unknown0,
125 Unknown1,
126};
127
128// This is nn::irsensor::PackedMomentProcessorPreprocess
129enum class PackedMomentProcessorPreprocess : u8 {
130 Unknown0,
131 Unknown1,
132};
133
134// This is nn::irsensor::PointingStatus
135enum class PointingStatus : u32 {
136 Unknown0,
137 Unknown1,
138};
139
140struct IrsRect {
141 s16 x;
142 s16 y;
143 s16 width;
144 s16 height;
145};
146
147struct IrsCentroid {
148 f32 x;
149 f32 y;
150};
151
152struct CameraConfig {
153 u64 exposure_time;
154 CameraLightTarget light_target;
155 u32 gain;
156 bool is_negative_used;
157 INSERT_PADDING_BYTES(7);
158};
159static_assert(sizeof(CameraConfig) == 0x18, "CameraConfig is an invalid size");
160
161struct PackedCameraConfig {
162 u64 exposure_time;
163 PackedCameraLightTarget light_target;
164 u8 gain;
165 bool is_negative_used;
166 INSERT_PADDING_BYTES(5);
167};
168static_assert(sizeof(PackedCameraConfig) == 0x10, "PackedCameraConfig is an invalid size");
169
170// This is nn::irsensor::IrCameraHandle
171struct IrCameraHandle {
172 u8 npad_id{};
173 Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None};
174 INSERT_PADDING_BYTES(2);
175};
176static_assert(sizeof(IrCameraHandle) == 4, "IrCameraHandle is an invalid size");
177
178// This is nn::irsensor::PackedMcuVersion
179struct PackedMcuVersion {
180 u16 major;
181 u16 minor;
182};
183static_assert(sizeof(PackedMcuVersion) == 4, "PackedMcuVersion is an invalid size");
184
185// This is nn::irsensor::PackedMomentProcessorConfig
186struct PackedMomentProcessorConfig {
187 PackedCameraConfig camera_config;
188 IrsRect window_of_interest;
189 PackedMcuVersion required_mcu_version;
190 PackedMomentProcessorPreprocess preprocess;
191 u8 preprocess_intensity_threshold;
192 INSERT_PADDING_BYTES(2);
193};
194static_assert(sizeof(PackedMomentProcessorConfig) == 0x20,
195 "PackedMomentProcessorConfig is an invalid size");
196
197// This is nn::irsensor::PackedClusteringProcessorConfig
198struct PackedClusteringProcessorConfig {
199 PackedCameraConfig camera_config;
200 IrsRect window_of_interest;
201 PackedMcuVersion required_mcu_version;
202 u32 pixel_count_min;
203 u32 pixel_count_max;
204 u8 object_intensity_min;
205 bool is_external_light_filter_enabled;
206 INSERT_PADDING_BYTES(2);
207};
208static_assert(sizeof(PackedClusteringProcessorConfig) == 0x28,
209 "PackedClusteringProcessorConfig is an invalid size");
210
211// This is nn::irsensor::PackedImageTransferProcessorConfig
212struct PackedImageTransferProcessorConfig {
213 PackedCameraConfig camera_config;
214 PackedMcuVersion required_mcu_version;
215 PackedImageTransferProcessorFormat format;
216 INSERT_PADDING_BYTES(3);
217};
218static_assert(sizeof(PackedImageTransferProcessorConfig) == 0x18,
219 "PackedImageTransferProcessorConfig is an invalid size");
220
221// This is nn::irsensor::PackedTeraPluginProcessorConfig
222struct PackedTeraPluginProcessorConfig {
223 PackedMcuVersion required_mcu_version;
224 u8 mode;
225 u8 unknown_1;
226 u8 unknown_2;
227 u8 unknown_3;
228};
229static_assert(sizeof(PackedTeraPluginProcessorConfig) == 0x8,
230 "PackedTeraPluginProcessorConfig is an invalid size");
231
232// This is nn::irsensor::PackedPointingProcessorConfig
233struct PackedPointingProcessorConfig {
234 IrsRect window_of_interest;
235 PackedMcuVersion required_mcu_version;
236};
237static_assert(sizeof(PackedPointingProcessorConfig) == 0xC,
238 "PackedPointingProcessorConfig is an invalid size");
239
240// This is nn::irsensor::PackedFunctionLevel
241struct PackedFunctionLevel {
242 IrSensorFunctionLevel function_level;
243 INSERT_PADDING_BYTES(3);
244};
245static_assert(sizeof(PackedFunctionLevel) == 0x4, "PackedFunctionLevel is an invalid size");
246
247// This is nn::irsensor::PackedImageTransferProcessorExConfig
248struct PackedImageTransferProcessorExConfig {
249 PackedCameraConfig camera_config;
250 PackedMcuVersion required_mcu_version;
251 PackedImageTransferProcessorFormat origin_format;
252 PackedImageTransferProcessorFormat trimming_format;
253 u16 trimming_start_x;
254 u16 trimming_start_y;
255 bool is_external_light_filter_enabled;
256 INSERT_PADDING_BYTES(5);
257};
258static_assert(sizeof(PackedImageTransferProcessorExConfig) == 0x20,
259 "PackedImageTransferProcessorExConfig is an invalid size");
260
261// This is nn::irsensor::PackedIrLedProcessorConfig
262struct PackedIrLedProcessorConfig {
263 PackedMcuVersion required_mcu_version;
264 u8 light_target;
265 INSERT_PADDING_BYTES(3);
266};
267static_assert(sizeof(PackedIrLedProcessorConfig) == 0x8,
268 "PackedIrLedProcessorConfig is an invalid size");
269
270// This is nn::irsensor::HandAnalysisConfig
271struct HandAnalysisConfig {
272 HandAnalysisMode mode;
273};
274static_assert(sizeof(HandAnalysisConfig) == 0x4, "HandAnalysisConfig is an invalid size");
275
276// This is nn::irsensor::detail::ProcessorState contents are different for each processor
277struct ProcessorState {
278 std::array<u8, 0xE20> processor_raw_data{};
279};
280static_assert(sizeof(ProcessorState) == 0xE20, "ProcessorState is an invalid size");
281
282// This is nn::irsensor::detail::DeviceFormat
283struct DeviceFormat {
284 Core::IrSensor::IrCameraStatus camera_status{Core::IrSensor::IrCameraStatus::Unconnected};
285 Core::IrSensor::IrCameraInternalStatus camera_internal_status{
286 Core::IrSensor::IrCameraInternalStatus::Ready};
287 Core::IrSensor::IrSensorMode mode{Core::IrSensor::IrSensorMode::None};
288 ProcessorState state{};
289};
290static_assert(sizeof(DeviceFormat) == 0xE30, "DeviceFormat is an invalid size");
291
292// This is nn::irsensor::ImageTransferProcessorState
293struct ImageTransferProcessorState {
294 u64 sampling_number;
295 Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level;
296 INSERT_PADDING_BYTES(4);
297};
298static_assert(sizeof(ImageTransferProcessorState) == 0x10,
299 "ImageTransferProcessorState is an invalid size");
300
301} // namespace Core::IrSensor
diff --git a/src/core/hid/motion_input.cpp b/src/core/hid/motion_input.cpp
deleted file mode 100644
index f56f2ae1d..000000000
--- a/src/core/hid/motion_input.cpp
+++ /dev/null
@@ -1,357 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <cmath>
5
6#include "common/math_util.h"
7#include "core/hid/motion_input.h"
8
9namespace Core::HID {
10
11MotionInput::MotionInput() {
12 // Initialize PID constants with default values
13 SetPID(0.3f, 0.005f, 0.0f);
14 SetGyroThreshold(ThresholdStandard);
15 ResetQuaternion();
16 ResetRotations();
17}
18
19void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) {
20 kp = new_kp;
21 ki = new_ki;
22 kd = new_kd;
23}
24
25void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) {
26 accel = acceleration;
27
28 accel.x = std::clamp(accel.x, -AccelMaxValue, AccelMaxValue);
29 accel.y = std::clamp(accel.y, -AccelMaxValue, AccelMaxValue);
30 accel.z = std::clamp(accel.z, -AccelMaxValue, AccelMaxValue);
31}
32
33void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
34 gyro = gyroscope - gyro_bias;
35
36 gyro.x = std::clamp(gyro.x, -GyroMaxValue, GyroMaxValue);
37 gyro.y = std::clamp(gyro.y, -GyroMaxValue, GyroMaxValue);
38 gyro.z = std::clamp(gyro.z, -GyroMaxValue, GyroMaxValue);
39
40 // Auto adjust gyro_bias to minimize drift
41 if (!IsMoving(IsAtRestRelaxed)) {
42 gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f);
43 }
44
45 // Adjust drift when calibration mode is enabled
46 if (calibration_mode) {
47 gyro_bias = (gyro_bias * 0.99f) + (gyroscope * 0.01f);
48 StopCalibration();
49 }
50
51 if (gyro.Length() < gyro_threshold * user_gyro_threshold) {
52 gyro = {};
53 } else {
54 only_accelerometer = false;
55 }
56}
57
58void MotionInput::SetQuaternion(const Common::Quaternion<f32>& quaternion) {
59 quat = quaternion;
60}
61
62void MotionInput::SetEulerAngles(const Common::Vec3f& euler_angles) {
63 const float cr = std::cos(euler_angles.x * 0.5f);
64 const float sr = std::sin(euler_angles.x * 0.5f);
65 const float cp = std::cos(euler_angles.y * 0.5f);
66 const float sp = std::sin(euler_angles.y * 0.5f);
67 const float cy = std::cos(euler_angles.z * 0.5f);
68 const float sy = std::sin(euler_angles.z * 0.5f);
69
70 quat.w = cr * cp * cy + sr * sp * sy;
71 quat.xyz.x = sr * cp * cy - cr * sp * sy;
72 quat.xyz.y = cr * sp * cy + sr * cp * sy;
73 quat.xyz.z = cr * cp * sy - sr * sp * cy;
74}
75
76void MotionInput::SetGyroBias(const Common::Vec3f& bias) {
77 gyro_bias = bias;
78}
79
80void MotionInput::SetGyroThreshold(f32 threshold) {
81 gyro_threshold = threshold;
82}
83
84void MotionInput::SetUserGyroThreshold(f32 threshold) {
85 user_gyro_threshold = threshold / ThresholdStandard;
86}
87
88void MotionInput::EnableReset(bool reset) {
89 reset_enabled = reset;
90}
91
92void MotionInput::ResetRotations() {
93 rotations = {};
94}
95
96void MotionInput::ResetQuaternion() {
97 quat = {{0.0f, 0.0f, -1.0f}, 0.0f};
98}
99
100bool MotionInput::IsMoving(f32 sensitivity) const {
101 return gyro.Length() >= sensitivity || accel.Length() <= 0.9f || accel.Length() >= 1.1f;
102}
103
104bool MotionInput::IsCalibrated(f32 sensitivity) const {
105 return real_error.Length() < sensitivity;
106}
107
108void MotionInput::UpdateRotation(u64 elapsed_time) {
109 const auto sample_period = static_cast<f32>(elapsed_time) / 1000000.0f;
110 if (sample_period > 0.1f) {
111 return;
112 }
113 rotations += gyro * sample_period;
114}
115
116void MotionInput::Calibrate() {
117 calibration_mode = true;
118 calibration_counter = 0;
119}
120
121void MotionInput::StopCalibration() {
122 if (calibration_counter++ > CalibrationSamples) {
123 calibration_mode = false;
124 ResetQuaternion();
125 ResetRotations();
126 }
127}
128
129// Based on Madgwick's implementation of Mayhony's AHRS algorithm.
130// https://github.com/xioTechnologies/Open-Source-AHRS-With-x-IMU/blob/master/x-IMU%20IMU%20and%20AHRS%20Algorithms/x-IMU%20IMU%20and%20AHRS%20Algorithms/AHRS/MahonyAHRS.cs
131void MotionInput::UpdateOrientation(u64 elapsed_time) {
132 if (!IsCalibrated(0.1f)) {
133 ResetOrientation();
134 }
135 // Short name local variable for readability
136 f32 q1 = quat.w;
137 f32 q2 = quat.xyz[0];
138 f32 q3 = quat.xyz[1];
139 f32 q4 = quat.xyz[2];
140 const auto sample_period = static_cast<f32>(elapsed_time) / 1000000.0f;
141
142 // Ignore invalid elapsed time
143 if (sample_period > 0.1f) {
144 return;
145 }
146
147 const auto normal_accel = accel.Normalized();
148 auto rad_gyro = gyro * Common::PI * 2;
149 const f32 swap = rad_gyro.x;
150 rad_gyro.x = rad_gyro.y;
151 rad_gyro.y = -swap;
152 rad_gyro.z = -rad_gyro.z;
153
154 // Clear gyro values if there is no gyro present
155 if (only_accelerometer) {
156 rad_gyro.x = 0;
157 rad_gyro.y = 0;
158 rad_gyro.z = 0;
159 }
160
161 // Ignore drift correction if acceleration is not reliable
162 if (accel.Length() >= 0.75f && accel.Length() <= 1.25f) {
163 const f32 ax = -normal_accel.x;
164 const f32 ay = normal_accel.y;
165 const f32 az = -normal_accel.z;
166
167 // Estimated direction of gravity
168 const f32 vx = 2.0f * (q2 * q4 - q1 * q3);
169 const f32 vy = 2.0f * (q1 * q2 + q3 * q4);
170 const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
171
172 // Error is cross product between estimated direction and measured direction of gravity
173 const Common::Vec3f new_real_error = {
174 az * vx - ax * vz,
175 ay * vz - az * vy,
176 ax * vy - ay * vx,
177 };
178
179 derivative_error = new_real_error - real_error;
180 real_error = new_real_error;
181
182 // Prevent integral windup
183 if (ki != 0.0f && !IsCalibrated(0.05f)) {
184 integral_error += real_error;
185 } else {
186 integral_error = {};
187 }
188
189 // Apply feedback terms
190 if (!only_accelerometer) {
191 rad_gyro += kp * real_error;
192 rad_gyro += ki * integral_error;
193 rad_gyro += kd * derivative_error;
194 } else {
195 // Give more weight to accelerometer values to compensate for the lack of gyro
196 rad_gyro += 35.0f * kp * real_error;
197 rad_gyro += 10.0f * ki * integral_error;
198 rad_gyro += 10.0f * kd * derivative_error;
199
200 // Emulate gyro values for games that need them
201 gyro.x = -rad_gyro.y;
202 gyro.y = rad_gyro.x;
203 gyro.z = -rad_gyro.z;
204 UpdateRotation(elapsed_time);
205 }
206 }
207
208 const f32 gx = rad_gyro.y;
209 const f32 gy = rad_gyro.x;
210 const f32 gz = rad_gyro.z;
211
212 // Integrate rate of change of quaternion
213 const f32 pa = q2;
214 const f32 pb = q3;
215 const f32 pc = q4;
216 q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period);
217 q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period);
218 q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period);
219 q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period);
220
221 quat.w = q1;
222 quat.xyz[0] = q2;
223 quat.xyz[1] = q3;
224 quat.xyz[2] = q4;
225 quat = quat.Normalized();
226}
227
228std::array<Common::Vec3f, 3> MotionInput::GetOrientation() const {
229 const Common::Quaternion<float> quad{
230 .xyz = {-quat.xyz[1], -quat.xyz[0], -quat.w},
231 .w = -quat.xyz[2],
232 };
233 const std::array<float, 16> matrix4x4 = quad.ToMatrix();
234
235 return {Common::Vec3f(matrix4x4[0], matrix4x4[1], -matrix4x4[2]),
236 Common::Vec3f(matrix4x4[4], matrix4x4[5], -matrix4x4[6]),
237 Common::Vec3f(-matrix4x4[8], -matrix4x4[9], matrix4x4[10])};
238}
239
240Common::Vec3f MotionInput::GetAcceleration() const {
241 return accel;
242}
243
244Common::Vec3f MotionInput::GetGyroscope() const {
245 return gyro;
246}
247
248Common::Vec3f MotionInput::GetGyroBias() const {
249 return gyro_bias;
250}
251
252Common::Quaternion<f32> MotionInput::GetQuaternion() const {
253 return quat;
254}
255
256Common::Vec3f MotionInput::GetRotations() const {
257 return rotations;
258}
259
260Common::Vec3f MotionInput::GetEulerAngles() const {
261 // roll (x-axis rotation)
262 const float sinr_cosp = 2 * (quat.w * quat.xyz.x + quat.xyz.y * quat.xyz.z);
263 const float cosr_cosp = 1 - 2 * (quat.xyz.x * quat.xyz.x + quat.xyz.y * quat.xyz.y);
264
265 // pitch (y-axis rotation)
266 const float sinp = std::sqrt(1 + 2 * (quat.w * quat.xyz.y - quat.xyz.x * quat.xyz.z));
267 const float cosp = std::sqrt(1 - 2 * (quat.w * quat.xyz.y - quat.xyz.x * quat.xyz.z));
268
269 // yaw (z-axis rotation)
270 const float siny_cosp = 2 * (quat.w * quat.xyz.z + quat.xyz.x * quat.xyz.y);
271 const float cosy_cosp = 1 - 2 * (quat.xyz.y * quat.xyz.y + quat.xyz.z * quat.xyz.z);
272
273 return {
274 std::atan2(sinr_cosp, cosr_cosp),
275 2 * std::atan2(sinp, cosp) - Common::PI / 2,
276 std::atan2(siny_cosp, cosy_cosp),
277 };
278}
279
280void MotionInput::ResetOrientation() {
281 if (!reset_enabled || only_accelerometer) {
282 return;
283 }
284 if (!IsMoving(IsAtRestRelaxed) && accel.z <= -0.9f) {
285 ++reset_counter;
286 if (reset_counter > 900) {
287 quat.w = 0;
288 quat.xyz[0] = 0;
289 quat.xyz[1] = 0;
290 quat.xyz[2] = -1;
291 SetOrientationFromAccelerometer();
292 integral_error = {};
293 reset_counter = 0;
294 }
295 } else {
296 reset_counter = 0;
297 }
298}
299
300void MotionInput::SetOrientationFromAccelerometer() {
301 int iterations = 0;
302 const f32 sample_period = 0.015f;
303
304 const auto normal_accel = accel.Normalized();
305
306 while (!IsCalibrated(0.01f) && ++iterations < 100) {
307 // Short name local variable for readability
308 f32 q1 = quat.w;
309 f32 q2 = quat.xyz[0];
310 f32 q3 = quat.xyz[1];
311 f32 q4 = quat.xyz[2];
312
313 Common::Vec3f rad_gyro;
314 const f32 ax = -normal_accel.x;
315 const f32 ay = normal_accel.y;
316 const f32 az = -normal_accel.z;
317
318 // Estimated direction of gravity
319 const f32 vx = 2.0f * (q2 * q4 - q1 * q3);
320 const f32 vy = 2.0f * (q1 * q2 + q3 * q4);
321 const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
322
323 // Error is cross product between estimated direction and measured direction of gravity
324 const Common::Vec3f new_real_error = {
325 az * vx - ax * vz,
326 ay * vz - az * vy,
327 ax * vy - ay * vx,
328 };
329
330 derivative_error = new_real_error - real_error;
331 real_error = new_real_error;
332
333 rad_gyro += 10.0f * kp * real_error;
334 rad_gyro += 5.0f * ki * integral_error;
335 rad_gyro += 10.0f * kd * derivative_error;
336
337 const f32 gx = rad_gyro.y;
338 const f32 gy = rad_gyro.x;
339 const f32 gz = rad_gyro.z;
340
341 // Integrate rate of change of quaternion
342 const f32 pa = q2;
343 const f32 pb = q3;
344 const f32 pc = q4;
345 q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period);
346 q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period);
347 q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period);
348 q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period);
349
350 quat.w = q1;
351 quat.xyz[0] = q2;
352 quat.xyz[1] = q3;
353 quat.xyz[2] = q4;
354 quat = quat.Normalized();
355 }
356}
357} // namespace Core::HID
diff --git a/src/core/hid/motion_input.h b/src/core/hid/motion_input.h
deleted file mode 100644
index 11678983d..000000000
--- a/src/core/hid/motion_input.h
+++ /dev/null
@@ -1,119 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "common/quaternion.h"
8#include "common/vector_math.h"
9
10namespace Core::HID {
11
12class MotionInput {
13public:
14 static constexpr float ThresholdLoose = 0.01f;
15 static constexpr float ThresholdStandard = 0.007f;
16 static constexpr float ThresholdThight = 0.002f;
17
18 static constexpr float IsAtRestRelaxed = 0.05f;
19 static constexpr float IsAtRestLoose = 0.02f;
20 static constexpr float IsAtRestStandard = 0.01f;
21 static constexpr float IsAtRestThight = 0.005f;
22
23 static constexpr float GyroMaxValue = 5.0f;
24 static constexpr float AccelMaxValue = 7.0f;
25
26 static constexpr std::size_t CalibrationSamples = 300;
27
28 explicit MotionInput();
29
30 MotionInput(const MotionInput&) = default;
31 MotionInput& operator=(const MotionInput&) = default;
32
33 MotionInput(MotionInput&&) = default;
34 MotionInput& operator=(MotionInput&&) = default;
35
36 void SetPID(f32 new_kp, f32 new_ki, f32 new_kd);
37 void SetAcceleration(const Common::Vec3f& acceleration);
38 void SetGyroscope(const Common::Vec3f& gyroscope);
39 void SetQuaternion(const Common::Quaternion<f32>& quaternion);
40 void SetEulerAngles(const Common::Vec3f& euler_angles);
41 void SetGyroBias(const Common::Vec3f& bias);
42 void SetGyroThreshold(f32 threshold);
43
44 /// Applies a modifier on top of the normal gyro threshold
45 void SetUserGyroThreshold(f32 threshold);
46
47 void EnableReset(bool reset);
48 void ResetRotations();
49 void ResetQuaternion();
50
51 void UpdateRotation(u64 elapsed_time);
52 void UpdateOrientation(u64 elapsed_time);
53
54 void Calibrate();
55
56 [[nodiscard]] std::array<Common::Vec3f, 3> GetOrientation() const;
57 [[nodiscard]] Common::Vec3f GetAcceleration() const;
58 [[nodiscard]] Common::Vec3f GetGyroscope() const;
59 [[nodiscard]] Common::Vec3f GetGyroBias() const;
60 [[nodiscard]] Common::Vec3f GetRotations() const;
61 [[nodiscard]] Common::Quaternion<f32> GetQuaternion() const;
62 [[nodiscard]] Common::Vec3f GetEulerAngles() const;
63
64 [[nodiscard]] bool IsMoving(f32 sensitivity) const;
65 [[nodiscard]] bool IsCalibrated(f32 sensitivity) const;
66
67private:
68 void StopCalibration();
69 void ResetOrientation();
70 void SetOrientationFromAccelerometer();
71
72 // PID constants
73 f32 kp;
74 f32 ki;
75 f32 kd;
76
77 // PID errors
78 Common::Vec3f real_error;
79 Common::Vec3f integral_error;
80 Common::Vec3f derivative_error;
81
82 // Quaternion containing the device orientation
83 Common::Quaternion<f32> quat;
84
85 // Number of full rotations in each axis
86 Common::Vec3f rotations;
87
88 // Acceleration vector measurement in G force
89 Common::Vec3f accel;
90
91 // Gyroscope vector measurement in radians/s.
92 Common::Vec3f gyro;
93
94 // Vector to be subtracted from gyro measurements
95 Common::Vec3f gyro_bias;
96
97 // Minimum gyro amplitude to detect if the device is moving
98 f32 gyro_threshold = 0.0f;
99
100 // Multiplies gyro_threshold by this value
101 f32 user_gyro_threshold = 0.0f;
102
103 // Number of invalid sequential data
104 u32 reset_counter = 0;
105
106 // If the provided data is invalid the device will be autocalibrated
107 bool reset_enabled = true;
108
109 // Use accelerometer values to calculate position
110 bool only_accelerometer = true;
111
112 // When enabled it will aggressively adjust for gyro drift
113 bool calibration_mode = false;
114
115 // Used to auto disable calibration mode
116 std::size_t calibration_counter = 0;
117};
118
119} // namespace Core::HID
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 97eb56ff0..9e05bdafa 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -13,7 +13,6 @@
13#include "core/file_sys/patch_manager.h" 13#include "core/file_sys/patch_manager.h"
14#include "core/file_sys/registered_cache.h" 14#include "core/file_sys/registered_cache.h"
15#include "core/file_sys/savedata_factory.h" 15#include "core/file_sys/savedata_factory.h"
16#include "core/hid/hid_types.h"
17#include "core/hle/kernel/k_event.h" 16#include "core/hle/kernel/k_event.h"
18#include "core/hle/kernel/k_transfer_memory.h" 17#include "core/hle/kernel/k_transfer_memory.h"
19#include "core/hle/result.h" 18#include "core/hle/result.h"
@@ -37,7 +36,6 @@
37#include "core/hle/service/caps/caps_su.h" 36#include "core/hle/service/caps/caps_su.h"
38#include "core/hle/service/caps/caps_types.h" 37#include "core/hle/service/caps/caps_types.h"
39#include "core/hle/service/filesystem/filesystem.h" 38#include "core/hle/service/filesystem/filesystem.h"
40#include "core/hle/service/hid/controllers/npad.h"
41#include "core/hle/service/ipc_helpers.h" 39#include "core/hle/service/ipc_helpers.h"
42#include "core/hle/service/ns/ns.h" 40#include "core/hle/service/ns/ns.h"
43#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" 41#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
@@ -48,6 +46,8 @@
48#include "core/hle/service/vi/vi.h" 46#include "core/hle/service/vi/vi.h"
49#include "core/hle/service/vi/vi_results.h" 47#include "core/hle/service/vi/vi_results.h"
50#include "core/memory.h" 48#include "core/memory.h"
49#include "hid_core/hid_types.h"
50#include "hid_core/resources/npad/npad.h"
51 51
52namespace Service::AM { 52namespace Service::AM {
53 53
diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp
index 3906c0fa4..c2ff444a6 100644
--- a/src/core/hle/service/am/applets/applet_cabinet.cpp
+++ b/src/core/hle/service/am/applets/applet_cabinet.cpp
@@ -5,13 +5,13 @@
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/core.h" 6#include "core/core.h"
7#include "core/frontend/applets/cabinet.h" 7#include "core/frontend/applets/cabinet.h"
8#include "core/hid/hid_core.h"
9#include "core/hle/kernel/k_event.h" 8#include "core/hle/kernel/k_event.h"
10#include "core/hle/kernel/k_readable_event.h" 9#include "core/hle/kernel/k_readable_event.h"
11#include "core/hle/service/am/am.h" 10#include "core/hle/service/am/am.h"
12#include "core/hle/service/am/applets/applet_cabinet.h" 11#include "core/hle/service/am/applets/applet_cabinet.h"
13#include "core/hle/service/mii/mii_manager.h" 12#include "core/hle/service/mii/mii_manager.h"
14#include "core/hle/service/nfc/common/device.h" 13#include "core/hle/service/nfc/common/device.h"
14#include "hid_core/hid_core.h"
15 15
16namespace Service::AM::Applets { 16namespace Service::AM::Applets {
17 17
diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp
index 9840d2547..0e4d9cc39 100644
--- a/src/core/hle/service/am/applets/applet_controller.cpp
+++ b/src/core/hle/service/am/applets/applet_controller.cpp
@@ -9,13 +9,13 @@
9#include "common/string_util.h" 9#include "common/string_util.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/frontend/applets/controller.h" 11#include "core/frontend/applets/controller.h"
12#include "core/hid/emulated_controller.h"
13#include "core/hid/hid_core.h"
14#include "core/hid/hid_types.h"
15#include "core/hle/result.h" 12#include "core/hle/result.h"
16#include "core/hle/service/am/am.h" 13#include "core/hle/service/am/am.h"
17#include "core/hle/service/am/applets/applet_controller.h" 14#include "core/hle/service/am/applets/applet_controller.h"
18#include "core/hle/service/hid/controllers/npad.h" 15#include "hid_core/frontend/emulated_controller.h"
16#include "hid_core/hid_core.h"
17#include "hid_core/hid_types.h"
18#include "hid_core/resources/npad/npad.h"
19 19
20namespace Service::AM::Applets { 20namespace Service::AM::Applets {
21 21
diff --git a/src/core/hle/service/hid/controllers/applet_resource.cpp b/src/core/hle/service/hid/controllers/applet_resource.cpp
deleted file mode 100644
index b4ff663c2..000000000
--- a/src/core/hle/service/hid/controllers/applet_resource.cpp
+++ /dev/null
@@ -1,329 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/core.h"
5#include "core/hle/kernel/k_shared_memory.h"
6#include "core/hle/service/hid/controllers/applet_resource.h"
7#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
8#include "core/hle/service/hid/errors.h"
9
10namespace Service::HID {
11
12AppletResource::AppletResource(Core::System& system_) : system{system_} {}
13
14AppletResource::~AppletResource() = default;
15
16Result AppletResource::CreateAppletResource(u64 aruid) {
17 const u64 index = GetIndexFromAruid(aruid);
18
19 if (index >= AruidIndexMax) {
20 return ResultAruidNotRegistered;
21 }
22
23 if (data[index].flag.is_assigned) {
24 return ResultAruidAlreadyRegistered;
25 }
26
27 auto& shared_memory = shared_memory_holder[index];
28 if (!shared_memory.IsMapped()) {
29 const Result result = shared_memory.Initialize(system);
30 if (result.IsError()) {
31 return result;
32 }
33 if (shared_memory.GetAddress() == nullptr) {
34 shared_memory.Finalize();
35 return ResultSharedMemoryNotInitialized;
36 }
37 }
38
39 auto* shared_memory_format = shared_memory.GetAddress();
40 if (shared_memory_format != nullptr) {
41 shared_memory_format->Initialize();
42 }
43
44 data[index].shared_memory_format = shared_memory_format;
45 data[index].flag.is_assigned.Assign(true);
46 // TODO: InitializeSixAxisControllerConfig(false);
47 active_aruid = aruid;
48 return ResultSuccess;
49}
50
51Result AppletResource::RegisterAppletResourceUserId(u64 aruid, bool enable_input) {
52 const u64 index = GetIndexFromAruid(aruid);
53
54 if (index < AruidIndexMax) {
55 return ResultAruidAlreadyRegistered;
56 }
57
58 std::size_t data_index = AruidIndexMax;
59 for (std::size_t i = 0; i < AruidIndexMax; i++) {
60 if (!data[i].flag.is_initialized) {
61 data_index = i;
62 break;
63 }
64 }
65
66 if (data_index == AruidIndexMax) {
67 return ResultAruidNoAvailableEntries;
68 }
69
70 AruidData& aruid_data = data[data_index];
71
72 aruid_data.aruid = aruid;
73 aruid_data.flag.is_initialized.Assign(true);
74 if (enable_input) {
75 aruid_data.flag.enable_pad_input.Assign(true);
76 aruid_data.flag.enable_six_axis_sensor.Assign(true);
77 aruid_data.flag.bit_18.Assign(true);
78 aruid_data.flag.enable_touchscreen.Assign(true);
79 }
80
81 data_index = AruidIndexMax;
82 for (std::size_t i = 0; i < AruidIndexMax; i++) {
83 if (registration_list.flag[i] == RegistrationStatus::Initialized) {
84 if (registration_list.aruid[i] != aruid) {
85 continue;
86 }
87 data_index = i;
88 break;
89 }
90 if (registration_list.flag[i] == RegistrationStatus::None) {
91 data_index = i;
92 break;
93 }
94 }
95
96 if (data_index == AruidIndexMax) {
97 return ResultSuccess;
98 }
99
100 registration_list.flag[data_index] = RegistrationStatus::Initialized;
101 registration_list.aruid[data_index] = aruid;
102
103 return ResultSuccess;
104}
105
106void AppletResource::UnregisterAppletResourceUserId(u64 aruid) {
107 u64 index = GetIndexFromAruid(aruid);
108
109 if (index < AruidIndexMax) {
110 if (data[index].flag.is_assigned) {
111 data[index].shared_memory_format = nullptr;
112 data[index].flag.is_assigned.Assign(false);
113 }
114 }
115
116 index = GetIndexFromAruid(aruid);
117 if (index < AruidIndexMax) {
118 DestroySevenSixAxisTransferMemory();
119 data[index].flag.raw = 0;
120 data[index].aruid = 0;
121
122 index = GetIndexFromAruid(aruid);
123 if (index < AruidIndexMax) {
124 registration_list.flag[index] = RegistrationStatus::PendingDelete;
125 }
126 }
127}
128
129void AppletResource::FreeAppletResourceId(u64 aruid) {
130 u64 index = GetIndexFromAruid(aruid);
131 if (index >= AruidIndexMax) {
132 return;
133 }
134
135 auto& aruid_data = data[index];
136 if (aruid_data.flag.is_assigned) {
137 aruid_data.shared_memory_format = nullptr;
138 aruid_data.flag.is_assigned.Assign(false);
139 }
140}
141
142u64 AppletResource::GetActiveAruid() {
143 return active_aruid;
144}
145
146Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) {
147 u64 index = GetIndexFromAruid(aruid);
148 if (index >= AruidIndexMax) {
149 return ResultAruidNotRegistered;
150 }
151
152 *out_handle = shared_memory_holder[index].GetHandle();
153 return ResultSuccess;
154}
155
156Result AppletResource::GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format,
157 u64 aruid) {
158 u64 index = GetIndexFromAruid(aruid);
159 if (index >= AruidIndexMax) {
160 return ResultAruidNotRegistered;
161 }
162
163 *out_shared_memory_format = data[index].shared_memory_format;
164 return ResultSuccess;
165}
166
167AruidData* AppletResource::GetAruidData(u64 aruid) {
168 const u64 aruid_index = GetIndexFromAruid(aruid);
169 if (aruid_index == AruidIndexMax) {
170 return nullptr;
171 }
172 return &data[aruid_index];
173}
174
175AruidData* AppletResource::GetAruidDataByIndex(std::size_t aruid_index) {
176 return &data[aruid_index];
177}
178
179bool AppletResource::IsVibrationAruidActive(u64 aruid) const {
180 return aruid == 0 || aruid == active_vibration_aruid;
181}
182
183u64 AppletResource::GetIndexFromAruid(u64 aruid) {
184 for (std::size_t i = 0; i < AruidIndexMax; i++) {
185 if (registration_list.flag[i] == RegistrationStatus::Initialized &&
186 registration_list.aruid[i] == aruid) {
187 return i;
188 }
189 }
190 return AruidIndexMax;
191}
192
193Result AppletResource::DestroySevenSixAxisTransferMemory() {
194 // TODO
195 return ResultSuccess;
196}
197
198void AppletResource::EnableInput(u64 aruid, bool is_enabled) {
199 const u64 index = GetIndexFromAruid(aruid);
200 if (index >= AruidIndexMax) {
201 return;
202 }
203
204 data[index].flag.enable_pad_input.Assign(is_enabled);
205 data[index].flag.enable_touchscreen.Assign(is_enabled);
206}
207
208void AppletResource::EnableSixAxisSensor(u64 aruid, bool is_enabled) {
209 const u64 index = GetIndexFromAruid(aruid);
210 if (index >= AruidIndexMax) {
211 return;
212 }
213
214 data[index].flag.enable_six_axis_sensor.Assign(is_enabled);
215}
216
217void AppletResource::EnablePadInput(u64 aruid, bool is_enabled) {
218 const u64 index = GetIndexFromAruid(aruid);
219 if (index >= AruidIndexMax) {
220 return;
221 }
222
223 data[index].flag.enable_pad_input.Assign(is_enabled);
224}
225
226void AppletResource::EnableTouchScreen(u64 aruid, bool is_enabled) {
227 const u64 index = GetIndexFromAruid(aruid);
228 if (index >= AruidIndexMax) {
229 return;
230 }
231
232 data[index].flag.enable_touchscreen.Assign(is_enabled);
233}
234
235void AppletResource::SetIsPalmaConnectable(u64 aruid, bool is_connectable) {
236 const u64 index = GetIndexFromAruid(aruid);
237 if (index >= AruidIndexMax) {
238 return;
239 }
240
241 data[index].flag.is_palma_connectable.Assign(is_connectable);
242}
243
244void AppletResource::EnablePalmaBoostMode(u64 aruid, bool is_enabled) {
245 const u64 index = GetIndexFromAruid(aruid);
246 if (index >= AruidIndexMax) {
247 return;
248 }
249
250 data[index].flag.enable_palma_boost_mode.Assign(is_enabled);
251}
252
253Result AppletResource::RegisterCoreAppletResource() {
254 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
255 return ResultAppletResourceOverflow;
256 }
257 if (ref_counter == 0) {
258 const u64 index = GetIndexFromAruid(0);
259 if (index < AruidIndexMax) {
260 return ResultAruidAlreadyRegistered;
261 }
262
263 std::size_t data_index = AruidIndexMax;
264 for (std::size_t i = 0; i < AruidIndexMax; i++) {
265 if (!data[i].flag.is_initialized) {
266 data_index = i;
267 break;
268 }
269 }
270
271 if (data_index == AruidIndexMax) {
272 return ResultAruidNoAvailableEntries;
273 }
274
275 AruidData& aruid_data = data[data_index];
276
277 aruid_data.aruid = 0;
278 aruid_data.flag.is_initialized.Assign(true);
279 aruid_data.flag.enable_pad_input.Assign(true);
280 aruid_data.flag.enable_six_axis_sensor.Assign(true);
281 aruid_data.flag.bit_18.Assign(true);
282 aruid_data.flag.enable_touchscreen.Assign(true);
283
284 data_index = AruidIndexMax;
285 for (std::size_t i = 0; i < AruidIndexMax; i++) {
286 if (registration_list.flag[i] == RegistrationStatus::Initialized) {
287 if (registration_list.aruid[i] != 0) {
288 continue;
289 }
290 data_index = i;
291 break;
292 }
293 if (registration_list.flag[i] == RegistrationStatus::None) {
294 data_index = i;
295 break;
296 }
297 }
298
299 Result result = ResultSuccess;
300
301 if (data_index == AruidIndexMax) {
302 result = CreateAppletResource(0);
303 } else {
304 registration_list.flag[data_index] = RegistrationStatus::Initialized;
305 registration_list.aruid[data_index] = 0;
306 }
307
308 if (result.IsError()) {
309 UnregisterAppletResourceUserId(0);
310 return result;
311 }
312 }
313 ref_counter++;
314 return ResultSuccess;
315}
316
317Result AppletResource::UnregisterCoreAppletResource() {
318 if (ref_counter == 0) {
319 return ResultAppletResourceNotInitialized;
320 }
321
322 if (--ref_counter == 0) {
323 UnregisterAppletResourceUserId(0);
324 }
325
326 return ResultSuccess;
327}
328
329} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/applet_resource.h b/src/core/hle/service/hid/controllers/applet_resource.h
deleted file mode 100644
index 0862fdc2f..000000000
--- a/src/core/hle/service/hid/controllers/applet_resource.h
+++ /dev/null
@@ -1,123 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7#include <mutex>
8
9#include "common/bit_field.h"
10#include "common/common_types.h"
11#include "core/hle/result.h"
12#include "core/hle/service/hid/controllers/shared_memory_holder.h"
13
14namespace Core {
15class System;
16}
17
18namespace Kernel {
19class KSharedMemory;
20}
21
22namespace Service::HID {
23struct SharedMemoryFormat;
24class AppletResource;
25class NPadResource;
26
27static constexpr std::size_t AruidIndexMax = 0x20;
28static constexpr u64 SystemAruid = 0;
29
30enum class RegistrationStatus : u32 {
31 None,
32 Initialized,
33 PendingDelete,
34};
35
36struct DataStatusFlag {
37 union {
38 u32 raw{};
39
40 BitField<0, 1, u32> is_initialized;
41 BitField<1, 1, u32> is_assigned;
42 BitField<16, 1, u32> enable_pad_input;
43 BitField<17, 1, u32> enable_six_axis_sensor;
44 BitField<18, 1, u32> bit_18;
45 BitField<19, 1, u32> is_palma_connectable;
46 BitField<20, 1, u32> enable_palma_boost_mode;
47 BitField<21, 1, u32> enable_touchscreen;
48 };
49};
50
51struct AruidRegisterList {
52 std::array<RegistrationStatus, AruidIndexMax> flag{};
53 std::array<u64, AruidIndexMax> aruid{};
54};
55static_assert(sizeof(AruidRegisterList) == 0x180, "AruidRegisterList is an invalid size");
56
57struct AruidData {
58 DataStatusFlag flag{};
59 u64 aruid{};
60 SharedMemoryFormat* shared_memory_format{nullptr};
61};
62
63struct HandheldConfig {
64 bool is_handheld_hid_enabled;
65 bool is_force_handheld;
66 bool is_joycon_rail_enabled;
67 bool is_force_handheld_style_vibration;
68};
69static_assert(sizeof(HandheldConfig) == 0x4, "HandheldConfig is an invalid size");
70
71struct AppletResourceHolder {
72 std::shared_ptr<AppletResource> applet_resource{nullptr};
73 std::recursive_mutex* shared_mutex{nullptr};
74 NPadResource* shared_npad_resource{nullptr};
75 std::shared_ptr<HandheldConfig> handheld_config{nullptr};
76 long* handle_1;
77};
78
79class AppletResource {
80public:
81 explicit AppletResource(Core::System& system_);
82 ~AppletResource();
83
84 Result CreateAppletResource(u64 aruid);
85
86 Result RegisterAppletResourceUserId(u64 aruid, bool enable_input);
87 void UnregisterAppletResourceUserId(u64 aruid);
88
89 void FreeAppletResourceId(u64 aruid);
90
91 u64 GetActiveAruid();
92 Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid);
93 Result GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, u64 aruid);
94 AruidData* GetAruidData(u64 aruid);
95 AruidData* GetAruidDataByIndex(std::size_t aruid_index);
96
97 bool IsVibrationAruidActive(u64 aruid) const;
98
99 u64 GetIndexFromAruid(u64 aruid);
100
101 Result DestroySevenSixAxisTransferMemory();
102
103 void EnableInput(u64 aruid, bool is_enabled);
104 void EnableSixAxisSensor(u64 aruid, bool is_enabled);
105 void EnablePadInput(u64 aruid, bool is_enabled);
106 void EnableTouchScreen(u64 aruid, bool is_enabled);
107 void SetIsPalmaConnectable(u64 aruid, bool is_connectable);
108 void EnablePalmaBoostMode(u64 aruid, bool is_enabled);
109
110 Result RegisterCoreAppletResource();
111 Result UnregisterCoreAppletResource();
112
113private:
114 u64 active_aruid{};
115 AruidRegisterList registration_list{};
116 std::array<AruidData, AruidIndexMax> data{};
117 std::array<SharedMemoryHolder, AruidIndexMax> shared_memory_holder{};
118 s32 ref_counter{};
119 u64 active_vibration_aruid;
120
121 Core::System& system;
122};
123} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/capture_button.cpp b/src/core/hle/service/hid/controllers/capture_button.cpp
deleted file mode 100644
index 7847c080e..000000000
--- a/src/core/hle/service/hid/controllers/capture_button.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core_timing.h"
5#include "core/hle/service/hid/controllers/applet_resource.h"
6#include "core/hle/service/hid/controllers/capture_button.h"
7#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
8
9namespace Service::HID {
10
11CaptureButton::CaptureButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
12
13CaptureButton::~CaptureButton() = default;
14
15void CaptureButton::OnInit() {}
16
17void CaptureButton::OnRelease() {}
18
19void CaptureButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
20 if (!smart_update) {
21 return;
22 }
23
24 std::scoped_lock shared_lock{*shared_mutex};
25 const u64 aruid = applet_resource->GetActiveAruid();
26 auto* data = applet_resource->GetAruidData(aruid);
27
28 if (data == nullptr || !data->flag.is_assigned) {
29 return;
30 }
31
32 auto& header = data->shared_memory_format->capture_button.header;
33 header.timestamp = core_timing.GetGlobalTimeNs().count();
34 header.total_entry_count = 17;
35 header.entry_count = 0;
36 header.last_entry_index = 0;
37}
38
39} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/capture_button.h b/src/core/hle/service/hid/controllers/capture_button.h
deleted file mode 100644
index dcc4715c5..000000000
--- a/src/core/hle/service/hid/controllers/capture_button.h
+++ /dev/null
@@ -1,27 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/hid/controllers/controller_base.h"
7
8namespace Service::HID {
9
10class CaptureButton final : public ControllerBase {
11public:
12 explicit CaptureButton(Core::HID::HIDCore& hid_core_);
13 ~CaptureButton() override;
14
15 // Called when the controller is initialized
16 void OnInit() override;
17
18 // When the controller is released
19 void OnRelease() override;
20
21 // When the controller is requesting an update for the shared memory
22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
23
24private:
25 bool smart_update{};
26};
27} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/console_six_axis.cpp b/src/core/hle/service/hid/controllers/console_six_axis.cpp
deleted file mode 100644
index 4b574c2e5..000000000
--- a/src/core/hle/service/hid/controllers/console_six_axis.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core_timing.h"
5#include "core/hid/emulated_console.h"
6#include "core/hid/hid_core.h"
7#include "core/hle/service/hid/controllers/console_six_axis.h"
8#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
9
10namespace Service::HID {
11
12ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
13 console = hid_core.GetEmulatedConsole();
14}
15
16ConsoleSixAxis::~ConsoleSixAxis() = default;
17
18void ConsoleSixAxis::OnInit() {}
19
20void ConsoleSixAxis::OnRelease() {}
21
22void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
23 std::scoped_lock shared_lock{*shared_mutex};
24 const u64 aruid = applet_resource->GetActiveAruid();
25 auto* data = applet_resource->GetAruidData(aruid);
26
27 if (data == nullptr || !data->flag.is_assigned) {
28 return;
29 }
30
31 ConsoleSixAxisSensorSharedMemoryFormat& shared_memory = data->shared_memory_format->console;
32
33 if (!IsControllerActivated()) {
34 return;
35 }
36
37 const auto motion_status = console->GetMotion();
38
39 shared_memory.sampling_number++;
40 shared_memory.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
41 shared_memory.verticalization_error = motion_status.verticalization_error;
42 shared_memory.gyro_bias = motion_status.gyro_bias;
43}
44
45} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/console_six_axis.h b/src/core/hle/service/hid/controllers/console_six_axis.h
deleted file mode 100644
index e3351f83c..000000000
--- a/src/core/hle/service/hid/controllers/console_six_axis.h
+++ /dev/null
@@ -1,30 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/hid/controllers/controller_base.h"
7
8namespace Core::HID {
9class EmulatedConsole;
10} // namespace Core::HID
11
12namespace Service::HID {
13class ConsoleSixAxis final : public ControllerBase {
14public:
15 explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_);
16 ~ConsoleSixAxis() override;
17
18 // Called when the controller is initialized
19 void OnInit() override;
20
21 // When the controller is released
22 void OnRelease() override;
23
24 // When the controller is requesting an update for the shared memory
25 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
26
27private:
28 Core::HID::EmulatedConsole* console = nullptr;
29};
30} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp
deleted file mode 100644
index afca7154c..000000000
--- a/src/core/hle/service/hid/controllers/controller_base.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/hid/controllers/controller_base.h"
5
6namespace Service::HID {
7
8ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {}
9ControllerBase::~ControllerBase() = default;
10
11Result ControllerBase::Activate() {
12 if (is_activated) {
13 return ResultSuccess;
14 }
15 is_activated = true;
16 OnInit();
17 return ResultSuccess;
18}
19
20Result ControllerBase::Activate(u64 aruid) {
21 return Activate();
22}
23
24void ControllerBase::DeactivateController() {
25 if (is_activated) {
26 OnRelease();
27 }
28 is_activated = false;
29}
30
31bool ControllerBase::IsControllerActivated() const {
32 return is_activated;
33}
34
35void ControllerBase::SetAppletResource(std::shared_ptr<AppletResource> resource,
36 std::recursive_mutex* resource_mutex) {
37 applet_resource = resource;
38 shared_mutex = resource_mutex;
39}
40
41} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
deleted file mode 100644
index b34b85ece..000000000
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ /dev/null
@@ -1,55 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7
8#include "common/common_types.h"
9#include "core/hle/result.h"
10#include "core/hle/service/hid/controllers/applet_resource.h"
11
12namespace Core::Timing {
13class CoreTiming;
14}
15
16namespace Core::HID {
17class HIDCore;
18} // namespace Core::HID
19
20namespace Service::HID {
21class ControllerBase {
22public:
23 explicit ControllerBase(Core::HID::HIDCore& hid_core_);
24 virtual ~ControllerBase();
25
26 // Called when the controller is initialized
27 virtual void OnInit() = 0;
28
29 // When the controller is released
30 virtual void OnRelease() = 0;
31
32 // When the controller is requesting an update for the shared memory
33 virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing) = 0;
34
35 // When the controller is requesting a motion update for the shared memory
36 virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {}
37
38 Result Activate();
39 Result Activate(u64 aruid);
40
41 void DeactivateController();
42
43 bool IsControllerActivated() const;
44
45 void SetAppletResource(std::shared_ptr<AppletResource> resource,
46 std::recursive_mutex* resource_mutex);
47
48protected:
49 bool is_activated{false};
50 std::shared_ptr<AppletResource> applet_resource{nullptr};
51 std::recursive_mutex* shared_mutex{nullptr};
52
53 Core::HID::HIDCore& hid_core;
54};
55} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/debug_mouse.cpp b/src/core/hle/service/hid/controllers/debug_mouse.cpp
deleted file mode 100644
index ceeb78d36..000000000
--- a/src/core/hle/service/hid/controllers/debug_mouse.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core_timing.h"
5#include "core/frontend/emu_window.h"
6#include "core/hid/emulated_devices.h"
7#include "core/hid/hid_core.h"
8#include "core/hle/service/hid/controllers/applet_resource.h"
9#include "core/hle/service/hid/controllers/debug_mouse.h"
10#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
11
12namespace Service::HID {
13
14DebugMouse::DebugMouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
15 emulated_devices = hid_core.GetEmulatedDevices();
16}
17
18DebugMouse::~DebugMouse() = default;
19
20void DebugMouse::OnInit() {}
21void DebugMouse::OnRelease() {}
22
23void DebugMouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
24 std::scoped_lock shared_lock{*shared_mutex};
25 const u64 aruid = applet_resource->GetActiveAruid();
26 auto* data = applet_resource->GetAruidData(aruid);
27
28 if (data == nullptr || !data->flag.is_assigned) {
29 return;
30 }
31
32 MouseSharedMemoryFormat& shared_memory = data->shared_memory_format->debug_mouse;
33
34 if (!IsControllerActivated()) {
35 shared_memory.mouse_lifo.buffer_count = 0;
36 shared_memory.mouse_lifo.buffer_tail = 0;
37 return;
38 }
39
40 next_state = {};
41
42 const auto& last_entry = shared_memory.mouse_lifo.ReadCurrentEntry().state;
43 next_state.sampling_number = last_entry.sampling_number + 1;
44
45 if (Settings::values.mouse_enabled) {
46 const auto& mouse_button_state = emulated_devices->GetMouseButtons();
47 const auto& mouse_position_state = emulated_devices->GetMousePosition();
48 const auto& mouse_wheel_state = emulated_devices->GetMouseWheel();
49 next_state.attribute.is_connected.Assign(1);
50 next_state.x = static_cast<s32>(mouse_position_state.x * Layout::ScreenUndocked::Width);
51 next_state.y = static_cast<s32>(mouse_position_state.y * Layout::ScreenUndocked::Height);
52 next_state.delta_x = next_state.x - last_entry.x;
53 next_state.delta_y = next_state.y - last_entry.y;
54 next_state.delta_wheel_x = mouse_wheel_state.x - last_mouse_wheel_state.x;
55 next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y;
56
57 last_mouse_wheel_state = mouse_wheel_state;
58 next_state.button = mouse_button_state;
59 }
60
61 shared_memory.mouse_lifo.WriteNextEntry(next_state);
62}
63
64} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/debug_mouse.h b/src/core/hle/service/hid/controllers/debug_mouse.h
deleted file mode 100644
index ec939fa9f..000000000
--- a/src/core/hle/service/hid/controllers/debug_mouse.h
+++ /dev/null
@@ -1,34 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/hid/controllers/controller_base.h"
7
8namespace Core::HID {
9class EmulatedDevices;
10struct MouseState;
11struct AnalogStickState;
12} // namespace Core::HID
13
14namespace Service::HID {
15class DebugMouse final : public ControllerBase {
16public:
17 explicit DebugMouse(Core::HID::HIDCore& hid_core_);
18 ~DebugMouse() override;
19
20 // Called when the controller is initialized
21 void OnInit() override;
22
23 // When the controller is released
24 void OnRelease() override;
25
26 // When the controller is requesting an update for the shared memory
27 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
28
29private:
30 Core::HID::MouseState next_state{};
31 Core::HID::AnalogStickState last_mouse_wheel_state{};
32 Core::HID::EmulatedDevices* emulated_devices = nullptr;
33};
34} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
deleted file mode 100644
index dc83f90f3..000000000
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/settings.h"
5#include "core/core_timing.h"
6#include "core/hid/emulated_controller.h"
7#include "core/hid/hid_core.h"
8#include "core/hid/hid_types.h"
9#include "core/hle/service/hid/controllers/applet_resource.h"
10#include "core/hle/service/hid/controllers/debug_pad.h"
11#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
12
13namespace Service::HID {
14
15DebugPad::DebugPad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
16 controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
17}
18
19DebugPad::~DebugPad() = default;
20
21void DebugPad::OnInit() {}
22
23void DebugPad::OnRelease() {}
24
25void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
26 std::scoped_lock shared_lock{*shared_mutex};
27 const u64 aruid = applet_resource->GetActiveAruid();
28 auto* data = applet_resource->GetAruidData(aruid);
29
30 if (data == nullptr || !data->flag.is_assigned) {
31 return;
32 }
33
34 DebugPadSharedMemoryFormat& shared_memory = data->shared_memory_format->debug_pad;
35
36 if (!IsControllerActivated()) {
37 shared_memory.debug_pad_lifo.buffer_count = 0;
38 shared_memory.debug_pad_lifo.buffer_tail = 0;
39 return;
40 }
41
42 const auto& last_entry = shared_memory.debug_pad_lifo.ReadCurrentEntry().state;
43 next_state.sampling_number = last_entry.sampling_number + 1;
44
45 if (Settings::values.debug_pad_enabled) {
46 next_state.attribute.connected.Assign(1);
47
48 const auto& button_state = controller->GetDebugPadButtons();
49 const auto& stick_state = controller->GetSticks();
50
51 next_state.pad_state = button_state;
52 next_state.l_stick = stick_state.left;
53 next_state.r_stick = stick_state.right;
54 }
55
56 shared_memory.debug_pad_lifo.WriteNextEntry(next_state);
57}
58
59} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
deleted file mode 100644
index dd00b2402..000000000
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ /dev/null
@@ -1,36 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/hid/controllers/controller_base.h"
7#include "core/hle/service/hid/controllers/types/debug_pad_types.h"
8
9namespace Core::HID {
10class HIDCore;
11}
12
13namespace Core::Timing {
14class CoreTiming;
15}
16
17namespace Service::HID {
18class DebugPad final : public ControllerBase {
19public:
20 explicit DebugPad(Core::HID::HIDCore& hid_core_);
21 ~DebugPad() override;
22
23 // Called when the controller is initialized
24 void OnInit() override;
25
26 // When the controller is released
27 void OnRelease() override;
28
29 // When the controller is requesting an update for the shared memory
30 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
31
32private:
33 DebugPadState next_state{};
34 Core::HID::EmulatedController* controller = nullptr;
35};
36} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/digitizer.cpp b/src/core/hle/service/hid/controllers/digitizer.cpp
deleted file mode 100644
index d5514c965..000000000
--- a/src/core/hle/service/hid/controllers/digitizer.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core_timing.h"
5#include "core/hle/service/hid/controllers/applet_resource.h"
6#include "core/hle/service/hid/controllers/digitizer.h"
7#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
8
9namespace Service::HID {
10
11Digitizer::Digitizer(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
12
13Digitizer::~Digitizer() = default;
14
15void Digitizer::OnInit() {}
16
17void Digitizer::OnRelease() {}
18
19void Digitizer::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
20 if (!smart_update) {
21 return;
22 }
23
24 std::scoped_lock shared_lock{*shared_mutex};
25 const u64 aruid = applet_resource->GetActiveAruid();
26 auto* data = applet_resource->GetAruidData(aruid);
27
28 if (data == nullptr || !data->flag.is_assigned) {
29 return;
30 }
31
32 auto& header = data->shared_memory_format->digitizer.header;
33 header.timestamp = core_timing.GetGlobalTimeNs().count();
34 header.total_entry_count = 17;
35 header.entry_count = 0;
36 header.last_entry_index = 0;
37}
38
39} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/digitizer.h b/src/core/hle/service/hid/controllers/digitizer.h
deleted file mode 100644
index d81f814c3..000000000
--- a/src/core/hle/service/hid/controllers/digitizer.h
+++ /dev/null
@@ -1,27 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/hid/controllers/controller_base.h"
7
8namespace Service::HID {
9
10class Digitizer final : public ControllerBase {
11public:
12 explicit Digitizer(Core::HID::HIDCore& hid_core_);
13 ~Digitizer() override;
14
15 // Called when the controller is initialized
16 void OnInit() override;
17
18 // When the controller is released
19 void OnRelease() override;
20
21 // When the controller is requesting an update for the shared memory
22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
23
24private:
25 bool smart_update{};
26};
27} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
deleted file mode 100644
index c73da13ee..000000000
--- a/src/core/hle/service/hid/controllers/gesture.cpp
+++ /dev/null
@@ -1,366 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/math_util.h"
5#include "common/settings.h"
6#include "core/frontend/emu_window.h"
7#include "core/hid/emulated_console.h"
8#include "core/hid/hid_core.h"
9#include "core/hle/service/hid/controllers/applet_resource.h"
10#include "core/hle/service/hid/controllers/gesture.h"
11#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
12
13namespace Service::HID {
14// HW is around 700, value is set to 400 to make it easier to trigger with mouse
15constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s
16constexpr f32 angle_threshold = 0.015f; // Threshold in radians
17constexpr f32 pinch_threshold = 0.5f; // Threshold in pixels
18constexpr f32 press_delay = 0.5f; // Time in seconds
19constexpr f32 double_tap_delay = 0.35f; // Time in seconds
20
21constexpr f32 Square(s32 num) {
22 return static_cast<f32>(num * num);
23}
24
25Gesture::Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) {
26 console = hid_core.GetEmulatedConsole();
27}
28Gesture::~Gesture() = default;
29
30void Gesture::OnInit() {
31 std::scoped_lock shared_lock{*shared_mutex};
32 const u64 aruid = applet_resource->GetActiveAruid();
33 auto* data = applet_resource->GetAruidData(aruid);
34
35 if (data == nullptr || !data->flag.is_assigned) {
36 return;
37 }
38
39 shared_memory = &data->shared_memory_format->gesture;
40 shared_memory->gesture_lifo.buffer_count = 0;
41 shared_memory->gesture_lifo.buffer_tail = 0;
42 force_update = true;
43}
44
45void Gesture::OnRelease() {}
46
47void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
48 std::scoped_lock shared_lock{*shared_mutex};
49 const u64 aruid = applet_resource->GetActiveAruid();
50 auto* data = applet_resource->GetAruidData(aruid);
51
52 if (data == nullptr || !data->flag.is_assigned) {
53 return;
54 }
55
56 shared_memory = &data->shared_memory_format->gesture;
57
58 if (!IsControllerActivated()) {
59 shared_memory->gesture_lifo.buffer_count = 0;
60 shared_memory->gesture_lifo.buffer_tail = 0;
61 return;
62 }
63
64 ReadTouchInput();
65
66 GestureProperties gesture = GetGestureProperties();
67 f32 time_difference =
68 static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) /
69 (1000 * 1000 * 1000);
70
71 // Only update if necessary
72 if (!ShouldUpdateGesture(gesture, time_difference)) {
73 return;
74 }
75
76 last_update_timestamp = shared_memory->gesture_lifo.timestamp;
77 UpdateGestureSharedMemory(gesture, time_difference);
78}
79
80void Gesture::ReadTouchInput() {
81 if (!Settings::values.touchscreen.enabled) {
82 fingers = {};
83 return;
84 }
85
86 const auto touch_status = console->GetTouch();
87 for (std::size_t id = 0; id < fingers.size(); ++id) {
88 fingers[id] = touch_status[id];
89 }
90}
91
92bool Gesture::ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference) {
93 const auto& last_entry = GetLastGestureEntry();
94 if (force_update) {
95 force_update = false;
96 return true;
97 }
98
99 // Update if coordinates change
100 for (size_t id = 0; id < MAX_POINTS; id++) {
101 if (gesture.points[id] != last_gesture.points[id]) {
102 return true;
103 }
104 }
105
106 // Update on press and hold event after 0.5 seconds
107 if (last_entry.type == GestureType::Touch && last_entry.point_count == 1 &&
108 time_difference > press_delay) {
109 return enable_press_and_tap;
110 }
111
112 return false;
113}
114
115void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference) {
116 GestureType type = GestureType::Idle;
117 GestureAttribute attributes{};
118
119 const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state;
120
121 // Reset next state to default
122 next_state.sampling_number = last_entry.sampling_number + 1;
123 next_state.delta = {};
124 next_state.vel_x = 0;
125 next_state.vel_y = 0;
126 next_state.direction = GestureDirection::None;
127 next_state.rotation_angle = 0;
128 next_state.scale = 0;
129
130 if (gesture.active_points > 0) {
131 if (last_gesture.active_points == 0) {
132 NewGesture(gesture, type, attributes);
133 } else {
134 UpdateExistingGesture(gesture, type, time_difference);
135 }
136 } else {
137 EndGesture(gesture, last_gesture, type, attributes, time_difference);
138 }
139
140 // Apply attributes
141 next_state.detection_count = gesture.detection_count;
142 next_state.type = type;
143 next_state.attributes = attributes;
144 next_state.pos = gesture.mid_point;
145 next_state.point_count = static_cast<s32>(gesture.active_points);
146 next_state.points = gesture.points;
147 last_gesture = gesture;
148
149 shared_memory->gesture_lifo.WriteNextEntry(next_state);
150}
151
152void Gesture::NewGesture(GestureProperties& gesture, GestureType& type,
153 GestureAttribute& attributes) {
154 const auto& last_entry = GetLastGestureEntry();
155
156 gesture.detection_count++;
157 type = GestureType::Touch;
158
159 // New touch after cancel is not considered new
160 if (last_entry.type != GestureType::Cancel) {
161 attributes.is_new_touch.Assign(1);
162 enable_press_and_tap = true;
163 }
164}
165
166void Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type,
167 f32 time_difference) {
168 const auto& last_entry = GetLastGestureEntry();
169
170 // Promote to pan type if touch moved
171 for (size_t id = 0; id < MAX_POINTS; id++) {
172 if (gesture.points[id] != last_gesture.points[id]) {
173 type = GestureType::Pan;
174 break;
175 }
176 }
177
178 // Number of fingers changed cancel the last event and clear data
179 if (gesture.active_points != last_gesture.active_points) {
180 type = GestureType::Cancel;
181 enable_press_and_tap = false;
182 gesture.active_points = 0;
183 gesture.mid_point = {};
184 gesture.points.fill({});
185 return;
186 }
187
188 // Calculate extra parameters of panning
189 if (type == GestureType::Pan) {
190 UpdatePanEvent(gesture, last_gesture, type, time_difference);
191 return;
192 }
193
194 // Promote to press type
195 if (last_entry.type == GestureType::Touch) {
196 type = GestureType::Press;
197 }
198}
199
200void Gesture::EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props,
201 GestureType& type, GestureAttribute& attributes, f32 time_difference) {
202 const auto& last_entry = GetLastGestureEntry();
203
204 if (last_gesture_props.active_points != 0) {
205 switch (last_entry.type) {
206 case GestureType::Touch:
207 if (enable_press_and_tap) {
208 SetTapEvent(gesture, last_gesture_props, type, attributes);
209 return;
210 }
211 type = GestureType::Cancel;
212 force_update = true;
213 break;
214 case GestureType::Press:
215 case GestureType::Tap:
216 case GestureType::Swipe:
217 case GestureType::Pinch:
218 case GestureType::Rotate:
219 type = GestureType::Complete;
220 force_update = true;
221 break;
222 case GestureType::Pan:
223 EndPanEvent(gesture, last_gesture_props, type, time_difference);
224 break;
225 default:
226 break;
227 }
228 return;
229 }
230 if (last_entry.type == GestureType::Complete || last_entry.type == GestureType::Cancel) {
231 gesture.detection_count++;
232 }
233}
234
235void Gesture::SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
236 GestureType& type, GestureAttribute& attributes) {
237 type = GestureType::Tap;
238 gesture = last_gesture_props;
239 force_update = true;
240 f32 tap_time_difference =
241 static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000);
242 last_tap_timestamp = last_update_timestamp;
243 if (tap_time_difference < double_tap_delay) {
244 attributes.is_double_tap.Assign(1);
245 }
246}
247
248void Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
249 GestureType& type, f32 time_difference) {
250 const auto& last_entry = GetLastGestureEntry();
251
252 next_state.delta = gesture.mid_point - last_entry.pos;
253 next_state.vel_x = static_cast<f32>(next_state.delta.x) / time_difference;
254 next_state.vel_y = static_cast<f32>(next_state.delta.y) / time_difference;
255 last_pan_time_difference = time_difference;
256
257 // Promote to pinch type
258 if (std::abs(gesture.average_distance - last_gesture_props.average_distance) >
259 pinch_threshold) {
260 type = GestureType::Pinch;
261 next_state.scale = gesture.average_distance / last_gesture_props.average_distance;
262 }
263
264 const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) /
265 (1 + (gesture.angle * last_gesture_props.angle)));
266 // Promote to rotate type
267 if (std::abs(angle_between_two_lines) > angle_threshold) {
268 type = GestureType::Rotate;
269 next_state.scale = 0;
270 next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI;
271 }
272}
273
274void Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
275 GestureType& type, f32 time_difference) {
276 const auto& last_entry = GetLastGestureEntry();
277 next_state.vel_x =
278 static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference);
279 next_state.vel_y =
280 static_cast<f32>(last_entry.delta.y) / (last_pan_time_difference + time_difference);
281 const f32 curr_vel =
282 std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y));
283
284 // Set swipe event with parameters
285 if (curr_vel > swipe_threshold) {
286 SetSwipeEvent(gesture, last_gesture_props, type);
287 return;
288 }
289
290 // End panning without swipe
291 type = GestureType::Complete;
292 next_state.vel_x = 0;
293 next_state.vel_y = 0;
294 force_update = true;
295}
296
297void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
298 GestureType& type) {
299 const auto& last_entry = GetLastGestureEntry();
300
301 type = GestureType::Swipe;
302 gesture = last_gesture_props;
303 force_update = true;
304 next_state.delta = last_entry.delta;
305
306 if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) {
307 if (next_state.delta.x > 0) {
308 next_state.direction = GestureDirection::Right;
309 return;
310 }
311 next_state.direction = GestureDirection::Left;
312 return;
313 }
314 if (next_state.delta.y > 0) {
315 next_state.direction = GestureDirection::Down;
316 return;
317 }
318 next_state.direction = GestureDirection::Up;
319}
320
321const GestureState& Gesture::GetLastGestureEntry() const {
322 return shared_memory->gesture_lifo.ReadCurrentEntry().state;
323}
324
325GestureProperties Gesture::GetGestureProperties() {
326 GestureProperties gesture;
327 std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers;
328 const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),
329 [](const auto& finger) { return finger.pressed; });
330 gesture.active_points =
331 static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
332
333 for (size_t id = 0; id < gesture.active_points; ++id) {
334 const auto& [active_x, active_y] = active_fingers[id].position;
335 gesture.points[id] = {
336 .x = static_cast<s32>(active_x * Layout::ScreenUndocked::Width),
337 .y = static_cast<s32>(active_y * Layout::ScreenUndocked::Height),
338 };
339
340 // Hack: There is no touch in docked but games still allow it
341 if (Settings::IsDockedMode()) {
342 gesture.points[id] = {
343 .x = static_cast<s32>(active_x * Layout::ScreenDocked::Width),
344 .y = static_cast<s32>(active_y * Layout::ScreenDocked::Height),
345 };
346 }
347
348 gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points);
349 gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points);
350 }
351
352 for (size_t id = 0; id < gesture.active_points; ++id) {
353 const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) +
354 Square(gesture.mid_point.y - gesture.points[id].y));
355 gesture.average_distance += distance / static_cast<f32>(gesture.active_points);
356 }
357
358 gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y),
359 static_cast<f32>(gesture.mid_point.x - gesture.points[0].x));
360
361 gesture.detection_count = last_gesture.detection_count;
362
363 return gesture;
364}
365
366} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h
deleted file mode 100644
index 78da1552a..000000000
--- a/src/core/hle/service/hid/controllers/gesture.h
+++ /dev/null
@@ -1,87 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "common/common_types.h"
9#include "core/hle/service/hid/controllers/controller_base.h"
10#include "core/hle/service/hid/controllers/types/touch_types.h"
11
12namespace Core::HID {
13class EmulatedConsole;
14}
15
16namespace Service::HID {
17struct GestureSharedMemoryFormat;
18
19class Gesture final : public ControllerBase {
20public:
21 explicit Gesture(Core::HID::HIDCore& hid_core_);
22 ~Gesture() override;
23
24 // Called when the controller is initialized
25 void OnInit() override;
26
27 // When the controller is released
28 void OnRelease() override;
29
30 // When the controller is requesting an update for the shared memory
31 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
32
33private:
34 // Reads input from all available input engines
35 void ReadTouchInput();
36
37 // Returns true if gesture state needs to be updated
38 bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference);
39
40 // Updates the shared memory to the next state
41 void UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference);
42
43 // Initializes new gesture
44 void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes);
45
46 // Updates existing gesture state
47 void UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference);
48
49 // Terminates exiting gesture
50 void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props,
51 GestureType& type, GestureAttribute& attributes, f32 time_difference);
52
53 // Set current event to a tap event
54 void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
55 GestureType& type, GestureAttribute& attributes);
56
57 // Calculates and set the extra parameters related to a pan event
58 void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
59 GestureType& type, f32 time_difference);
60
61 // Terminates the pan event
62 void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
63 GestureType& type, f32 time_difference);
64
65 // Set current event to a swipe event
66 void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
67 GestureType& type);
68
69 // Retrieves the last gesture entry, as indicated by shared memory indices.
70 [[nodiscard]] const GestureState& GetLastGestureEntry() const;
71
72 // Returns the average distance, angle and middle point of the active fingers
73 GestureProperties GetGestureProperties();
74
75 GestureState next_state{};
76 GestureSharedMemoryFormat* shared_memory;
77 Core::HID::EmulatedConsole* console = nullptr;
78
79 std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{};
80 GestureProperties last_gesture{};
81 s64 last_update_timestamp{};
82 s64 last_tap_timestamp{};
83 f32 last_pan_time_difference{};
84 bool force_update{false};
85 bool enable_press_and_tap{false};
86};
87} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/home_button.cpp b/src/core/hle/service/hid/controllers/home_button.cpp
deleted file mode 100644
index 1397379f3..000000000
--- a/src/core/hle/service/hid/controllers/home_button.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core_timing.h"
5#include "core/hle/service/hid/controllers/applet_resource.h"
6#include "core/hle/service/hid/controllers/home_button.h"
7#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
8
9namespace Service::HID {
10
11HomeButton::HomeButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
12
13HomeButton::~HomeButton() = default;
14
15void HomeButton::OnInit() {}
16
17void HomeButton::OnRelease() {}
18
19void HomeButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
20 if (!smart_update) {
21 return;
22 }
23
24 std::scoped_lock shared_lock{*shared_mutex};
25 const u64 aruid = applet_resource->GetActiveAruid();
26 auto* data = applet_resource->GetAruidData(aruid);
27
28 if (data == nullptr || !data->flag.is_assigned) {
29 return;
30 }
31
32 auto& header = data->shared_memory_format->home_button.header;
33 header.timestamp = core_timing.GetGlobalTimeNs().count();
34 header.total_entry_count = 17;
35 header.entry_count = 0;
36 header.last_entry_index = 0;
37}
38
39} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/home_button.h b/src/core/hle/service/hid/controllers/home_button.h
deleted file mode 100644
index e91c2aa5d..000000000
--- a/src/core/hle/service/hid/controllers/home_button.h
+++ /dev/null
@@ -1,27 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/hid/controllers/controller_base.h"
7
8namespace Service::HID {
9
10class HomeButton final : public ControllerBase {
11public:
12 explicit HomeButton(Core::HID::HIDCore& hid_core_);
13 ~HomeButton() override;
14
15 // Called when the controller is initialized
16 void OnInit() override;
17
18 // When the controller is released
19 void OnRelease() override;
20
21 // When the controller is requesting an update for the shared memory
22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
23
24private:
25 bool smart_update{};
26};
27} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
deleted file mode 100644
index c069bcbb2..000000000
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/settings.h"
5#include "core/core_timing.h"
6#include "core/hid/emulated_devices.h"
7#include "core/hid/hid_core.h"
8#include "core/hle/service/hid/controllers/applet_resource.h"
9#include "core/hle/service/hid/controllers/keyboard.h"
10#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
11
12namespace Service::HID {
13
14Keyboard::Keyboard(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
15 emulated_devices = hid_core.GetEmulatedDevices();
16}
17
18Keyboard::~Keyboard() = default;
19
20void Keyboard::OnInit() {}
21
22void Keyboard::OnRelease() {}
23
24void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
25 std::scoped_lock shared_lock{*shared_mutex};
26 const u64 aruid = applet_resource->GetActiveAruid();
27 auto* data = applet_resource->GetAruidData(aruid);
28
29 if (data == nullptr || !data->flag.is_assigned) {
30 return;
31 }
32
33 KeyboardSharedMemoryFormat& shared_memory = data->shared_memory_format->keyboard;
34
35 if (!IsControllerActivated()) {
36 shared_memory.keyboard_lifo.buffer_count = 0;
37 shared_memory.keyboard_lifo.buffer_tail = 0;
38 return;
39 }
40
41 const auto& last_entry = shared_memory.keyboard_lifo.ReadCurrentEntry().state;
42 next_state.sampling_number = last_entry.sampling_number + 1;
43
44 if (Settings::values.keyboard_enabled) {
45 const auto& keyboard_state = emulated_devices->GetKeyboard();
46 const auto& keyboard_modifier_state = emulated_devices->GetKeyboardModifier();
47
48 next_state.key = keyboard_state;
49 next_state.modifier = keyboard_modifier_state;
50 next_state.attribute.is_connected.Assign(1);
51 }
52
53 shared_memory.keyboard_lifo.WriteNextEntry(next_state);
54}
55
56} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
deleted file mode 100644
index e8ca326c6..000000000
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ /dev/null
@@ -1,28 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/hid/controllers/controller_base.h"
7#include "core/hle/service/hid/controllers/types/keyboard_types.h"
8
9namespace Service::HID {
10class Keyboard final : public ControllerBase {
11public:
12 explicit Keyboard(Core::HID::HIDCore& hid_core_);
13 ~Keyboard() override;
14
15 // Called when the controller is initialized
16 void OnInit() override;
17
18 // When the controller is released
19 void OnRelease() override;
20
21 // When the controller is requesting an update for the shared memory
22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
23
24private:
25 KeyboardState next_state{};
26 Core::HID::EmulatedDevices* emulated_devices = nullptr;
27};
28} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
deleted file mode 100644
index 3a8d1751b..000000000
--- a/src/core/hle/service/hid/controllers/mouse.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core_timing.h"
5#include "core/frontend/emu_window.h"
6#include "core/hid/emulated_devices.h"
7#include "core/hid/hid_core.h"
8#include "core/hle/service/hid/controllers/applet_resource.h"
9#include "core/hle/service/hid/controllers/mouse.h"
10#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
11
12namespace Service::HID {
13
14Mouse::Mouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
15 emulated_devices = hid_core.GetEmulatedDevices();
16}
17
18Mouse::~Mouse() = default;
19
20void Mouse::OnInit() {}
21void Mouse::OnRelease() {}
22
23void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
24 std::scoped_lock shared_lock{*shared_mutex};
25 const u64 aruid = applet_resource->GetActiveAruid();
26 auto* data = applet_resource->GetAruidData(aruid);
27
28 if (data == nullptr || !data->flag.is_assigned) {
29 return;
30 }
31
32 MouseSharedMemoryFormat& shared_memory = data->shared_memory_format->mouse;
33
34 if (!IsControllerActivated()) {
35 shared_memory.mouse_lifo.buffer_count = 0;
36 shared_memory.mouse_lifo.buffer_tail = 0;
37 return;
38 }
39
40 next_state = {};
41
42 const auto& last_entry = shared_memory.mouse_lifo.ReadCurrentEntry().state;
43 next_state.sampling_number = last_entry.sampling_number + 1;
44
45 if (Settings::values.mouse_enabled) {
46 const auto& mouse_button_state = emulated_devices->GetMouseButtons();
47 const auto& mouse_position_state = emulated_devices->GetMousePosition();
48 const auto& mouse_wheel_state = emulated_devices->GetMouseWheel();
49 next_state.attribute.is_connected.Assign(1);
50 next_state.x = static_cast<s32>(mouse_position_state.x * Layout::ScreenUndocked::Width);
51 next_state.y = static_cast<s32>(mouse_position_state.y * Layout::ScreenUndocked::Height);
52 next_state.delta_x = next_state.x - last_entry.x;
53 next_state.delta_y = next_state.y - last_entry.y;
54 next_state.delta_wheel_x = mouse_wheel_state.x - last_mouse_wheel_state.x;
55 next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y;
56
57 last_mouse_wheel_state = mouse_wheel_state;
58 next_state.button = mouse_button_state;
59 }
60
61 shared_memory.mouse_lifo.WriteNextEntry(next_state);
62}
63
64} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
deleted file mode 100644
index cefad956c..000000000
--- a/src/core/hle/service/hid/controllers/mouse.h
+++ /dev/null
@@ -1,34 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/hid/controllers/controller_base.h"
7
8namespace Core::HID {
9class EmulatedDevices;
10struct MouseState;
11struct AnalogStickState;
12} // namespace Core::HID
13
14namespace Service::HID {
15class Mouse final : public ControllerBase {
16public:
17 explicit Mouse(Core::HID::HIDCore& hid_core_);
18 ~Mouse() override;
19
20 // Called when the controller is initialized
21 void OnInit() override;
22
23 // When the controller is released
24 void OnRelease() override;
25
26 // When the controller is requesting an update for the shared memory
27 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
28
29private:
30 Core::HID::MouseState next_state{};
31 Core::HID::AnalogStickState last_mouse_wheel_state{};
32 Core::HID::EmulatedDevices* emulated_devices = nullptr;
33};
34} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
deleted file mode 100644
index 17cd0d7a0..000000000
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ /dev/null
@@ -1,1342 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <array>
6#include <chrono>
7#include <cstring>
8
9#include "common/assert.h"
10#include "common/bit_field.h"
11#include "common/common_types.h"
12#include "common/logging/log.h"
13#include "common/settings.h"
14#include "core/core_timing.h"
15#include "core/hid/emulated_controller.h"
16#include "core/hid/hid_core.h"
17#include "core/hle/kernel/k_event.h"
18#include "core/hle/kernel/k_readable_event.h"
19#include "core/hle/service/hid/controllers/applet_resource.h"
20#include "core/hle/service/hid/controllers/npad.h"
21#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
22#include "core/hle/service/hid/errors.h"
23#include "core/hle/service/hid/hid_util.h"
24#include "core/hle/service/kernel_helpers.h"
25
26namespace Service::HID {
27
28NPad::NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_)
29 : hid_core{hid_core_}, service_context{service_context_}, npad_resource{service_context} {
30 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) {
31 for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) {
32 auto& controller = controller_data[aruid_index][i];
33 controller.device = hid_core.GetEmulatedControllerByIndex(i);
34 controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value =
35 Core::HID::DEFAULT_VIBRATION_VALUE;
36 controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex]
37 .latest_vibration_value = Core::HID::DEFAULT_VIBRATION_VALUE;
38 Core::HID::ControllerUpdateCallback engine_callback{
39 .on_change =
40 [this, i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); },
41 .is_npad_service = true,
42 };
43 controller.callback_key = controller.device->SetCallback(engine_callback);
44 }
45 }
46}
47
48NPad::~NPad() {
49 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) {
50 for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) {
51 auto& controller = controller_data[aruid_index][i];
52 controller.device->DeleteCallback(controller.callback_key);
53 }
54 }
55}
56
57Result NPad::Activate() {
58 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
59 return ResultNpadResourceOverflow;
60 }
61
62 if (ref_counter == 0) {
63 std::scoped_lock lock{mutex};
64
65 // TODO: Activate handlers and AbstractedPad
66 }
67
68 ref_counter++;
69 return ResultSuccess;
70}
71
72Result NPad::Activate(u64 aruid) {
73 std::scoped_lock lock{mutex};
74 std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex};
75
76 auto* data = applet_resource_holder.applet_resource->GetAruidData(aruid);
77 const auto aruid_index = applet_resource_holder.applet_resource->GetIndexFromAruid(aruid);
78
79 if (data == nullptr || !data->flag.is_assigned) {
80 return ResultSuccess;
81 }
82
83 for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) {
84 auto& controller = controller_data[aruid_index][i];
85 controller.shared_memory = &data->shared_memory_format->npad.npad_entry[i].internal_state;
86 }
87
88 // Prefill controller buffers
89 for (auto& controller : controller_data[aruid_index]) {
90 auto* npad = controller.shared_memory;
91 npad->fullkey_color = {
92 .attribute = ColorAttribute::NoController,
93 .fullkey = {},
94 };
95 npad->joycon_color = {
96 .attribute = ColorAttribute::NoController,
97 .left = {},
98 .right = {},
99 };
100 // HW seems to initialize the first 19 entries
101 for (std::size_t i = 0; i < 19; ++i) {
102 WriteEmptyEntry(npad);
103 }
104 }
105
106 return ResultSuccess;
107}
108
109Result NPad::ActivateNpadResource() {
110 return npad_resource.Activate();
111}
112
113Result NPad::ActivateNpadResource(u64 aruid) {
114 return npad_resource.Activate(aruid);
115}
116
117void NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx) {
118 if (type == Core::HID::ControllerTriggerType::All) {
119 ControllerUpdate(Core::HID::ControllerTriggerType::Connected, controller_idx);
120 ControllerUpdate(Core::HID::ControllerTriggerType::Battery, controller_idx);
121 return;
122 }
123
124 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
125 if (controller_idx >= controller_data[aruid_index].size()) {
126 return;
127 }
128
129 auto* data = applet_resource_holder.applet_resource->GetAruidDataByIndex(aruid_index);
130
131 if (!data->flag.is_assigned) {
132 continue;
133 }
134
135 auto& controller = controller_data[aruid_index][controller_idx];
136 const auto is_connected = controller.device->IsConnected();
137 const auto npad_type = controller.device->GetNpadStyleIndex();
138 const auto npad_id = controller.device->GetNpadIdType();
139 switch (type) {
140 case Core::HID::ControllerTriggerType::Connected:
141 case Core::HID::ControllerTriggerType::Disconnected:
142 if (is_connected == controller.is_connected) {
143 return;
144 }
145 UpdateControllerAt(data->aruid, npad_type, npad_id, is_connected);
146 break;
147 case Core::HID::ControllerTriggerType::Battery: {
148 if (!controller.device->IsConnected()) {
149 return;
150 }
151 auto* shared_memory = controller.shared_memory;
152 const auto& battery_level = controller.device->GetBattery();
153 shared_memory->battery_level_dual = battery_level.dual.battery_level;
154 shared_memory->battery_level_left = battery_level.left.battery_level;
155 shared_memory->battery_level_right = battery_level.right.battery_level;
156 break;
157 }
158 default:
159 break;
160 }
161 }
162}
163
164void NPad::InitNewlyAddedController(u64 aruid, Core::HID::NpadIdType npad_id) {
165 auto& controller = GetControllerFromNpadIdType(aruid, npad_id);
166 if (!npad_resource.IsControllerSupported(aruid, controller.device->GetNpadStyleIndex())) {
167 return;
168 }
169 LOG_DEBUG(Service_HID, "Npad connected {}", npad_id);
170 const auto controller_type = controller.device->GetNpadStyleIndex();
171 const auto& body_colors = controller.device->GetColors();
172 const auto& battery_level = controller.device->GetBattery();
173 auto* shared_memory = controller.shared_memory;
174 if (controller_type == Core::HID::NpadStyleIndex::None) {
175 npad_resource.SignalStyleSetUpdateEvent(aruid, npad_id);
176 return;
177 }
178
179 // Reset memory values
180 shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None;
181 shared_memory->device_type.raw = 0;
182 shared_memory->system_properties.raw = 0;
183 shared_memory->joycon_color.attribute = ColorAttribute::NoController;
184 shared_memory->joycon_color.attribute = ColorAttribute::NoController;
185 shared_memory->fullkey_color = {};
186 shared_memory->joycon_color.left = {};
187 shared_memory->joycon_color.right = {};
188 shared_memory->battery_level_dual = {};
189 shared_memory->battery_level_left = {};
190 shared_memory->battery_level_right = {};
191
192 switch (controller_type) {
193 case Core::HID::NpadStyleIndex::None:
194 ASSERT(false);
195 break;
196 case Core::HID::NpadStyleIndex::ProController:
197 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
198 shared_memory->fullkey_color.fullkey = body_colors.fullkey;
199 shared_memory->battery_level_dual = battery_level.dual.battery_level;
200 shared_memory->style_tag.fullkey.Assign(1);
201 shared_memory->device_type.fullkey.Assign(1);
202 shared_memory->system_properties.is_vertical.Assign(1);
203 shared_memory->system_properties.use_plus.Assign(1);
204 shared_memory->system_properties.use_minus.Assign(1);
205 shared_memory->system_properties.is_charging_joy_dual.Assign(
206 battery_level.dual.is_charging);
207 shared_memory->applet_footer_type = AppletFooterUiType::SwitchProController;
208 shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1);
209 break;
210 case Core::HID::NpadStyleIndex::Handheld:
211 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
212 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
213 shared_memory->fullkey_color.fullkey = body_colors.fullkey;
214 shared_memory->joycon_color.left = body_colors.left;
215 shared_memory->joycon_color.right = body_colors.right;
216 shared_memory->style_tag.handheld.Assign(1);
217 shared_memory->device_type.handheld_left.Assign(1);
218 shared_memory->device_type.handheld_right.Assign(1);
219 shared_memory->system_properties.is_vertical.Assign(1);
220 shared_memory->system_properties.use_plus.Assign(1);
221 shared_memory->system_properties.use_minus.Assign(1);
222 shared_memory->system_properties.use_directional_buttons.Assign(1);
223 shared_memory->system_properties.is_charging_joy_dual.Assign(
224 battery_level.left.is_charging);
225 shared_memory->system_properties.is_charging_joy_left.Assign(
226 battery_level.left.is_charging);
227 shared_memory->system_properties.is_charging_joy_right.Assign(
228 battery_level.right.is_charging);
229 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
230 shared_memory->applet_footer_type = AppletFooterUiType::HandheldJoyConLeftJoyConRight;
231 shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1);
232 break;
233 case Core::HID::NpadStyleIndex::JoyconDual:
234 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
235 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
236 shared_memory->style_tag.joycon_dual.Assign(1);
237 if (controller.is_dual_left_connected) {
238 shared_memory->joycon_color.left = body_colors.left;
239 shared_memory->battery_level_left = battery_level.left.battery_level;
240 shared_memory->device_type.joycon_left.Assign(1);
241 shared_memory->system_properties.use_minus.Assign(1);
242 shared_memory->system_properties.is_charging_joy_left.Assign(
243 battery_level.left.is_charging);
244 shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1);
245 }
246 if (controller.is_dual_right_connected) {
247 shared_memory->joycon_color.right = body_colors.right;
248 shared_memory->battery_level_right = battery_level.right.battery_level;
249 shared_memory->device_type.joycon_right.Assign(1);
250 shared_memory->system_properties.use_plus.Assign(1);
251 shared_memory->system_properties.is_charging_joy_right.Assign(
252 battery_level.right.is_charging);
253 shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1);
254 }
255 shared_memory->system_properties.use_directional_buttons.Assign(1);
256 shared_memory->system_properties.is_vertical.Assign(1);
257 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
258
259 if (controller.is_dual_left_connected && controller.is_dual_right_connected) {
260 shared_memory->applet_footer_type = AppletFooterUiType::JoyDual;
261 shared_memory->fullkey_color.fullkey = body_colors.left;
262 shared_memory->battery_level_dual = battery_level.left.battery_level;
263 shared_memory->system_properties.is_charging_joy_dual.Assign(
264 battery_level.left.is_charging);
265 } else if (controller.is_dual_left_connected) {
266 shared_memory->applet_footer_type = AppletFooterUiType::JoyDualLeftOnly;
267 shared_memory->fullkey_color.fullkey = body_colors.left;
268 shared_memory->battery_level_dual = battery_level.left.battery_level;
269 shared_memory->system_properties.is_charging_joy_dual.Assign(
270 battery_level.left.is_charging);
271 } else {
272 shared_memory->applet_footer_type = AppletFooterUiType::JoyDualRightOnly;
273 shared_memory->fullkey_color.fullkey = body_colors.right;
274 shared_memory->battery_level_dual = battery_level.right.battery_level;
275 shared_memory->system_properties.is_charging_joy_dual.Assign(
276 battery_level.right.is_charging);
277 }
278 break;
279 case Core::HID::NpadStyleIndex::JoyconLeft:
280 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
281 shared_memory->fullkey_color.fullkey = body_colors.left;
282 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
283 shared_memory->joycon_color.left = body_colors.left;
284 shared_memory->battery_level_dual = battery_level.left.battery_level;
285 shared_memory->style_tag.joycon_left.Assign(1);
286 shared_memory->device_type.joycon_left.Assign(1);
287 shared_memory->system_properties.is_horizontal.Assign(1);
288 shared_memory->system_properties.use_minus.Assign(1);
289 shared_memory->system_properties.is_charging_joy_left.Assign(
290 battery_level.left.is_charging);
291 shared_memory->applet_footer_type = AppletFooterUiType::JoyLeftHorizontal;
292 shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1);
293 break;
294 case Core::HID::NpadStyleIndex::JoyconRight:
295 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
296 shared_memory->fullkey_color.fullkey = body_colors.right;
297 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
298 shared_memory->joycon_color.right = body_colors.right;
299 shared_memory->battery_level_right = battery_level.right.battery_level;
300 shared_memory->style_tag.joycon_right.Assign(1);
301 shared_memory->device_type.joycon_right.Assign(1);
302 shared_memory->system_properties.is_horizontal.Assign(1);
303 shared_memory->system_properties.use_plus.Assign(1);
304 shared_memory->system_properties.is_charging_joy_right.Assign(
305 battery_level.right.is_charging);
306 shared_memory->applet_footer_type = AppletFooterUiType::JoyRightHorizontal;
307 shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1);
308 break;
309 case Core::HID::NpadStyleIndex::GameCube:
310 shared_memory->style_tag.gamecube.Assign(1);
311 shared_memory->device_type.fullkey.Assign(1);
312 shared_memory->system_properties.is_vertical.Assign(1);
313 shared_memory->system_properties.use_plus.Assign(1);
314 break;
315 case Core::HID::NpadStyleIndex::Pokeball:
316 shared_memory->style_tag.palma.Assign(1);
317 shared_memory->device_type.palma.Assign(1);
318 shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1);
319 break;
320 case Core::HID::NpadStyleIndex::NES:
321 shared_memory->style_tag.lark.Assign(1);
322 shared_memory->device_type.fullkey.Assign(1);
323 break;
324 case Core::HID::NpadStyleIndex::SNES:
325 shared_memory->style_tag.lucia.Assign(1);
326 shared_memory->device_type.fullkey.Assign(1);
327 shared_memory->applet_footer_type = AppletFooterUiType::Lucia;
328 break;
329 case Core::HID::NpadStyleIndex::N64:
330 shared_memory->style_tag.lagoon.Assign(1);
331 shared_memory->device_type.fullkey.Assign(1);
332 shared_memory->applet_footer_type = AppletFooterUiType::Lagon;
333 break;
334 case Core::HID::NpadStyleIndex::SegaGenesis:
335 shared_memory->style_tag.lager.Assign(1);
336 shared_memory->device_type.fullkey.Assign(1);
337 break;
338 default:
339 break;
340 }
341
342 controller.is_connected = true;
343 controller.device->Connect();
344 controller.device->SetLedPattern();
345 if (controller_type == Core::HID::NpadStyleIndex::JoyconDual) {
346 if (controller.is_dual_left_connected) {
347 controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::LeftIndex,
348 Common::Input::PollingMode::Active);
349 }
350 if (controller.is_dual_right_connected) {
351 controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
352 Common::Input::PollingMode::Active);
353 }
354 } else {
355 controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::AllDevices,
356 Common::Input::PollingMode::Active);
357 }
358
359 npad_resource.SignalStyleSetUpdateEvent(aruid, npad_id);
360 WriteEmptyEntry(controller.shared_memory);
361 hid_core.SetLastActiveController(npad_id);
362}
363
364void NPad::WriteEmptyEntry(NpadInternalState* npad) {
365 NPadGenericState dummy_pad_state{};
366 NpadGcTriggerState dummy_gc_state{};
367 dummy_pad_state.sampling_number = npad->fullkey_lifo.ReadCurrentEntry().sampling_number + 1;
368 npad->fullkey_lifo.WriteNextEntry(dummy_pad_state);
369 dummy_pad_state.sampling_number = npad->handheld_lifo.ReadCurrentEntry().sampling_number + 1;
370 npad->handheld_lifo.WriteNextEntry(dummy_pad_state);
371 dummy_pad_state.sampling_number = npad->joy_dual_lifo.ReadCurrentEntry().sampling_number + 1;
372 npad->joy_dual_lifo.WriteNextEntry(dummy_pad_state);
373 dummy_pad_state.sampling_number = npad->joy_left_lifo.ReadCurrentEntry().sampling_number + 1;
374 npad->joy_left_lifo.WriteNextEntry(dummy_pad_state);
375 dummy_pad_state.sampling_number = npad->joy_right_lifo.ReadCurrentEntry().sampling_number + 1;
376 npad->joy_right_lifo.WriteNextEntry(dummy_pad_state);
377 dummy_pad_state.sampling_number = npad->palma_lifo.ReadCurrentEntry().sampling_number + 1;
378 npad->palma_lifo.WriteNextEntry(dummy_pad_state);
379 dummy_pad_state.sampling_number = npad->system_ext_lifo.ReadCurrentEntry().sampling_number + 1;
380 npad->system_ext_lifo.WriteNextEntry(dummy_pad_state);
381 dummy_gc_state.sampling_number = npad->gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1;
382 npad->gc_trigger_lifo.WriteNextEntry(dummy_gc_state);
383}
384
385void NPad::RequestPadStateUpdate(u64 aruid, Core::HID::NpadIdType npad_id) {
386 std::scoped_lock lock{*applet_resource_holder.shared_mutex};
387 auto& controller = GetControllerFromNpadIdType(aruid, npad_id);
388 const auto controller_type = controller.device->GetNpadStyleIndex();
389
390 if (!controller.device->IsConnected() && controller.is_connected) {
391 DisconnectNpad(aruid, npad_id);
392 return;
393 }
394 if (!controller.device->IsConnected()) {
395 return;
396 }
397 if (controller.device->IsConnected() && !controller.is_connected) {
398 InitNewlyAddedController(aruid, npad_id);
399 }
400
401 // This function is unique to yuzu for the turbo buttons and motion to work properly
402 controller.device->StatusUpdate();
403
404 auto& pad_entry = controller.npad_pad_state;
405 auto& trigger_entry = controller.npad_trigger_state;
406 const auto button_state = controller.device->GetNpadButtons();
407 const auto stick_state = controller.device->GetSticks();
408
409 using btn = Core::HID::NpadButton;
410 pad_entry.npad_buttons.raw = btn::None;
411 if (controller_type != Core::HID::NpadStyleIndex::JoyconLeft) {
412 constexpr btn right_button_mask = btn::A | btn::B | btn::X | btn::Y | btn::StickR | btn::R |
413 btn::ZR | btn::Plus | btn::StickRLeft | btn::StickRUp |
414 btn::StickRRight | btn::StickRDown;
415 pad_entry.npad_buttons.raw = button_state.raw & right_button_mask;
416 pad_entry.r_stick = stick_state.right;
417 }
418
419 if (controller_type != Core::HID::NpadStyleIndex::JoyconRight) {
420 constexpr btn left_button_mask =
421 btn::Left | btn::Up | btn::Right | btn::Down | btn::StickL | btn::L | btn::ZL |
422 btn::Minus | btn::StickLLeft | btn::StickLUp | btn::StickLRight | btn::StickLDown;
423 pad_entry.npad_buttons.raw |= button_state.raw & left_button_mask;
424 pad_entry.l_stick = stick_state.left;
425 }
426
427 if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft ||
428 controller_type == Core::HID::NpadStyleIndex::JoyconDual) {
429 pad_entry.npad_buttons.left_sl.Assign(button_state.left_sl);
430 pad_entry.npad_buttons.left_sr.Assign(button_state.left_sr);
431 }
432
433 if (controller_type == Core::HID::NpadStyleIndex::JoyconRight ||
434 controller_type == Core::HID::NpadStyleIndex::JoyconDual) {
435 pad_entry.npad_buttons.right_sl.Assign(button_state.right_sl);
436 pad_entry.npad_buttons.right_sr.Assign(button_state.right_sr);
437 }
438
439 if (controller_type == Core::HID::NpadStyleIndex::GameCube) {
440 const auto& trigger_state = controller.device->GetTriggers();
441 trigger_entry.l_analog = trigger_state.left;
442 trigger_entry.r_analog = trigger_state.right;
443 pad_entry.npad_buttons.zl.Assign(false);
444 pad_entry.npad_buttons.zr.Assign(button_state.r);
445 pad_entry.npad_buttons.l.Assign(button_state.zl);
446 pad_entry.npad_buttons.r.Assign(button_state.zr);
447 }
448
449 if (pad_entry.npad_buttons.raw != Core::HID::NpadButton::None) {
450 hid_core.SetLastActiveController(npad_id);
451 }
452}
453
454void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
455 if (ref_counter == 0) {
456 return;
457 }
458
459 std::scoped_lock lock{*applet_resource_holder.shared_mutex};
460 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) {
461 const auto* data = applet_resource_holder.applet_resource->GetAruidDataByIndex(aruid_index);
462 const auto aruid = data->aruid;
463
464 if (!data->flag.is_assigned) {
465 continue;
466 }
467
468 for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) {
469 auto& controller = controller_data[aruid_index][i];
470 controller.shared_memory =
471 &data->shared_memory_format->npad.npad_entry[i].internal_state;
472 auto* npad = controller.shared_memory;
473
474 const auto& controller_type = controller.device->GetNpadStyleIndex();
475
476 if (controller_type == Core::HID::NpadStyleIndex::None ||
477 !controller.device->IsConnected()) {
478 continue;
479 }
480
481 RequestPadStateUpdate(aruid, controller.device->GetNpadIdType());
482 auto& pad_state = controller.npad_pad_state;
483 auto& libnx_state = controller.npad_libnx_state;
484 auto& trigger_state = controller.npad_trigger_state;
485
486 // LibNX exclusively uses this section, so we always update it since LibNX doesn't
487 // activate any controllers.
488 libnx_state.connection_status.raw = 0;
489 libnx_state.connection_status.is_connected.Assign(1);
490 switch (controller_type) {
491 case Core::HID::NpadStyleIndex::None:
492 ASSERT(false);
493 break;
494 case Core::HID::NpadStyleIndex::ProController:
495 case Core::HID::NpadStyleIndex::NES:
496 case Core::HID::NpadStyleIndex::SNES:
497 case Core::HID::NpadStyleIndex::N64:
498 case Core::HID::NpadStyleIndex::SegaGenesis:
499 pad_state.connection_status.raw = 0;
500 pad_state.connection_status.is_connected.Assign(1);
501 pad_state.connection_status.is_wired.Assign(1);
502
503 libnx_state.connection_status.is_wired.Assign(1);
504 pad_state.sampling_number =
505 npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
506 npad->fullkey_lifo.WriteNextEntry(pad_state);
507 break;
508 case Core::HID::NpadStyleIndex::Handheld:
509 pad_state.connection_status.raw = 0;
510 pad_state.connection_status.is_connected.Assign(1);
511 pad_state.connection_status.is_wired.Assign(1);
512 pad_state.connection_status.is_left_connected.Assign(1);
513 pad_state.connection_status.is_right_connected.Assign(1);
514 pad_state.connection_status.is_left_wired.Assign(1);
515 pad_state.connection_status.is_right_wired.Assign(1);
516
517 libnx_state.connection_status.is_wired.Assign(1);
518 libnx_state.connection_status.is_left_connected.Assign(1);
519 libnx_state.connection_status.is_right_connected.Assign(1);
520 libnx_state.connection_status.is_left_wired.Assign(1);
521 libnx_state.connection_status.is_right_wired.Assign(1);
522 pad_state.sampling_number =
523 npad->handheld_lifo.ReadCurrentEntry().state.sampling_number + 1;
524 npad->handheld_lifo.WriteNextEntry(pad_state);
525 break;
526 case Core::HID::NpadStyleIndex::JoyconDual:
527 pad_state.connection_status.raw = 0;
528 pad_state.connection_status.is_connected.Assign(1);
529 if (controller.is_dual_left_connected) {
530 pad_state.connection_status.is_left_connected.Assign(1);
531 libnx_state.connection_status.is_left_connected.Assign(1);
532 }
533 if (controller.is_dual_right_connected) {
534 pad_state.connection_status.is_right_connected.Assign(1);
535 libnx_state.connection_status.is_right_connected.Assign(1);
536 }
537
538 pad_state.sampling_number =
539 npad->joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1;
540 npad->joy_dual_lifo.WriteNextEntry(pad_state);
541 break;
542 case Core::HID::NpadStyleIndex::JoyconLeft:
543 pad_state.connection_status.raw = 0;
544 pad_state.connection_status.is_connected.Assign(1);
545 pad_state.connection_status.is_left_connected.Assign(1);
546
547 libnx_state.connection_status.is_left_connected.Assign(1);
548 pad_state.sampling_number =
549 npad->joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
550 npad->joy_left_lifo.WriteNextEntry(pad_state);
551 break;
552 case Core::HID::NpadStyleIndex::JoyconRight:
553 pad_state.connection_status.raw = 0;
554 pad_state.connection_status.is_connected.Assign(1);
555 pad_state.connection_status.is_right_connected.Assign(1);
556
557 libnx_state.connection_status.is_right_connected.Assign(1);
558 pad_state.sampling_number =
559 npad->joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
560 npad->joy_right_lifo.WriteNextEntry(pad_state);
561 break;
562 case Core::HID::NpadStyleIndex::GameCube:
563 pad_state.connection_status.raw = 0;
564 pad_state.connection_status.is_connected.Assign(1);
565 pad_state.connection_status.is_wired.Assign(1);
566
567 libnx_state.connection_status.is_wired.Assign(1);
568 pad_state.sampling_number =
569 npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
570 trigger_state.sampling_number =
571 npad->gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1;
572 npad->fullkey_lifo.WriteNextEntry(pad_state);
573 npad->gc_trigger_lifo.WriteNextEntry(trigger_state);
574 break;
575 case Core::HID::NpadStyleIndex::Pokeball:
576 pad_state.connection_status.raw = 0;
577 pad_state.connection_status.is_connected.Assign(1);
578 pad_state.sampling_number =
579 npad->palma_lifo.ReadCurrentEntry().state.sampling_number + 1;
580 npad->palma_lifo.WriteNextEntry(pad_state);
581 break;
582 default:
583 break;
584 }
585
586 libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw;
587 libnx_state.l_stick = pad_state.l_stick;
588 libnx_state.r_stick = pad_state.r_stick;
589 npad->system_ext_lifo.WriteNextEntry(pad_state);
590
591 press_state |= static_cast<u64>(pad_state.npad_buttons.raw);
592 }
593 }
594}
595
596Result NPad::SetSupportedNpadStyleSet(u64 aruid, Core::HID::NpadStyleSet supported_style_set) {
597 std::scoped_lock lock{mutex};
598 hid_core.SetSupportedStyleTag({supported_style_set});
599 const Result result = npad_resource.SetSupportedNpadStyleSet(aruid, supported_style_set);
600 if (result.IsSuccess()) {
601 OnUpdate({});
602 }
603 return result;
604}
605
606Result NPad::GetSupportedNpadStyleSet(u64 aruid,
607 Core::HID::NpadStyleSet& out_supported_style_set) const {
608 std::scoped_lock lock{mutex};
609 const Result result = npad_resource.GetSupportedNpadStyleSet(out_supported_style_set, aruid);
610
611 if (result == ResultUndefinedStyleset) {
612 out_supported_style_set = Core::HID::NpadStyleSet::None;
613 return ResultSuccess;
614 }
615
616 return result;
617}
618
619Result NPad::GetMaskedSupportedNpadStyleSet(
620 u64 aruid, Core::HID::NpadStyleSet& out_supported_style_set) const {
621 std::scoped_lock lock{mutex};
622 const Result result =
623 npad_resource.GetMaskedSupportedNpadStyleSet(out_supported_style_set, aruid);
624
625 if (result == ResultUndefinedStyleset) {
626 out_supported_style_set = Core::HID::NpadStyleSet::None;
627 return ResultSuccess;
628 }
629
630 return result;
631}
632
633Result NPad::SetSupportedNpadIdType(u64 aruid,
634 std::span<const Core::HID::NpadIdType> supported_npad_list) {
635 std::scoped_lock lock{mutex};
636 if (supported_npad_list.size() > MaxSupportedNpadIdTypes) {
637 return ResultInvalidArraySize;
638 }
639
640 Result result = npad_resource.SetSupportedNpadIdType(aruid, supported_npad_list);
641
642 if (result.IsSuccess()) {
643 OnUpdate({});
644 }
645
646 return result;
647}
648
649Result NPad::SetNpadJoyHoldType(u64 aruid, NpadJoyHoldType hold_type) {
650 std::scoped_lock lock{mutex};
651 return npad_resource.SetNpadJoyHoldType(aruid, hold_type);
652}
653
654Result NPad::GetNpadJoyHoldType(u64 aruid, NpadJoyHoldType& out_hold_type) const {
655 std::scoped_lock lock{mutex};
656 return npad_resource.GetNpadJoyHoldType(out_hold_type, aruid);
657}
658
659Result NPad::SetNpadHandheldActivationMode(u64 aruid, NpadHandheldActivationMode mode) {
660 std::scoped_lock lock{mutex};
661 Result result = npad_resource.SetNpadHandheldActivationMode(aruid, mode);
662 if (result.IsSuccess()) {
663 OnUpdate({});
664 }
665 return result;
666}
667
668Result NPad::GetNpadHandheldActivationMode(u64 aruid, NpadHandheldActivationMode& out_mode) const {
669 std::scoped_lock lock{mutex};
670 return npad_resource.GetNpadHandheldActivationMode(out_mode, aruid);
671}
672
673bool NPad::SetNpadMode(u64 aruid, Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id,
674 NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode) {
675 if (!IsNpadIdValid(npad_id)) {
676 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
677 return false;
678 }
679
680 auto& controller = GetControllerFromNpadIdType(aruid, npad_id);
681 if (controller.shared_memory->assignment_mode != assignment_mode) {
682 controller.shared_memory->assignment_mode = assignment_mode;
683 }
684
685 if (!controller.device->IsConnected()) {
686 return false;
687 }
688
689 if (assignment_mode == NpadJoyAssignmentMode::Dual) {
690 if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft) {
691 DisconnectNpad(aruid, npad_id);
692 controller.is_dual_left_connected = true;
693 controller.is_dual_right_connected = false;
694 UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconDual, npad_id, true);
695 return false;
696 }
697 if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) {
698 DisconnectNpad(aruid, npad_id);
699 controller.is_dual_left_connected = false;
700 controller.is_dual_right_connected = true;
701 UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconDual, npad_id, true);
702 return false;
703 }
704 return false;
705 }
706
707 // This is for NpadJoyAssignmentMode::Single
708
709 // Only JoyconDual get affected by this function
710 if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) {
711 return false;
712 }
713
714 if (controller.is_dual_left_connected && !controller.is_dual_right_connected) {
715 DisconnectNpad(aruid, npad_id);
716 UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true);
717 return false;
718 }
719 if (!controller.is_dual_left_connected && controller.is_dual_right_connected) {
720 DisconnectNpad(aruid, npad_id);
721 UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconRight, npad_id, true);
722 return false;
723 }
724
725 // We have two controllers connected to the same npad_id we need to split them
726 new_npad_id = hid_core.GetFirstDisconnectedNpadId();
727 auto& controller_2 = GetControllerFromNpadIdType(aruid, new_npad_id);
728 DisconnectNpad(aruid, npad_id);
729 if (npad_device_type == NpadJoyDeviceType::Left) {
730 UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true);
731 controller_2.is_dual_left_connected = false;
732 controller_2.is_dual_right_connected = true;
733 UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconDual, new_npad_id, true);
734 } else {
735 UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconRight, npad_id, true);
736 controller_2.is_dual_left_connected = true;
737 controller_2.is_dual_right_connected = false;
738 UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconDual, new_npad_id, true);
739 }
740 return true;
741}
742
743bool NPad::VibrateControllerAtIndex(u64 aruid, Core::HID::NpadIdType npad_id,
744 std::size_t device_index,
745 const Core::HID::VibrationValue& vibration_value) {
746 auto& controller = GetControllerFromNpadIdType(aruid, npad_id);
747 if (!controller.device->IsConnected()) {
748 return false;
749 }
750
751 if (!controller.device->IsVibrationEnabled(device_index)) {
752 if (controller.vibration[device_index].latest_vibration_value.low_amplitude != 0.0f ||
753 controller.vibration[device_index].latest_vibration_value.high_amplitude != 0.0f) {
754 // Send an empty vibration to stop any vibrations.
755 Core::HID::VibrationValue vibration{0.0f, 160.0f, 0.0f, 320.0f};
756 controller.device->SetVibration(device_index, vibration);
757 // Then reset the vibration value to its default value.
758 controller.vibration[device_index].latest_vibration_value =
759 Core::HID::DEFAULT_VIBRATION_VALUE;
760 }
761
762 return false;
763 }
764
765 if (!Settings::values.enable_accurate_vibrations.GetValue()) {
766 using std::chrono::duration_cast;
767 using std::chrono::milliseconds;
768 using std::chrono::steady_clock;
769
770 const auto now = steady_clock::now();
771
772 // Filter out non-zero vibrations that are within 15ms of each other.
773 if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) &&
774 duration_cast<milliseconds>(
775 now - controller.vibration[device_index].last_vibration_timepoint) <
776 milliseconds(15)) {
777 return false;
778 }
779
780 controller.vibration[device_index].last_vibration_timepoint = now;
781 }
782
783 Core::HID::VibrationValue vibration{
784 vibration_value.low_amplitude, vibration_value.low_frequency,
785 vibration_value.high_amplitude, vibration_value.high_frequency};
786 return controller.device->SetVibration(device_index, vibration);
787}
788
789void NPad::VibrateController(u64 aruid,
790 const Core::HID::VibrationDeviceHandle& vibration_device_handle,
791 const Core::HID::VibrationValue& vibration_value) {
792 if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
793 return;
794 }
795
796 if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
797 return;
798 }
799
800 auto& controller = GetControllerFromHandle(aruid, vibration_device_handle);
801 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
802
803 if (!controller.vibration[device_index].device_mounted || !controller.device->IsConnected()) {
804 return;
805 }
806
807 if (vibration_device_handle.device_index == Core::HID::DeviceIndex::None) {
808 ASSERT_MSG(false, "DeviceIndex should never be None!");
809 return;
810 }
811
812 // Some games try to send mismatched parameters in the device handle, block these.
813 if ((controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft &&
814 (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconRight ||
815 vibration_device_handle.device_index == Core::HID::DeviceIndex::Right)) ||
816 (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight &&
817 (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconLeft ||
818 vibration_device_handle.device_index == Core::HID::DeviceIndex::Left))) {
819 return;
820 }
821
822 // Filter out vibrations with equivalent values to reduce unnecessary state changes.
823 if (vibration_value.low_amplitude ==
824 controller.vibration[device_index].latest_vibration_value.low_amplitude &&
825 vibration_value.high_amplitude ==
826 controller.vibration[device_index].latest_vibration_value.high_amplitude) {
827 return;
828 }
829
830 if (VibrateControllerAtIndex(aruid, controller.device->GetNpadIdType(), device_index,
831 vibration_value)) {
832 controller.vibration[device_index].latest_vibration_value = vibration_value;
833 }
834}
835
836void NPad::VibrateControllers(
837 u64 aruid, std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
838 std::span<const Core::HID::VibrationValue> vibration_values) {
839 if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
840 return;
841 }
842
843 ASSERT_OR_EXECUTE_MSG(
844 vibration_device_handles.size() == vibration_values.size(), { return; },
845 "The amount of device handles does not match with the amount of vibration values,"
846 "this is undefined behavior!");
847
848 for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) {
849 VibrateController(aruid, vibration_device_handles[i], vibration_values[i]);
850 }
851}
852
853Core::HID::VibrationValue NPad::GetLastVibration(
854 u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
855 if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
856 return {};
857 }
858
859 const auto& controller = GetControllerFromHandle(aruid, vibration_device_handle);
860 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
861 return controller.vibration[device_index].latest_vibration_value;
862}
863
864void NPad::InitializeVibrationDevice(
865 const Core::HID::VibrationDeviceHandle& vibration_device_handle) {
866 if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
867 return;
868 }
869
870 const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid();
871 const auto npad_index = static_cast<Core::HID::NpadIdType>(vibration_device_handle.npad_id);
872 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
873 InitializeVibrationDeviceAtIndex(aruid, npad_index, device_index);
874}
875
876void NPad::InitializeVibrationDeviceAtIndex(u64 aruid, Core::HID::NpadIdType npad_id,
877 std::size_t device_index) {
878 auto& controller = GetControllerFromNpadIdType(aruid, npad_id);
879 if (!Settings::values.vibration_enabled.GetValue()) {
880 controller.vibration[device_index].device_mounted = false;
881 return;
882 }
883
884 controller.vibration[device_index].device_mounted =
885 controller.device->IsVibrationEnabled(device_index);
886}
887
888void NPad::SetPermitVibrationSession(bool permit_vibration_session) {
889 permit_vibration_session_enabled = permit_vibration_session;
890}
891
892bool NPad::IsVibrationDeviceMounted(
893 u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
894 if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
895 return false;
896 }
897
898 const auto& controller = GetControllerFromHandle(aruid, vibration_device_handle);
899 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
900 return controller.vibration[device_index].device_mounted;
901}
902
903Result NPad::AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event,
904 Core::HID::NpadIdType npad_id) {
905 std::scoped_lock lock{mutex};
906 return npad_resource.AcquireNpadStyleSetUpdateEventHandle(aruid, out_event, npad_id);
907}
908
909void NPad::AddNewControllerAt(u64 aruid, Core::HID::NpadStyleIndex controller,
910 Core::HID::NpadIdType npad_id) {
911 UpdateControllerAt(aruid, controller, npad_id, true);
912}
913
914void NPad::UpdateControllerAt(u64 aruid, Core::HID::NpadStyleIndex type,
915 Core::HID::NpadIdType npad_id, bool connected) {
916 auto& controller = GetControllerFromNpadIdType(aruid, npad_id);
917 if (!connected) {
918 DisconnectNpad(aruid, npad_id);
919 return;
920 }
921
922 controller.device->SetNpadStyleIndex(type);
923 InitNewlyAddedController(aruid, npad_id);
924}
925
926Result NPad::DisconnectNpad(u64 aruid, Core::HID::NpadIdType npad_id) {
927 if (!IsNpadIdValid(npad_id)) {
928 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
929 return ResultInvalidNpadId;
930 }
931
932 LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id);
933 auto& controller = GetControllerFromNpadIdType(aruid, npad_id);
934 for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) {
935 // Send an empty vibration to stop any vibrations.
936 VibrateControllerAtIndex(aruid, npad_id, device_idx, {});
937 controller.vibration[device_idx].device_mounted = false;
938 }
939
940 auto* shared_memory = controller.shared_memory;
941 // Don't reset shared_memory->assignment_mode this value is persistent
942 shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out
943 shared_memory->device_type.raw = 0;
944 shared_memory->system_properties.raw = 0;
945 shared_memory->button_properties.raw = 0;
946 shared_memory->sixaxis_fullkey_properties.raw = 0;
947 shared_memory->sixaxis_handheld_properties.raw = 0;
948 shared_memory->sixaxis_dual_left_properties.raw = 0;
949 shared_memory->sixaxis_dual_right_properties.raw = 0;
950 shared_memory->sixaxis_left_properties.raw = 0;
951 shared_memory->sixaxis_right_properties.raw = 0;
952 shared_memory->battery_level_dual = Core::HID::NpadBatteryLevel::Empty;
953 shared_memory->battery_level_left = Core::HID::NpadBatteryLevel::Empty;
954 shared_memory->battery_level_right = Core::HID::NpadBatteryLevel::Empty;
955 shared_memory->fullkey_color = {
956 .attribute = ColorAttribute::NoController,
957 .fullkey = {},
958 };
959 shared_memory->joycon_color = {
960 .attribute = ColorAttribute::NoController,
961 .left = {},
962 .right = {},
963 };
964 shared_memory->applet_footer_type = AppletFooterUiType::None;
965
966 controller.is_dual_left_connected = true;
967 controller.is_dual_right_connected = true;
968 controller.is_connected = false;
969 controller.device->Disconnect();
970 npad_resource.SignalStyleSetUpdateEvent(aruid, npad_id);
971 WriteEmptyEntry(shared_memory);
972 return ResultSuccess;
973}
974
975Result NPad::IsFirmwareUpdateAvailableForSixAxisSensor(
976 u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle,
977 bool& is_firmware_available) const {
978 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
979 if (is_valid.IsError()) {
980 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
981 return is_valid;
982 }
983
984 const auto& sixaxis_properties = GetSixaxisProperties(aruid, sixaxis_handle);
985 is_firmware_available = sixaxis_properties.is_firmware_update_available != 0;
986 return ResultSuccess;
987}
988
989Result NPad::ResetIsSixAxisSensorDeviceNewlyAssigned(
990 u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
991 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
992 if (is_valid.IsError()) {
993 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
994 return is_valid;
995 }
996
997 auto& sixaxis_properties = GetSixaxisProperties(aruid, sixaxis_handle);
998 sixaxis_properties.is_newly_assigned.Assign(0);
999
1000 return ResultSuccess;
1001}
1002
1003Result NPad::MergeSingleJoyAsDualJoy(u64 aruid, Core::HID::NpadIdType npad_id_1,
1004 Core::HID::NpadIdType npad_id_2) {
1005 if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) {
1006 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1,
1007 npad_id_2);
1008 return ResultInvalidNpadId;
1009 }
1010 auto& controller_1 = GetControllerFromNpadIdType(aruid, npad_id_1);
1011 auto& controller_2 = GetControllerFromNpadIdType(aruid, npad_id_2);
1012 auto controller_style_1 = controller_1.device->GetNpadStyleIndex();
1013 auto controller_style_2 = controller_2.device->GetNpadStyleIndex();
1014
1015 // Simplify this code by converting dualjoycon with only a side connected to single joycons
1016 if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual) {
1017 if (controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected) {
1018 controller_style_1 = Core::HID::NpadStyleIndex::JoyconLeft;
1019 }
1020 if (!controller_1.is_dual_left_connected && controller_1.is_dual_right_connected) {
1021 controller_style_1 = Core::HID::NpadStyleIndex::JoyconRight;
1022 }
1023 }
1024 if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual) {
1025 if (controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) {
1026 controller_style_2 = Core::HID::NpadStyleIndex::JoyconLeft;
1027 }
1028 if (!controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) {
1029 controller_style_2 = Core::HID::NpadStyleIndex::JoyconRight;
1030 }
1031 }
1032
1033 // Invalid merge errors
1034 if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual ||
1035 controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual) {
1036 return NpadIsDualJoycon;
1037 }
1038 if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft &&
1039 controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft) {
1040 return NpadIsSameType;
1041 }
1042 if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight &&
1043 controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight) {
1044 return NpadIsSameType;
1045 }
1046
1047 // These exceptions are handled as if they where dual joycon
1048 if (controller_style_1 != Core::HID::NpadStyleIndex::JoyconLeft &&
1049 controller_style_1 != Core::HID::NpadStyleIndex::JoyconRight) {
1050 return NpadIsDualJoycon;
1051 }
1052 if (controller_style_2 != Core::HID::NpadStyleIndex::JoyconLeft &&
1053 controller_style_2 != Core::HID::NpadStyleIndex::JoyconRight) {
1054 return NpadIsDualJoycon;
1055 }
1056
1057 // Disconnect the joycons and connect them as dual joycon at the first index.
1058 DisconnectNpad(aruid, npad_id_1);
1059 DisconnectNpad(aruid, npad_id_2);
1060 controller_1.is_dual_left_connected = true;
1061 controller_1.is_dual_right_connected = true;
1062 AddNewControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconDual, npad_id_1);
1063 return ResultSuccess;
1064}
1065
1066Result NPad::StartLrAssignmentMode(u64 aruid) {
1067 std::scoped_lock lock{mutex};
1068 bool is_enabled{};
1069 Result result = npad_resource.GetLrAssignmentMode(is_enabled, aruid);
1070 if (result.IsSuccess() && is_enabled == false) {
1071 result = npad_resource.SetLrAssignmentMode(aruid, true);
1072 }
1073 return result;
1074}
1075
1076Result NPad::StopLrAssignmentMode(u64 aruid) {
1077 std::scoped_lock lock{mutex};
1078 bool is_enabled{};
1079 Result result = npad_resource.GetLrAssignmentMode(is_enabled, aruid);
1080 if (result.IsSuccess() && is_enabled == true) {
1081 result = npad_resource.SetLrAssignmentMode(aruid, false);
1082 }
1083 return result;
1084}
1085
1086Result NPad::SwapNpadAssignment(u64 aruid, Core::HID::NpadIdType npad_id_1,
1087 Core::HID::NpadIdType npad_id_2) {
1088 if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) {
1089 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1,
1090 npad_id_2);
1091 return ResultInvalidNpadId;
1092 }
1093 if (npad_id_1 == Core::HID::NpadIdType::Handheld ||
1094 npad_id_2 == Core::HID::NpadIdType::Handheld || npad_id_1 == Core::HID::NpadIdType::Other ||
1095 npad_id_2 == Core::HID::NpadIdType::Other) {
1096 return ResultSuccess;
1097 }
1098 const auto& controller_1 = GetControllerFromNpadIdType(aruid, npad_id_1).device;
1099 const auto& controller_2 = GetControllerFromNpadIdType(aruid, npad_id_2).device;
1100 const auto type_index_1 = controller_1->GetNpadStyleIndex();
1101 const auto type_index_2 = controller_2->GetNpadStyleIndex();
1102 const auto is_connected_1 = controller_1->IsConnected();
1103 const auto is_connected_2 = controller_2->IsConnected();
1104
1105 if (!npad_resource.IsControllerSupported(aruid, type_index_1) && is_connected_1) {
1106 return ResultNpadNotConnected;
1107 }
1108 if (!npad_resource.IsControllerSupported(aruid, type_index_2) && is_connected_2) {
1109 return ResultNpadNotConnected;
1110 }
1111
1112 UpdateControllerAt(aruid, type_index_2, npad_id_1, is_connected_2);
1113 UpdateControllerAt(aruid, type_index_1, npad_id_2, is_connected_1);
1114
1115 return ResultSuccess;
1116}
1117
1118Result NPad::GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const {
1119 if (!IsNpadIdValid(npad_id)) {
1120 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
1121 return ResultInvalidNpadId;
1122 }
1123 const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid();
1124 const auto& controller = GetControllerFromNpadIdType(aruid, npad_id).device;
1125 pattern = controller->GetLedPattern();
1126 return ResultSuccess;
1127}
1128
1129Result NPad::IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, u64 aruid,
1130 Core::HID::NpadIdType npad_id) const {
1131 std::scoped_lock lock{mutex};
1132 return npad_resource.GetHomeProtectionEnabled(out_is_enabled, aruid, npad_id);
1133}
1134
1135Result NPad::EnableUnintendedHomeButtonInputProtection(u64 aruid, Core::HID::NpadIdType npad_id,
1136 bool is_enabled) {
1137 std::scoped_lock lock{mutex};
1138 return npad_resource.SetHomeProtectionEnabled(aruid, npad_id, is_enabled);
1139}
1140
1141void NPad::SetNpadAnalogStickUseCenterClamp(u64 aruid, bool is_enabled) {
1142 std::scoped_lock lock{mutex};
1143 npad_resource.SetNpadAnalogStickUseCenterClamp(aruid, is_enabled);
1144}
1145
1146void NPad::ClearAllConnectedControllers() {
1147 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
1148 for (auto& controller : controller_data[aruid_index]) {
1149 if (controller.device->IsConnected() &&
1150 controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None) {
1151 controller.device->Disconnect();
1152 controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None);
1153 }
1154 }
1155 }
1156}
1157
1158void NPad::DisconnectAllConnectedControllers() {
1159 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
1160 for (auto& controller : controller_data[aruid_index]) {
1161 controller.device->Disconnect();
1162 }
1163 }
1164}
1165
1166void NPad::ConnectAllDisconnectedControllers() {
1167 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
1168 for (auto& controller : controller_data[aruid_index]) {
1169 if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None &&
1170 !controller.device->IsConnected()) {
1171 controller.device->Connect();
1172 }
1173 }
1174 }
1175}
1176
1177void NPad::ClearAllControllers() {
1178 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
1179 for (auto& controller : controller_data[aruid_index]) {
1180 controller.device->Disconnect();
1181 controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None);
1182 }
1183 }
1184}
1185
1186Core::HID::NpadButton NPad::GetAndResetPressState() {
1187 return static_cast<Core::HID::NpadButton>(press_state.exchange(0));
1188}
1189
1190Result NPad::ApplyNpadSystemCommonPolicy(u64 aruid) {
1191 std::scoped_lock lock{mutex};
1192 const Result result = npad_resource.ApplyNpadSystemCommonPolicy(aruid, false);
1193 if (result.IsSuccess()) {
1194 OnUpdate({});
1195 }
1196 return result;
1197}
1198
1199Result NPad::ApplyNpadSystemCommonPolicyFull(u64 aruid) {
1200 std::scoped_lock lock{mutex};
1201 const Result result = npad_resource.ApplyNpadSystemCommonPolicy(aruid, true);
1202 if (result.IsSuccess()) {
1203 OnUpdate({});
1204 }
1205 return result;
1206}
1207
1208Result NPad::ClearNpadSystemCommonPolicy(u64 aruid) {
1209 std::scoped_lock lock{mutex};
1210 const Result result = npad_resource.ClearNpadSystemCommonPolicy(aruid);
1211 if (result.IsSuccess()) {
1212 OnUpdate({});
1213 }
1214 return result;
1215}
1216
1217void NPad::SetRevision(u64 aruid, NpadRevision revision) {
1218 npad_resource.SetNpadRevision(aruid, revision);
1219}
1220
1221NpadRevision NPad::GetRevision(u64 aruid) {
1222 return npad_resource.GetNpadRevision(aruid);
1223}
1224
1225Result NPad::RegisterAppletResourceUserId(u64 aruid) {
1226 return npad_resource.RegisterAppletResourceUserId(aruid);
1227}
1228
1229void NPad::UnregisterAppletResourceUserId(u64 aruid) {
1230 npad_resource.UnregisterAppletResourceUserId(aruid);
1231}
1232
1233void NPad::SetNpadExternals(std::shared_ptr<AppletResource> resource,
1234 std::recursive_mutex* shared_mutex) {
1235 applet_resource_holder.applet_resource = resource;
1236 applet_resource_holder.shared_mutex = shared_mutex;
1237 applet_resource_holder.shared_npad_resource = &npad_resource;
1238}
1239
1240NPad::NpadControllerData& NPad::GetControllerFromHandle(
1241 u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) {
1242 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
1243 return GetControllerFromNpadIdType(aruid, npad_id);
1244}
1245
1246const NPad::NpadControllerData& NPad::GetControllerFromHandle(
1247 u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) const {
1248 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
1249 return GetControllerFromNpadIdType(aruid, npad_id);
1250}
1251
1252NPad::NpadControllerData& NPad::GetControllerFromHandle(
1253 u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle) {
1254 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
1255 return GetControllerFromNpadIdType(aruid, npad_id);
1256}
1257
1258const NPad::NpadControllerData& NPad::GetControllerFromHandle(
1259 u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle) const {
1260 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
1261 return GetControllerFromNpadIdType(aruid, npad_id);
1262}
1263
1264NPad::NpadControllerData& NPad::GetControllerFromNpadIdType(u64 aruid,
1265 Core::HID::NpadIdType npad_id) {
1266 if (!IsNpadIdValid(npad_id)) {
1267 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
1268 npad_id = Core::HID::NpadIdType::Player1;
1269 }
1270 const auto npad_index = NpadIdTypeToIndex(npad_id);
1271 const auto aruid_index = applet_resource_holder.applet_resource->GetIndexFromAruid(aruid);
1272 return controller_data[aruid_index][npad_index];
1273}
1274
1275const NPad::NpadControllerData& NPad::GetControllerFromNpadIdType(
1276 u64 aruid, Core::HID::NpadIdType npad_id) const {
1277 if (!IsNpadIdValid(npad_id)) {
1278 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
1279 npad_id = Core::HID::NpadIdType::Player1;
1280 }
1281 const auto npad_index = NpadIdTypeToIndex(npad_id);
1282 const auto aruid_index = applet_resource_holder.applet_resource->GetIndexFromAruid(aruid);
1283 return controller_data[aruid_index][npad_index];
1284}
1285
1286Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
1287 u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
1288 auto& controller = GetControllerFromHandle(aruid, sixaxis_handle);
1289 switch (sixaxis_handle.npad_type) {
1290 case Core::HID::NpadStyleIndex::ProController:
1291 case Core::HID::NpadStyleIndex::Pokeball:
1292 return controller.shared_memory->sixaxis_fullkey_properties;
1293 case Core::HID::NpadStyleIndex::Handheld:
1294 return controller.shared_memory->sixaxis_handheld_properties;
1295 case Core::HID::NpadStyleIndex::JoyconDual:
1296 if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
1297 return controller.shared_memory->sixaxis_dual_left_properties;
1298 }
1299 return controller.shared_memory->sixaxis_dual_right_properties;
1300 case Core::HID::NpadStyleIndex::JoyconLeft:
1301 return controller.shared_memory->sixaxis_left_properties;
1302 case Core::HID::NpadStyleIndex::JoyconRight:
1303 return controller.shared_memory->sixaxis_right_properties;
1304 default:
1305 return controller.shared_memory->sixaxis_fullkey_properties;
1306 }
1307}
1308
1309const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
1310 u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
1311 const auto& controller = GetControllerFromHandle(aruid, sixaxis_handle);
1312 switch (sixaxis_handle.npad_type) {
1313 case Core::HID::NpadStyleIndex::ProController:
1314 case Core::HID::NpadStyleIndex::Pokeball:
1315 return controller.shared_memory->sixaxis_fullkey_properties;
1316 case Core::HID::NpadStyleIndex::Handheld:
1317 return controller.shared_memory->sixaxis_handheld_properties;
1318 case Core::HID::NpadStyleIndex::JoyconDual:
1319 if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
1320 return controller.shared_memory->sixaxis_dual_left_properties;
1321 }
1322 return controller.shared_memory->sixaxis_dual_right_properties;
1323 case Core::HID::NpadStyleIndex::JoyconLeft:
1324 return controller.shared_memory->sixaxis_left_properties;
1325 case Core::HID::NpadStyleIndex::JoyconRight:
1326 return controller.shared_memory->sixaxis_right_properties;
1327 default:
1328 return controller.shared_memory->sixaxis_fullkey_properties;
1329 }
1330}
1331
1332AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) {
1333 const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid();
1334 const auto& shared_memory = GetControllerFromNpadIdType(aruid, npad_id).shared_memory;
1335
1336 return {
1337 .ui_variant = 0,
1338 .footer = shared_memory->applet_footer_type,
1339 };
1340}
1341
1342} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
deleted file mode 100644
index 8ab333064..000000000
--- a/src/core/hle/service/hid/controllers/npad.h
+++ /dev/null
@@ -1,214 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <atomic>
8#include <mutex>
9#include <span>
10
11#include "common/common_types.h"
12#include "core/hid/hid_types.h"
13#include "core/hle/service/hid/controllers/controller_base.h"
14#include "core/hle/service/hid/controllers/npad/npad_resource.h"
15#include "core/hle/service/hid/controllers/types/npad_types.h"
16
17namespace Core::HID {
18class EmulatedController;
19enum class ControllerTriggerType;
20} // namespace Core::HID
21
22namespace Kernel {
23class KEvent;
24class KReadableEvent;
25} // namespace Kernel
26
27namespace Service::KernelHelpers {
28class ServiceContext;
29} // namespace Service::KernelHelpers
30
31union Result;
32
33namespace Service::HID {
34class AppletResource;
35struct NpadInternalState;
36struct NpadSixAxisSensorLifo;
37struct NpadSharedMemoryFormat;
38
39class NPad final {
40public:
41 explicit NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_);
42 ~NPad();
43
44 Result Activate();
45 Result Activate(u64 aruid);
46
47 Result ActivateNpadResource();
48 Result ActivateNpadResource(u64 aruid);
49
50 // When the controller is requesting an update for the shared memory
51 void OnUpdate(const Core::Timing::CoreTiming& core_timing);
52
53 Result SetSupportedNpadStyleSet(u64 aruid, Core::HID::NpadStyleSet supported_style_set);
54 Result GetSupportedNpadStyleSet(u64 aruid,
55 Core::HID::NpadStyleSet& out_supported_style_set) const;
56 Result GetMaskedSupportedNpadStyleSet(u64 aruid,
57 Core::HID::NpadStyleSet& out_supported_style_set) const;
58
59 Result SetSupportedNpadIdType(u64 aruid,
60 std::span<const Core::HID::NpadIdType> supported_npad_list);
61
62 Result SetNpadJoyHoldType(u64 aruid, NpadJoyHoldType hold_type);
63 Result GetNpadJoyHoldType(u64 aruid, NpadJoyHoldType& out_hold_type) const;
64
65 Result SetNpadHandheldActivationMode(u64 aruid, NpadHandheldActivationMode mode);
66 Result GetNpadHandheldActivationMode(u64 aruid, NpadHandheldActivationMode& out_mode) const;
67
68 bool SetNpadMode(u64 aruid, Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id,
69 NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode);
70
71 bool VibrateControllerAtIndex(u64 aruid, Core::HID::NpadIdType npad_id,
72 std::size_t device_index,
73 const Core::HID::VibrationValue& vibration_value);
74
75 void VibrateController(u64 aruid,
76 const Core::HID::VibrationDeviceHandle& vibration_device_handle,
77 const Core::HID::VibrationValue& vibration_value);
78
79 void VibrateControllers(
80 u64 aruid, std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
81 std::span<const Core::HID::VibrationValue> vibration_values);
82
83 Core::HID::VibrationValue GetLastVibration(
84 u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
85
86 void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle);
87
88 void InitializeVibrationDeviceAtIndex(u64 aruid, Core::HID::NpadIdType npad_id,
89 std::size_t device_index);
90
91 void SetPermitVibrationSession(bool permit_vibration_session);
92
93 bool IsVibrationDeviceMounted(
94 u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
95
96 Result AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event,
97 Core::HID::NpadIdType npad_id);
98
99 // Adds a new controller at an index.
100 void AddNewControllerAt(u64 aruid, Core::HID::NpadStyleIndex controller,
101 Core::HID::NpadIdType npad_id);
102 // Adds a new controller at an index with connection status.
103 void UpdateControllerAt(u64 aruid, Core::HID::NpadStyleIndex controller,
104 Core::HID::NpadIdType npad_id, bool connected);
105
106 Result DisconnectNpad(u64 aruid, Core::HID::NpadIdType npad_id);
107
108 Result IsFirmwareUpdateAvailableForSixAxisSensor(
109 u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle,
110 bool& is_firmware_available) const;
111 Result ResetIsSixAxisSensorDeviceNewlyAssigned(
112 u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle);
113
114 Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
115
116 Result IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, u64 aruid,
117 Core::HID::NpadIdType npad_id) const;
118 Result EnableUnintendedHomeButtonInputProtection(u64 aruid, Core::HID::NpadIdType npad_id,
119 bool is_enabled);
120
121 void SetNpadAnalogStickUseCenterClamp(u64 aruid, bool is_enabled);
122 void ClearAllConnectedControllers();
123 void DisconnectAllConnectedControllers();
124 void ConnectAllDisconnectedControllers();
125 void ClearAllControllers();
126
127 Result MergeSingleJoyAsDualJoy(u64 aruid, Core::HID::NpadIdType npad_id_1,
128 Core::HID::NpadIdType npad_id_2);
129 Result StartLrAssignmentMode(u64 aruid);
130 Result StopLrAssignmentMode(u64 aruid);
131 Result SwapNpadAssignment(u64 aruid, Core::HID::NpadIdType npad_id_1,
132 Core::HID::NpadIdType npad_id_2);
133
134 // Logical OR for all buttons presses on all controllers
135 // Specifically for cheat engine and other features.
136 Core::HID::NpadButton GetAndResetPressState();
137
138 Result ApplyNpadSystemCommonPolicy(u64 aruid);
139 Result ApplyNpadSystemCommonPolicyFull(u64 aruid);
140 Result ClearNpadSystemCommonPolicy(u64 aruid);
141
142 void SetRevision(u64 aruid, NpadRevision revision);
143 NpadRevision GetRevision(u64 aruid);
144
145 Result RegisterAppletResourceUserId(u64 aruid);
146 void UnregisterAppletResourceUserId(u64 aruid);
147 void SetNpadExternals(std::shared_ptr<AppletResource> resource,
148 std::recursive_mutex* shared_mutex);
149
150 AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);
151
152private:
153 struct VibrationData {
154 bool device_mounted{};
155 Core::HID::VibrationValue latest_vibration_value{};
156 std::chrono::steady_clock::time_point last_vibration_timepoint{};
157 };
158
159 struct NpadControllerData {
160 NpadInternalState* shared_memory = nullptr;
161 Core::HID::EmulatedController* device = nullptr;
162
163 std::array<VibrationData, 2> vibration{};
164 bool is_connected{};
165
166 // Dual joycons can have only one side connected
167 bool is_dual_left_connected{true};
168 bool is_dual_right_connected{true};
169
170 // Current pad state
171 NPadGenericState npad_pad_state{};
172 NPadGenericState npad_libnx_state{};
173 NpadGcTriggerState npad_trigger_state{};
174 int callback_key{};
175 };
176
177 void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx);
178 void InitNewlyAddedController(u64 aruid, Core::HID::NpadIdType npad_id);
179 void RequestPadStateUpdate(u64 aruid, Core::HID::NpadIdType npad_id);
180 void WriteEmptyEntry(NpadInternalState* npad);
181
182 NpadControllerData& GetControllerFromHandle(
183 u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle);
184 const NpadControllerData& GetControllerFromHandle(
185 u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) const;
186 NpadControllerData& GetControllerFromHandle(
187 u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle);
188 const NpadControllerData& GetControllerFromHandle(
189 u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle) const;
190 NpadControllerData& GetControllerFromNpadIdType(u64 aruid, Core::HID::NpadIdType npad_id);
191 const NpadControllerData& GetControllerFromNpadIdType(u64 aruid,
192 Core::HID::NpadIdType npad_id) const;
193
194 Core::HID::SixAxisSensorProperties& GetSixaxisProperties(
195 u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle);
196 const Core::HID::SixAxisSensorProperties& GetSixaxisProperties(
197 u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle) const;
198
199 Core::HID::HIDCore& hid_core;
200 KernelHelpers::ServiceContext& service_context;
201
202 s32 ref_counter{};
203 mutable std::mutex mutex;
204 NPadResource npad_resource;
205 AppletResourceHolder applet_resource_holder{};
206 Kernel::KEvent* input_event{nullptr};
207 std::mutex* input_mutex{nullptr};
208
209 std::atomic<u64> press_state{};
210 bool permit_vibration_session_enabled;
211 std::array<std::array<NpadControllerData, MaxSupportedNpadIdTypes>, AruidIndexMax>
212 controller_data{};
213};
214} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad/npad_data.cpp b/src/core/hle/service/hid/controllers/npad/npad_data.cpp
deleted file mode 100644
index d2423b6d3..000000000
--- a/src/core/hle/service/hid/controllers/npad/npad_data.cpp
+++ /dev/null
@@ -1,228 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/hid/controllers/npad/npad_data.h"
5#include "core/hle/service/hid/hid_util.h"
6
7namespace Service::HID {
8
9NPadData::NPadData() {
10 ClearNpadSystemCommonPolicy();
11}
12
13NPadData::~NPadData() = default;
14
15NpadStatus NPadData::GetNpadStatus() const {
16 return status;
17}
18
19void NPadData::SetNpadAnalogStickUseCenterClamp(bool is_enabled) {
20 status.use_center_clamp.Assign(is_enabled);
21}
22
23bool NPadData::GetNpadAnalogStickUseCenterClamp() const {
24 return status.use_center_clamp.As<bool>();
25}
26
27void NPadData::SetNpadSystemExtStateEnabled(bool is_enabled) {
28 status.system_ext_state.Assign(is_enabled);
29}
30
31bool NPadData::GetNpadSystemExtState() const {
32 return status.system_ext_state.As<bool>();
33}
34
35Result NPadData::SetSupportedNpadIdType(std::span<const Core::HID::NpadIdType> list) {
36 // Note: Real limit is 11. But array size is 10. N's bug?
37 if (list.size() > MaxSupportedNpadIdTypes) {
38 return ResultInvalidArraySize;
39 }
40
41 supported_npad_id_types_count = list.size();
42 memcpy(supported_npad_id_types.data(), list.data(),
43 list.size() * sizeof(Core::HID::NpadIdType));
44
45 return ResultSuccess;
46}
47
48std::size_t NPadData::GetSupportedNpadIdType(std::span<Core::HID::NpadIdType> out_list) const {
49 std::size_t out_size = std::min(supported_npad_id_types_count, out_list.size());
50
51 memcpy(out_list.data(), supported_npad_id_types.data(),
52 out_size * sizeof(Core::HID::NpadIdType));
53
54 return out_size;
55}
56
57bool NPadData::IsNpadIdTypeSupported(Core::HID::NpadIdType npad_id) const {
58 for (std::size_t i = 0; i < supported_npad_id_types_count; i++) {
59 if (supported_npad_id_types[i] == npad_id) {
60 return true;
61 }
62 }
63
64 return false;
65}
66
67void NPadData::SetNpadSystemCommonPolicy(bool is_full_policy) {
68 supported_npad_style_set = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::JoyDual |
69 Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System;
70 handheld_activation_mode = NpadHandheldActivationMode::Dual;
71
72 status.is_supported_styleset_set.Assign(true);
73 status.is_hold_type_set.Assign(true);
74 status.lr_assignment_mode.Assign(false);
75 status.is_policy.Assign(true);
76 if (is_full_policy) {
77 status.is_full_policy.Assign(true);
78 }
79
80 supported_npad_id_types_count = 10;
81 supported_npad_id_types[0] = Core::HID::NpadIdType::Player1;
82 supported_npad_id_types[1] = Core::HID::NpadIdType::Player2;
83 supported_npad_id_types[2] = Core::HID::NpadIdType::Player3;
84 supported_npad_id_types[3] = Core::HID::NpadIdType::Player4;
85 supported_npad_id_types[4] = Core::HID::NpadIdType::Player5;
86 supported_npad_id_types[5] = Core::HID::NpadIdType::Player6;
87 supported_npad_id_types[6] = Core::HID::NpadIdType::Player7;
88 supported_npad_id_types[7] = Core::HID::NpadIdType::Player8;
89 supported_npad_id_types[8] = Core::HID::NpadIdType::Other;
90 supported_npad_id_types[9] = Core::HID::NpadIdType::Handheld;
91
92 for (auto& input_protection : is_unintended_home_button_input_protection) {
93 input_protection = true;
94 }
95}
96
97void NPadData::ClearNpadSystemCommonPolicy() {
98 status.raw = 0;
99 supported_npad_style_set = Core::HID::NpadStyleSet::All;
100 npad_hold_type = NpadJoyHoldType::Vertical;
101 handheld_activation_mode = NpadHandheldActivationMode::Dual;
102
103 for (auto& button_assignment : npad_button_assignment) {
104 button_assignment = Core::HID::NpadButton::None;
105 }
106
107 supported_npad_id_types_count = 10;
108 supported_npad_id_types[0] = Core::HID::NpadIdType::Player1;
109 supported_npad_id_types[1] = Core::HID::NpadIdType::Player2;
110 supported_npad_id_types[2] = Core::HID::NpadIdType::Player3;
111 supported_npad_id_types[3] = Core::HID::NpadIdType::Player4;
112 supported_npad_id_types[4] = Core::HID::NpadIdType::Player5;
113 supported_npad_id_types[5] = Core::HID::NpadIdType::Player6;
114 supported_npad_id_types[6] = Core::HID::NpadIdType::Player7;
115 supported_npad_id_types[7] = Core::HID::NpadIdType::Player8;
116 supported_npad_id_types[8] = Core::HID::NpadIdType::Other;
117 supported_npad_id_types[9] = Core::HID::NpadIdType::Handheld;
118
119 for (auto& input_protection : is_unintended_home_button_input_protection) {
120 input_protection = true;
121 }
122}
123
124void NPadData::SetNpadJoyHoldType(NpadJoyHoldType hold_type) {
125 npad_hold_type = hold_type;
126 status.is_hold_type_set.Assign(true);
127}
128
129NpadJoyHoldType NPadData::GetNpadJoyHoldType() const {
130 return npad_hold_type;
131}
132
133void NPadData::SetHandheldActivationMode(NpadHandheldActivationMode activation_mode) {
134 handheld_activation_mode = activation_mode;
135}
136
137NpadHandheldActivationMode NPadData::GetHandheldActivationMode() const {
138 return handheld_activation_mode;
139}
140
141void NPadData::SetSupportedNpadStyleSet(Core::HID::NpadStyleSet style_set) {
142 supported_npad_style_set = style_set;
143 status.is_supported_styleset_set.Assign(true);
144 status.is_hold_type_set.Assign(true);
145}
146
147Core::HID::NpadStyleSet NPadData::GetSupportedNpadStyleSet() const {
148 return supported_npad_style_set;
149}
150
151bool NPadData::IsNpadStyleIndexSupported(Core::HID::NpadStyleIndex style_index) const {
152 Core::HID::NpadStyleTag style = {supported_npad_style_set};
153 switch (style_index) {
154 case Core::HID::NpadStyleIndex::ProController:
155 return style.fullkey.As<bool>();
156 case Core::HID::NpadStyleIndex::Handheld:
157 return style.handheld.As<bool>();
158 case Core::HID::NpadStyleIndex::JoyconDual:
159 return style.joycon_dual.As<bool>();
160 case Core::HID::NpadStyleIndex::JoyconLeft:
161 return style.joycon_left.As<bool>();
162 case Core::HID::NpadStyleIndex::JoyconRight:
163 return style.joycon_right.As<bool>();
164 case Core::HID::NpadStyleIndex::GameCube:
165 return style.gamecube.As<bool>();
166 case Core::HID::NpadStyleIndex::Pokeball:
167 return style.palma.As<bool>();
168 case Core::HID::NpadStyleIndex::NES:
169 return style.lark.As<bool>();
170 case Core::HID::NpadStyleIndex::SNES:
171 return style.lucia.As<bool>();
172 case Core::HID::NpadStyleIndex::N64:
173 return style.lagoon.As<bool>();
174 case Core::HID::NpadStyleIndex::SegaGenesis:
175 return style.lager.As<bool>();
176 default:
177 return false;
178 }
179}
180
181void NPadData::SetLrAssignmentMode(bool is_enabled) {
182 status.lr_assignment_mode.Assign(is_enabled);
183}
184
185bool NPadData::GetLrAssignmentMode() const {
186 return status.lr_assignment_mode.As<bool>();
187}
188
189void NPadData::SetAssigningSingleOnSlSrPress(bool is_enabled) {
190 status.assigning_single_on_sl_sr_press.Assign(is_enabled);
191}
192
193bool NPadData::GetAssigningSingleOnSlSrPress() const {
194 return status.assigning_single_on_sl_sr_press.As<bool>();
195}
196
197void NPadData::SetHomeProtectionEnabled(bool is_enabled, Core::HID::NpadIdType npad_id) {
198 is_unintended_home_button_input_protection[NpadIdTypeToIndex(npad_id)] = is_enabled;
199}
200
201bool NPadData::GetHomeProtectionEnabled(Core::HID::NpadIdType npad_id) const {
202 return is_unintended_home_button_input_protection[NpadIdTypeToIndex(npad_id)];
203}
204
205void NPadData::SetCaptureButtonAssignment(Core::HID::NpadButton button_assignment,
206 std::size_t style_index) {
207 npad_button_assignment[style_index] = button_assignment;
208}
209
210Core::HID::NpadButton NPadData::GetCaptureButtonAssignment(std::size_t style_index) const {
211 return npad_button_assignment[style_index];
212}
213
214std::size_t NPadData::GetNpadCaptureButtonAssignmentList(
215 std::span<Core::HID::NpadButton> out_list) const {
216 for (std::size_t i = 0; i < out_list.size(); i++) {
217 Core::HID::NpadStyleSet style_set = GetStylesetByIndex(i);
218 if ((style_set & supported_npad_style_set) == Core::HID::NpadStyleSet::None ||
219 npad_button_assignment[i] == Core::HID::NpadButton::None) {
220 return i;
221 }
222 out_list[i] = npad_button_assignment[i];
223 }
224
225 return out_list.size();
226}
227
228} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad/npad_data.h b/src/core/hle/service/hid/controllers/npad/npad_data.h
deleted file mode 100644
index f799a9f9c..000000000
--- a/src/core/hle/service/hid/controllers/npad/npad_data.h
+++ /dev/null
@@ -1,88 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7#include <span>
8
9#include "common/common_types.h"
10#include "core/hid/hid_types.h"
11#include "core/hle/result.h"
12#include "core/hle/service/hid/controllers/types/npad_types.h"
13
14namespace Service::HID {
15
16struct NpadStatus {
17 union {
18 u32 raw{};
19
20 BitField<0, 1, u32> is_supported_styleset_set;
21 BitField<1, 1, u32> is_hold_type_set;
22 BitField<2, 1, u32> lr_assignment_mode;
23 BitField<3, 1, u32> assigning_single_on_sl_sr_press;
24 BitField<4, 1, u32> is_full_policy;
25 BitField<5, 1, u32> is_policy;
26 BitField<6, 1, u32> use_center_clamp;
27 BitField<7, 1, u32> system_ext_state;
28 };
29};
30static_assert(sizeof(NpadStatus) == 4, "NpadStatus is an invalid size");
31
32/// Handles Npad request from HID interfaces
33class NPadData final {
34public:
35 explicit NPadData();
36 ~NPadData();
37
38 NpadStatus GetNpadStatus() const;
39
40 void SetNpadAnalogStickUseCenterClamp(bool is_enabled);
41 bool GetNpadAnalogStickUseCenterClamp() const;
42
43 void SetNpadSystemExtStateEnabled(bool is_enabled);
44 bool GetNpadSystemExtState() const;
45
46 Result SetSupportedNpadIdType(std::span<const Core::HID::NpadIdType> list);
47 std::size_t GetSupportedNpadIdType(std::span<Core::HID::NpadIdType> out_list) const;
48 bool IsNpadIdTypeSupported(Core::HID::NpadIdType npad_id) const;
49
50 void SetNpadSystemCommonPolicy(bool is_full_policy);
51 void ClearNpadSystemCommonPolicy();
52
53 void SetNpadJoyHoldType(NpadJoyHoldType hold_type);
54 NpadJoyHoldType GetNpadJoyHoldType() const;
55
56 void SetHandheldActivationMode(NpadHandheldActivationMode activation_mode);
57 NpadHandheldActivationMode GetHandheldActivationMode() const;
58
59 void SetSupportedNpadStyleSet(Core::HID::NpadStyleSet style_set);
60 Core::HID::NpadStyleSet GetSupportedNpadStyleSet() const;
61 bool IsNpadStyleIndexSupported(Core::HID::NpadStyleIndex style_index) const;
62
63 void SetLrAssignmentMode(bool is_enabled);
64 bool GetLrAssignmentMode() const;
65
66 void SetAssigningSingleOnSlSrPress(bool is_enabled);
67 bool GetAssigningSingleOnSlSrPress() const;
68
69 void SetHomeProtectionEnabled(bool is_enabled, Core::HID::NpadIdType npad_id);
70 bool GetHomeProtectionEnabled(Core::HID::NpadIdType npad_id) const;
71
72 void SetCaptureButtonAssignment(Core::HID::NpadButton button_assignment,
73 std::size_t style_index);
74 Core::HID::NpadButton GetCaptureButtonAssignment(std::size_t style_index) const;
75 std::size_t GetNpadCaptureButtonAssignmentList(std::span<Core::HID::NpadButton> out_list) const;
76
77private:
78 NpadStatus status{};
79 Core::HID::NpadStyleSet supported_npad_style_set{Core::HID::NpadStyleSet::All};
80 NpadJoyHoldType npad_hold_type{NpadJoyHoldType::Vertical};
81 NpadHandheldActivationMode handheld_activation_mode{};
82 std::array<Core::HID::NpadIdType, MaxSupportedNpadIdTypes> supported_npad_id_types{};
83 std::array<Core::HID::NpadButton, StyleIndexCount> npad_button_assignment{};
84 std::size_t supported_npad_id_types_count{};
85 std::array<bool, MaxSupportedNpadIdTypes> is_unintended_home_button_input_protection{};
86};
87
88} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad/npad_resource.cpp b/src/core/hle/service/hid/controllers/npad/npad_resource.cpp
deleted file mode 100644
index 0a9341a39..000000000
--- a/src/core/hle/service/hid/controllers/npad/npad_resource.cpp
+++ /dev/null
@@ -1,685 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/kernel/k_event.h"
5#include "core/hle/kernel/k_readable_event.h"
6#include "core/hle/service/hid/controllers/npad/npad_resource.h"
7#include "core/hle/service/hid/controllers/types/npad_types.h"
8#include "core/hle/service/hid/errors.h"
9#include "core/hle/service/hid/hid_util.h"
10
11namespace Service::HID {
12
13NPadResource::NPadResource(KernelHelpers::ServiceContext& context) : service_context{context} {}
14
15NPadResource::~NPadResource() = default;
16
17Result NPadResource::RegisterAppletResourceUserId(u64 aruid) {
18 const auto aruid_index = GetIndexFromAruid(aruid);
19 if (aruid_index < AruidIndexMax) {
20 return ResultAruidAlreadyRegistered;
21 }
22
23 std::size_t data_index = AruidIndexMax;
24 for (std::size_t i = 0; i < AruidIndexMax; i++) {
25 if (!state[i].flag.is_initialized) {
26 data_index = i;
27 break;
28 }
29 }
30
31 if (data_index == AruidIndexMax) {
32 return ResultAruidNoAvailableEntries;
33 }
34
35 auto& aruid_data = state[data_index];
36
37 aruid_data.aruid = aruid;
38 aruid_data.flag.is_initialized.Assign(true);
39
40 data_index = AruidIndexMax;
41 for (std::size_t i = 0; i < AruidIndexMax; i++) {
42 if (registration_list.flag[i] == RegistrationStatus::Initialized) {
43 if (registration_list.aruid[i] != aruid) {
44 continue;
45 }
46 data_index = i;
47 break;
48 }
49 if (registration_list.flag[i] == RegistrationStatus::None) {
50 data_index = i;
51 break;
52 }
53 }
54
55 if (data_index == AruidIndexMax) {
56 return ResultSuccess;
57 }
58
59 registration_list.flag[data_index] = RegistrationStatus::Initialized;
60 registration_list.aruid[data_index] = aruid;
61
62 return ResultSuccess;
63}
64
65void NPadResource::UnregisterAppletResourceUserId(u64 aruid) {
66 const u64 aruid_index = GetIndexFromAruid(aruid);
67
68 DestroyStyleSetUpdateEvents(aruid);
69 if (aruid_index < AruidIndexMax) {
70 state[aruid_index] = {};
71 registration_list.flag[aruid_index] = RegistrationStatus::PendingDelete;
72 }
73}
74
75void NPadResource::DestroyStyleSetUpdateEvents(u64 aruid) {
76 const u64 aruid_index = GetIndexFromAruid(aruid);
77
78 if (aruid_index >= AruidIndexMax) {
79 return;
80 }
81
82 for (auto& controller_state : state[aruid_index].controller_state) {
83 if (!controller_state.is_styleset_update_event_initialized) {
84 continue;
85 }
86 service_context.CloseEvent(controller_state.style_set_update_event);
87 controller_state.is_styleset_update_event_initialized = false;
88 }
89}
90
91Result NPadResource::Activate(u64 aruid) {
92 const u64 aruid_index = GetIndexFromAruid(aruid);
93
94 if (aruid_index >= AruidIndexMax) {
95 return ResultSuccess;
96 }
97
98 auto& state_data = state[aruid_index];
99
100 if (state_data.flag.is_assigned) {
101 return ResultAruidAlreadyRegistered;
102 }
103
104 state_data.flag.is_assigned.Assign(true);
105 state_data.data.ClearNpadSystemCommonPolicy();
106 state_data.npad_revision = NpadRevision::Revision0;
107 state_data.button_config = {};
108
109 if (active_data_aruid == aruid) {
110 default_hold_type = active_data.GetNpadJoyHoldType();
111 active_data.SetNpadJoyHoldType(default_hold_type);
112 }
113 return ResultSuccess;
114}
115
116Result NPadResource::Activate() {
117 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
118 return ResultAppletResourceOverflow;
119 }
120 if (ref_counter == 0) {
121 RegisterAppletResourceUserId(SystemAruid);
122 Activate(SystemAruid);
123 }
124 ref_counter++;
125 return ResultSuccess;
126}
127
128Result NPadResource::Deactivate() {
129 if (ref_counter == 0) {
130 return ResultAppletResourceNotInitialized;
131 }
132
133 UnregisterAppletResourceUserId(SystemAruid);
134 ref_counter--;
135 return ResultSuccess;
136}
137
138NPadData* NPadResource::GetActiveData() {
139 return &active_data;
140}
141
142u64 NPadResource::GetActiveDataAruid() {
143 return active_data_aruid;
144}
145
146void NPadResource::SetAppletResourceUserId(u64 aruid) {
147 if (active_data_aruid == aruid) {
148 return;
149 }
150
151 active_data_aruid = aruid;
152 default_hold_type = active_data.GetNpadJoyHoldType();
153 const u64 aruid_index = GetIndexFromAruid(aruid);
154
155 if (aruid_index >= AruidIndexMax) {
156 return;
157 }
158
159 auto& data = state[aruid_index].data;
160 if (data.GetNpadStatus().is_policy || data.GetNpadStatus().is_full_policy) {
161 data.SetNpadJoyHoldType(default_hold_type);
162 }
163
164 active_data = data;
165 if (data.GetNpadStatus().is_hold_type_set) {
166 active_data.SetNpadJoyHoldType(default_hold_type);
167 }
168}
169
170std::size_t NPadResource::GetIndexFromAruid(u64 aruid) const {
171 for (std::size_t i = 0; i < AruidIndexMax; i++) {
172 if (registration_list.flag[i] == RegistrationStatus::Initialized &&
173 registration_list.aruid[i] == aruid) {
174 return i;
175 }
176 }
177 return AruidIndexMax;
178}
179
180Result NPadResource::ApplyNpadSystemCommonPolicy(u64 aruid, bool is_full_policy) {
181 const u64 aruid_index = GetIndexFromAruid(aruid);
182 if (aruid_index >= AruidIndexMax) {
183 return ResultNpadNotConnected;
184 }
185
186 auto& data = state[aruid_index].data;
187 data.SetNpadSystemCommonPolicy(is_full_policy);
188 data.SetNpadJoyHoldType(default_hold_type);
189 if (active_data_aruid == aruid) {
190 active_data.SetNpadSystemCommonPolicy(is_full_policy);
191 active_data.SetNpadJoyHoldType(default_hold_type);
192 }
193 return ResultSuccess;
194}
195
196Result NPadResource::ClearNpadSystemCommonPolicy(u64 aruid) {
197 const u64 aruid_index = GetIndexFromAruid(aruid);
198 if (aruid_index >= AruidIndexMax) {
199 return ResultNpadNotConnected;
200 }
201
202 state[aruid_index].data.ClearNpadSystemCommonPolicy();
203 if (active_data_aruid == aruid) {
204 active_data.ClearNpadSystemCommonPolicy();
205 }
206 return ResultSuccess;
207}
208
209Result NPadResource::SetSupportedNpadStyleSet(u64 aruid, Core::HID::NpadStyleSet style_set) {
210 const u64 aruid_index = GetIndexFromAruid(aruid);
211 if (aruid_index >= AruidIndexMax) {
212 return ResultNpadNotConnected;
213 }
214
215 auto& data = state[aruid_index].data;
216 data.SetSupportedNpadStyleSet(style_set);
217 if (active_data_aruid == aruid) {
218 active_data.SetSupportedNpadStyleSet(style_set);
219 active_data.SetNpadJoyHoldType(data.GetNpadJoyHoldType());
220 }
221 return ResultSuccess;
222}
223
224Result NPadResource::GetSupportedNpadStyleSet(Core::HID::NpadStyleSet& out_style_Set,
225 u64 aruid) const {
226 const u64 aruid_index = GetIndexFromAruid(aruid);
227 if (aruid_index >= AruidIndexMax) {
228 return ResultNpadNotConnected;
229 }
230
231 auto& data = state[aruid_index].data;
232 if (!data.GetNpadStatus().is_supported_styleset_set) {
233 return ResultUndefinedStyleset;
234 }
235
236 out_style_Set = data.GetSupportedNpadStyleSet();
237 return ResultSuccess;
238}
239
240Result NPadResource::GetMaskedSupportedNpadStyleSet(Core::HID::NpadStyleSet& out_style_set,
241 u64 aruid) const {
242 if (aruid == SystemAruid) {
243 out_style_set = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
244 Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
245 Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Palma |
246 Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System;
247 return ResultSuccess;
248 }
249
250 const u64 aruid_index = GetIndexFromAruid(aruid);
251 if (aruid_index >= AruidIndexMax) {
252 return ResultNpadNotConnected;
253 }
254
255 auto& data = state[aruid_index].data;
256 if (!data.GetNpadStatus().is_supported_styleset_set) {
257 return ResultUndefinedStyleset;
258 }
259
260 Core::HID::NpadStyleSet mask{Core::HID::NpadStyleSet::None};
261 out_style_set = data.GetSupportedNpadStyleSet();
262
263 switch (state[aruid_index].npad_revision) {
264 case NpadRevision::Revision1:
265 mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
266 Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
267 Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc |
268 Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::SystemExt |
269 Core::HID::NpadStyleSet::System;
270 break;
271 case NpadRevision::Revision2:
272 mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
273 Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
274 Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc |
275 Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::Lark |
276 Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System;
277 break;
278 case NpadRevision::Revision3:
279 mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
280 Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
281 Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc |
282 Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::Lark |
283 Core::HID::NpadStyleSet::HandheldLark | Core::HID::NpadStyleSet::Lucia |
284 Core::HID::NpadStyleSet::Lagoon | Core::HID::NpadStyleSet::Lager |
285 Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System;
286 break;
287 default:
288 mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
289 Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
290 Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::SystemExt |
291 Core::HID::NpadStyleSet::System;
292 break;
293 }
294
295 out_style_set = out_style_set & mask;
296 return ResultSuccess;
297}
298
299Result NPadResource::GetAvailableStyleset(Core::HID::NpadStyleSet& out_style_set, u64 aruid) const {
300 const u64 aruid_index = GetIndexFromAruid(aruid);
301 if (aruid_index >= AruidIndexMax) {
302 return ResultNpadNotConnected;
303 }
304
305 auto& data = state[aruid_index].data;
306 if (!data.GetNpadStatus().is_supported_styleset_set) {
307 return ResultUndefinedStyleset;
308 }
309
310 Core::HID::NpadStyleSet mask{Core::HID::NpadStyleSet::None};
311 out_style_set = data.GetSupportedNpadStyleSet();
312
313 switch (state[aruid_index].npad_revision) {
314 case NpadRevision::Revision1:
315 mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
316 Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
317 Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc |
318 Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::SystemExt |
319 Core::HID::NpadStyleSet::System;
320 break;
321 case NpadRevision::Revision2:
322 mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
323 Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
324 Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc |
325 Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::Lark |
326 Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System;
327 break;
328 case NpadRevision::Revision3:
329 mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
330 Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
331 Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc |
332 Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::Lark |
333 Core::HID::NpadStyleSet::HandheldLark | Core::HID::NpadStyleSet::Lucia |
334 Core::HID::NpadStyleSet::Lagoon | Core::HID::NpadStyleSet::Lager |
335 Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System;
336 break;
337 default:
338 mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld |
339 Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft |
340 Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::SystemExt |
341 Core::HID::NpadStyleSet::System;
342 break;
343 }
344
345 out_style_set = out_style_set & mask;
346 return ResultSuccess;
347}
348
349NpadRevision NPadResource::GetNpadRevision(u64 aruid) const {
350 const u64 aruid_index = GetIndexFromAruid(aruid);
351 if (aruid_index >= AruidIndexMax) {
352 return NpadRevision::Revision0;
353 }
354
355 return state[aruid_index].npad_revision;
356}
357
358Result NPadResource::IsSupportedNpadStyleSet(bool& is_set, u64 aruid) {
359 const u64 aruid_index = GetIndexFromAruid(aruid);
360 if (aruid_index >= AruidIndexMax) {
361 return ResultNpadNotConnected;
362 }
363
364 is_set = state[aruid_index].data.GetNpadStatus().is_supported_styleset_set.Value() != 0;
365 return ResultSuccess;
366}
367
368Result NPadResource::SetNpadJoyHoldType(u64 aruid, NpadJoyHoldType hold_type) {
369 const u64 aruid_index = GetIndexFromAruid(aruid);
370 if (aruid_index >= AruidIndexMax) {
371 return ResultNpadNotConnected;
372 }
373
374 state[aruid_index].data.SetNpadJoyHoldType(hold_type);
375 if (active_data_aruid == aruid) {
376 active_data.SetNpadJoyHoldType(hold_type);
377 }
378 return ResultSuccess;
379}
380
381Result NPadResource::GetNpadJoyHoldType(NpadJoyHoldType& hold_type, u64 aruid) const {
382 const u64 aruid_index = GetIndexFromAruid(aruid);
383 if (aruid_index >= AruidIndexMax) {
384 return ResultNpadNotConnected;
385 }
386
387 auto& data = state[aruid_index].data;
388 if (data.GetNpadStatus().is_policy || data.GetNpadStatus().is_full_policy) {
389 hold_type = active_data.GetNpadJoyHoldType();
390 return ResultSuccess;
391 }
392 hold_type = data.GetNpadJoyHoldType();
393 return ResultSuccess;
394}
395
396Result NPadResource::SetNpadHandheldActivationMode(u64 aruid,
397 NpadHandheldActivationMode activation_mode) {
398 const u64 aruid_index = GetIndexFromAruid(aruid);
399 if (aruid_index >= AruidIndexMax) {
400 return ResultNpadNotConnected;
401 }
402
403 state[aruid_index].data.SetHandheldActivationMode(activation_mode);
404 if (active_data_aruid == aruid) {
405 active_data.SetHandheldActivationMode(activation_mode);
406 }
407 return ResultSuccess;
408}
409
410Result NPadResource::GetNpadHandheldActivationMode(NpadHandheldActivationMode& activation_mode,
411 u64 aruid) const {
412 const u64 aruid_index = GetIndexFromAruid(aruid);
413 if (aruid_index >= AruidIndexMax) {
414 return ResultNpadNotConnected;
415 }
416
417 activation_mode = state[aruid_index].data.GetHandheldActivationMode();
418 return ResultSuccess;
419}
420
421Result NPadResource::SetSupportedNpadIdType(
422 u64 aruid, std::span<const Core::HID::NpadIdType> supported_npad_list) {
423 const u64 aruid_index = GetIndexFromAruid(aruid);
424 if (aruid_index >= AruidIndexMax) {
425 return ResultNpadNotConnected;
426 }
427 if (supported_npad_list.size() > MaxSupportedNpadIdTypes) {
428 return ResultInvalidArraySize;
429 }
430
431 Result result = state[aruid_index].data.SetSupportedNpadIdType(supported_npad_list);
432 if (result.IsSuccess() && active_data_aruid == aruid) {
433 result = active_data.SetSupportedNpadIdType(supported_npad_list);
434 }
435
436 return result;
437}
438
439bool NPadResource::IsControllerSupported(u64 aruid, Core::HID::NpadStyleIndex style_index) const {
440 const u64 aruid_index = GetIndexFromAruid(aruid);
441 if (aruid_index >= AruidIndexMax) {
442 return false;
443 }
444 return state[aruid_index].data.IsNpadStyleIndexSupported(style_index);
445}
446
447Result NPadResource::SetLrAssignmentMode(u64 aruid, bool is_enabled) {
448 const u64 aruid_index = GetIndexFromAruid(aruid);
449 if (aruid_index >= AruidIndexMax) {
450 return ResultNpadNotConnected;
451 }
452
453 state[aruid_index].data.SetLrAssignmentMode(is_enabled);
454 if (active_data_aruid == aruid) {
455 active_data.SetLrAssignmentMode(is_enabled);
456 }
457 return ResultSuccess;
458}
459
460Result NPadResource::GetLrAssignmentMode(bool& is_enabled, u64 aruid) const {
461 const u64 aruid_index = GetIndexFromAruid(aruid);
462 if (aruid_index >= AruidIndexMax) {
463 return ResultNpadNotConnected;
464 }
465
466 is_enabled = state[aruid_index].data.GetLrAssignmentMode();
467 return ResultSuccess;
468}
469
470Result NPadResource::SetAssigningSingleOnSlSrPress(u64 aruid, bool is_enabled) {
471 const u64 aruid_index = GetIndexFromAruid(aruid);
472 if (aruid_index >= AruidIndexMax) {
473 return ResultNpadNotConnected;
474 }
475
476 state[aruid_index].data.SetAssigningSingleOnSlSrPress(is_enabled);
477 if (active_data_aruid == aruid) {
478 active_data.SetAssigningSingleOnSlSrPress(is_enabled);
479 }
480 return ResultSuccess;
481}
482
483Result NPadResource::IsAssigningSingleOnSlSrPressEnabled(bool& is_enabled, u64 aruid) const {
484 const u64 aruid_index = GetIndexFromAruid(aruid);
485 if (aruid_index >= AruidIndexMax) {
486 return ResultNpadNotConnected;
487 }
488
489 is_enabled = state[aruid_index].data.GetAssigningSingleOnSlSrPress();
490 return ResultSuccess;
491}
492
493Result NPadResource::AcquireNpadStyleSetUpdateEventHandle(u64 aruid,
494 Kernel::KReadableEvent** out_event,
495 Core::HID::NpadIdType npad_id) {
496 const u64 aruid_index = GetIndexFromAruid(aruid);
497 if (aruid_index >= AruidIndexMax) {
498 return ResultNpadNotConnected;
499 }
500
501 auto& controller_state = state[aruid_index].controller_state[NpadIdTypeToIndex(npad_id)];
502 if (!controller_state.is_styleset_update_event_initialized) {
503 // Auto clear = true
504 controller_state.style_set_update_event =
505 service_context.CreateEvent("NpadResource:StylesetUpdateEvent");
506
507 // Assume creating the event succeeds otherwise crash the system here
508 controller_state.is_styleset_update_event_initialized = true;
509 }
510
511 *out_event = &controller_state.style_set_update_event->GetReadableEvent();
512
513 if (controller_state.is_styleset_update_event_initialized) {
514 controller_state.style_set_update_event->Signal();
515 }
516
517 return ResultSuccess;
518}
519
520Result NPadResource::SignalStyleSetUpdateEvent(u64 aruid, Core::HID::NpadIdType npad_id) {
521 const u64 aruid_index = GetIndexFromAruid(aruid);
522 if (aruid_index >= AruidIndexMax) {
523 return ResultNpadNotConnected;
524 }
525 auto controller = state[aruid_index].controller_state[NpadIdTypeToIndex(npad_id)];
526 if (controller.is_styleset_update_event_initialized) {
527 controller.style_set_update_event->Signal();
528 }
529 return ResultSuccess;
530}
531
532Result NPadResource::GetHomeProtectionEnabled(bool& is_enabled, u64 aruid,
533 Core::HID::NpadIdType npad_id) const {
534 const u64 aruid_index = GetIndexFromAruid(aruid);
535 if (aruid_index >= AruidIndexMax) {
536 return ResultNpadNotConnected;
537 }
538
539 is_enabled = state[aruid_index].data.GetHomeProtectionEnabled(npad_id);
540 return ResultSuccess;
541}
542
543Result NPadResource::SetHomeProtectionEnabled(u64 aruid, Core::HID::NpadIdType npad_id,
544 bool is_enabled) {
545 const u64 aruid_index = GetIndexFromAruid(aruid);
546 if (aruid_index >= AruidIndexMax) {
547 return ResultNpadNotConnected;
548 }
549
550 state[aruid_index].data.SetHomeProtectionEnabled(is_enabled, npad_id);
551 if (active_data_aruid == aruid) {
552 active_data.SetHomeProtectionEnabled(is_enabled, npad_id);
553 }
554 return ResultSuccess;
555}
556
557Result NPadResource::SetNpadAnalogStickUseCenterClamp(u64 aruid, bool is_enabled) {
558 const u64 aruid_index = GetIndexFromAruid(aruid);
559 if (aruid_index >= AruidIndexMax) {
560 return ResultNpadNotConnected;
561 }
562
563 state[aruid_index].data.SetNpadAnalogStickUseCenterClamp(is_enabled);
564 if (active_data_aruid == aruid) {
565 active_data.SetNpadAnalogStickUseCenterClamp(is_enabled);
566 }
567 return ResultSuccess;
568}
569
570Result NPadResource::SetButtonConfig(u64 aruid, Core::HID::NpadIdType npad_id, std::size_t index,
571 Core::HID::NpadButton button_config) {
572 const u64 aruid_index = GetIndexFromAruid(aruid);
573 if (aruid_index >= AruidIndexMax) {
574 return ResultNpadNotConnected;
575 }
576
577 state[aruid_index].button_config[NpadIdTypeToIndex(npad_id)][index] = button_config;
578 return ResultSuccess;
579}
580
581Core::HID::NpadButton NPadResource::GetButtonConfig(u64 aruid, Core::HID::NpadIdType npad_id,
582 std::size_t index, Core::HID::NpadButton mask,
583 bool is_enabled) {
584 const u64 aruid_index = GetIndexFromAruid(aruid);
585 if (aruid_index >= AruidIndexMax) {
586 return Core::HID::NpadButton::None;
587 }
588
589 auto& button_config = state[aruid_index].button_config[NpadIdTypeToIndex(npad_id)][index];
590 if (is_enabled) {
591 button_config = button_config | mask;
592 return button_config;
593 }
594
595 button_config = Core::HID::NpadButton::None;
596 return Core::HID::NpadButton::None;
597}
598
599void NPadResource::ResetButtonConfig() {
600 for (auto& selected_state : state) {
601 selected_state.button_config = {};
602 }
603}
604
605Result NPadResource::SetNpadCaptureButtonAssignment(u64 aruid,
606 Core::HID::NpadStyleSet npad_style_set,
607 Core::HID::NpadButton button_assignment) {
608 const u64 aruid_index = GetIndexFromAruid(aruid);
609 if (aruid_index >= AruidIndexMax) {
610 return ResultNpadNotConnected;
611 }
612
613 // Must be a power of two
614 const auto raw_styleset = static_cast<u32>(npad_style_set);
615 if (raw_styleset == 0 && (raw_styleset & (raw_styleset - 1)) != 0) {
616 return ResultMultipleStyleSetSelected;
617 }
618
619 std::size_t style_index{};
620 Core::HID::NpadStyleSet style_selected{};
621 for (style_index = 0; style_index < StyleIndexCount; ++style_index) {
622 style_selected = GetStylesetByIndex(style_index);
623 if (npad_style_set == style_selected) {
624 break;
625 }
626 }
627
628 if (style_selected == Core::HID::NpadStyleSet::None) {
629 return ResultMultipleStyleSetSelected;
630 }
631
632 state[aruid_index].data.SetCaptureButtonAssignment(button_assignment, style_index);
633 if (active_data_aruid == aruid) {
634 active_data.SetCaptureButtonAssignment(button_assignment, style_index);
635 }
636 return ResultSuccess;
637}
638
639Result NPadResource::ClearNpadCaptureButtonAssignment(u64 aruid) {
640 const u64 aruid_index = GetIndexFromAruid(aruid);
641 if (aruid_index >= AruidIndexMax) {
642 return ResultNpadNotConnected;
643 }
644
645 for (std::size_t i = 0; i < StyleIndexCount; i++) {
646 state[aruid_index].data.SetCaptureButtonAssignment(Core::HID::NpadButton::None, i);
647 if (active_data_aruid == aruid) {
648 active_data.SetCaptureButtonAssignment(Core::HID::NpadButton::None, i);
649 }
650 }
651 return ResultSuccess;
652}
653
654std::size_t NPadResource::GetNpadCaptureButtonAssignment(std::span<Core::HID::NpadButton> out_list,
655 u64 aruid) const {
656 const u64 aruid_index = GetIndexFromAruid(aruid);
657 if (aruid_index >= AruidIndexMax) {
658 return 0;
659 }
660 return state[aruid_index].data.GetNpadCaptureButtonAssignmentList(out_list);
661}
662
663void NPadResource::SetNpadRevision(u64 aruid, NpadRevision revision) {
664 const u64 aruid_index = GetIndexFromAruid(aruid);
665 if (aruid_index >= AruidIndexMax) {
666 return;
667 }
668
669 state[aruid_index].npad_revision = revision;
670}
671
672Result NPadResource::SetNpadSystemExtStateEnabled(u64 aruid, bool is_enabled) {
673 const u64 aruid_index = GetIndexFromAruid(aruid);
674 if (aruid_index >= AruidIndexMax) {
675 return ResultNpadNotConnected;
676 }
677
678 state[aruid_index].data.SetNpadAnalogStickUseCenterClamp(is_enabled);
679 if (active_data_aruid == aruid) {
680 active_data.SetNpadAnalogStickUseCenterClamp(is_enabled);
681 }
682 return ResultSuccess;
683}
684
685} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad/npad_resource.h b/src/core/hle/service/hid/controllers/npad/npad_resource.h
deleted file mode 100644
index 4c7e6ab0e..000000000
--- a/src/core/hle/service/hid/controllers/npad/npad_resource.h
+++ /dev/null
@@ -1,132 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7#include <mutex>
8#include <span>
9
10#include "common/common_types.h"
11#include "core/hid/hid_types.h"
12#include "core/hle/result.h"
13#include "core/hle/service/hid/controllers/applet_resource.h"
14#include "core/hle/service/hid/controllers/npad/npad_data.h"
15#include "core/hle/service/hid/controllers/types/npad_types.h"
16#include "core/hle/service/kernel_helpers.h"
17
18namespace Core {
19class System;
20}
21
22namespace Kernel {
23class KReadableEvent;
24}
25
26namespace Service::HID {
27struct DataStatusFlag;
28
29struct NpadControllerState {
30 bool is_styleset_update_event_initialized{};
31 INSERT_PADDING_BYTES(0x7);
32 Kernel::KEvent* style_set_update_event{nullptr};
33 INSERT_PADDING_BYTES(0x27);
34};
35
36struct NpadState {
37 DataStatusFlag flag{};
38 u64 aruid{};
39 NPadData data{};
40 std::array<std::array<Core::HID::NpadButton, StyleIndexCount>, MaxSupportedNpadIdTypes>
41 button_config;
42 std::array<NpadControllerState, MaxSupportedNpadIdTypes> controller_state;
43 NpadRevision npad_revision;
44};
45
46/// Handles Npad request from HID interfaces
47class NPadResource final {
48public:
49 explicit NPadResource(KernelHelpers::ServiceContext& context);
50 ~NPadResource();
51
52 NPadData* GetActiveData();
53 u64 GetActiveDataAruid();
54
55 Result RegisterAppletResourceUserId(u64 aruid);
56 void UnregisterAppletResourceUserId(u64 aruid);
57
58 void DestroyStyleSetUpdateEvents(u64 aruid);
59
60 Result Activate(u64 aruid);
61 Result Activate();
62 Result Deactivate();
63
64 void SetAppletResourceUserId(u64 aruid);
65 std::size_t GetIndexFromAruid(u64 aruid) const;
66
67 Result ApplyNpadSystemCommonPolicy(u64 aruid, bool is_full_policy);
68 Result ClearNpadSystemCommonPolicy(u64 aruid);
69
70 Result SetSupportedNpadStyleSet(u64 aruid, Core::HID::NpadStyleSet style_set);
71 Result GetSupportedNpadStyleSet(Core::HID::NpadStyleSet& out_style_Set, u64 aruid) const;
72 Result GetMaskedSupportedNpadStyleSet(Core::HID::NpadStyleSet& out_style_set, u64 aruid) const;
73 Result GetAvailableStyleset(Core::HID::NpadStyleSet& out_style_set, u64 aruid) const;
74
75 NpadRevision GetNpadRevision(u64 aruid) const;
76 void SetNpadRevision(u64 aruid, NpadRevision revision);
77
78 Result IsSupportedNpadStyleSet(bool& is_set, u64 aruid);
79
80 Result SetNpadJoyHoldType(u64 aruid, NpadJoyHoldType hold_type);
81 Result GetNpadJoyHoldType(NpadJoyHoldType& hold_type, u64 aruid) const;
82
83 Result SetNpadHandheldActivationMode(u64 aruid, NpadHandheldActivationMode activation_mode);
84 Result GetNpadHandheldActivationMode(NpadHandheldActivationMode& activation_mode,
85 u64 aruid) const;
86
87 Result SetSupportedNpadIdType(u64 aruid,
88 std::span<const Core::HID::NpadIdType> supported_npad_list);
89 bool IsControllerSupported(u64 aruid, Core::HID::NpadStyleIndex style_index) const;
90
91 Result SetLrAssignmentMode(u64 aruid, bool is_enabled);
92 Result GetLrAssignmentMode(bool& is_enabled, u64 aruid) const;
93
94 Result SetAssigningSingleOnSlSrPress(u64 aruid, bool is_enabled);
95 Result IsAssigningSingleOnSlSrPressEnabled(bool& is_enabled, u64 aruid) const;
96
97 Result AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event,
98 Core::HID::NpadIdType npad_id);
99 Result SignalStyleSetUpdateEvent(u64 aruid, Core::HID::NpadIdType npad_id);
100
101 Result GetHomeProtectionEnabled(bool& is_enabled, u64 aruid,
102 Core::HID::NpadIdType npad_id) const;
103 Result SetHomeProtectionEnabled(u64 aruid, Core::HID::NpadIdType npad_id, bool is_enabled);
104
105 Result SetNpadAnalogStickUseCenterClamp(u64 aruid, bool is_enabled);
106
107 Result SetButtonConfig(u64 aruid, Core::HID::NpadIdType npad_id, std::size_t index,
108 Core::HID::NpadButton button_config);
109 Core::HID::NpadButton GetButtonConfig(u64 aruid, Core::HID::NpadIdType npad_id,
110 std::size_t index, Core::HID::NpadButton mask,
111 bool is_enabled);
112 void ResetButtonConfig();
113
114 Result SetNpadCaptureButtonAssignment(u64 aruid, Core::HID::NpadStyleSet npad_style_set,
115 Core::HID::NpadButton button_assignment);
116 Result ClearNpadCaptureButtonAssignment(u64 aruid);
117 std::size_t GetNpadCaptureButtonAssignment(std::span<Core::HID::NpadButton> out_list,
118 u64 aruid) const;
119
120 Result SetNpadSystemExtStateEnabled(u64 aruid, bool is_enabled);
121
122private:
123 NPadData active_data{};
124 AruidRegisterList registration_list{};
125 std::array<NpadState, AruidIndexMax> state{};
126 u64 active_data_aruid{};
127 NpadJoyHoldType default_hold_type{};
128 s32 ref_counter{};
129
130 KernelHelpers::ServiceContext& service_context;
131};
132} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/palma.cpp b/src/core/hle/service/hid/controllers/palma.cpp
deleted file mode 100644
index aa0454b5e..000000000
--- a/src/core/hle/service/hid/controllers/palma.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core_timing.h"
5#include "core/hid/emulated_controller.h"
6#include "core/hid/hid_core.h"
7#include "core/hid/hid_types.h"
8#include "core/hle/kernel/k_event.h"
9#include "core/hle/kernel/k_readable_event.h"
10#include "core/hle/service/hid/controllers/palma.h"
11#include "core/hle/service/kernel_helpers.h"
12
13namespace Service::HID {
14
15Palma::Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_)
16 : ControllerBase{hid_core_}, service_context{service_context_} {
17 controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
18 operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent");
19}
20
21Palma::~Palma() {
22 service_context.CloseEvent(operation_complete_event);
23};
24
25void Palma::OnInit() {}
26
27void Palma::OnRelease() {}
28
29void Palma::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
30 if (!IsControllerActivated()) {
31 return;
32 }
33}
34
35Result Palma::GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id,
36 PalmaConnectionHandle& handle) {
37 active_handle.npad_id = npad_id;
38 handle = active_handle;
39 return ResultSuccess;
40}
41
42Result Palma::InitializePalma(const PalmaConnectionHandle& handle) {
43 if (handle.npad_id != active_handle.npad_id) {
44 return InvalidPalmaHandle;
45 }
46 Activate();
47 return ResultSuccess;
48}
49
50Kernel::KReadableEvent& Palma::AcquirePalmaOperationCompleteEvent(
51 const PalmaConnectionHandle& handle) const {
52 if (handle.npad_id != active_handle.npad_id) {
53 LOG_ERROR(Service_HID, "Invalid npad id {}", handle.npad_id);
54 }
55 return operation_complete_event->GetReadableEvent();
56}
57
58Result Palma::GetPalmaOperationInfo(const PalmaConnectionHandle& handle,
59 PalmaOperationType& operation_type,
60 PalmaOperationData& data) const {
61 if (handle.npad_id != active_handle.npad_id) {
62 return InvalidPalmaHandle;
63 }
64 operation_type = operation.operation;
65 data = operation.data;
66 return ResultSuccess;
67}
68
69Result Palma::PlayPalmaActivity(const PalmaConnectionHandle& handle, u64 palma_activity) {
70 if (handle.npad_id != active_handle.npad_id) {
71 return InvalidPalmaHandle;
72 }
73 operation.operation = PalmaOperationType::PlayActivity;
74 operation.result = PalmaResultSuccess;
75 operation.data = {};
76 operation_complete_event->Signal();
77 return ResultSuccess;
78}
79
80Result Palma::SetPalmaFrModeType(const PalmaConnectionHandle& handle, PalmaFrModeType fr_mode_) {
81 if (handle.npad_id != active_handle.npad_id) {
82 return InvalidPalmaHandle;
83 }
84 fr_mode = fr_mode_;
85 return ResultSuccess;
86}
87
88Result Palma::ReadPalmaStep(const PalmaConnectionHandle& handle) {
89 if (handle.npad_id != active_handle.npad_id) {
90 return InvalidPalmaHandle;
91 }
92 operation.operation = PalmaOperationType::ReadStep;
93 operation.result = PalmaResultSuccess;
94 operation.data = {};
95 operation_complete_event->Signal();
96 return ResultSuccess;
97}
98
99Result Palma::EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled) {
100 if (handle.npad_id != active_handle.npad_id) {
101 return InvalidPalmaHandle;
102 }
103 return ResultSuccess;
104}
105
106Result Palma::ResetPalmaStep(const PalmaConnectionHandle& handle) {
107 if (handle.npad_id != active_handle.npad_id) {
108 return InvalidPalmaHandle;
109 }
110 return ResultSuccess;
111}
112
113void Palma::ReadPalmaApplicationSection() {}
114
115void Palma::WritePalmaApplicationSection() {}
116
117Result Palma::ReadPalmaUniqueCode(const PalmaConnectionHandle& handle) {
118 if (handle.npad_id != active_handle.npad_id) {
119 return InvalidPalmaHandle;
120 }
121 operation.operation = PalmaOperationType::ReadUniqueCode;
122 operation.result = PalmaResultSuccess;
123 operation.data = {};
124 operation_complete_event->Signal();
125 return ResultSuccess;
126}
127
128Result Palma::SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle) {
129 if (handle.npad_id != active_handle.npad_id) {
130 return InvalidPalmaHandle;
131 }
132 operation.operation = PalmaOperationType::SetUniqueCodeInvalid;
133 operation.result = PalmaResultSuccess;
134 operation.data = {};
135 operation_complete_event->Signal();
136 return ResultSuccess;
137}
138
139void Palma::WritePalmaActivityEntry() {}
140
141Result Palma::WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle, u64 unknown) {
142 if (handle.npad_id != active_handle.npad_id) {
143 return InvalidPalmaHandle;
144 }
145 operation.operation = PalmaOperationType::WriteRgbLedPatternEntry;
146 operation.result = PalmaResultSuccess;
147 operation.data = {};
148 operation_complete_event->Signal();
149 return ResultSuccess;
150}
151
152Result Palma::WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave,
153 Common::ProcessAddress t_mem, u64 size) {
154 if (handle.npad_id != active_handle.npad_id) {
155 return InvalidPalmaHandle;
156 }
157 operation.operation = PalmaOperationType::WriteWaveEntry;
158 operation.result = PalmaResultSuccess;
159 operation.data = {};
160 operation_complete_event->Signal();
161 return ResultSuccess;
162}
163
164Result Palma::SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle,
165 s32 database_id_version_) {
166 if (handle.npad_id != active_handle.npad_id) {
167 return InvalidPalmaHandle;
168 }
169 database_id_version = database_id_version_;
170 operation.operation = PalmaOperationType::ReadDataBaseIdentificationVersion;
171 operation.result = PalmaResultSuccess;
172 operation.data[0] = {};
173 operation_complete_event->Signal();
174 return ResultSuccess;
175}
176
177Result Palma::GetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle) {
178 if (handle.npad_id != active_handle.npad_id) {
179 return InvalidPalmaHandle;
180 }
181 operation.operation = PalmaOperationType::ReadDataBaseIdentificationVersion;
182 operation.result = PalmaResultSuccess;
183 operation.data = {};
184 operation.data[0] = static_cast<u8>(database_id_version);
185 operation_complete_event->Signal();
186 return ResultSuccess;
187}
188
189void Palma::SuspendPalmaFeature() {}
190
191Result Palma::GetPalmaOperationResult(const PalmaConnectionHandle& handle) const {
192 if (handle.npad_id != active_handle.npad_id) {
193 return InvalidPalmaHandle;
194 }
195 return operation.result;
196}
197void Palma::ReadPalmaPlayLog() {}
198
199void Palma::ResetPalmaPlayLog() {}
200
201void Palma::SetIsPalmaAllConnectable(bool is_all_connectable) {
202 // If true controllers are able to be paired
203 is_connectable = is_all_connectable;
204}
205
206void Palma::SetIsPalmaPairedConnectable() {}
207
208Result Palma::PairPalma(const PalmaConnectionHandle& handle) {
209 if (handle.npad_id != active_handle.npad_id) {
210 return InvalidPalmaHandle;
211 }
212 // TODO: Do something
213 return ResultSuccess;
214}
215
216void Palma::SetPalmaBoostMode(bool boost_mode) {}
217
218void Palma::CancelWritePalmaWaveEntry() {}
219
220void Palma::EnablePalmaBoostMode() {}
221
222void Palma::GetPalmaBluetoothAddress() {}
223
224void Palma::SetDisallowedPalmaConnection() {}
225
226} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/palma.h b/src/core/hle/service/hid/controllers/palma.h
deleted file mode 100644
index 73884230d..000000000
--- a/src/core/hle/service/hid/controllers/palma.h
+++ /dev/null
@@ -1,162 +0,0 @@
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 "common/common_funcs.h"
8#include "common/typed_address.h"
9#include "core/hle/service/hid/controllers/controller_base.h"
10#include "core/hle/service/hid/errors.h"
11
12namespace Kernel {
13class KEvent;
14class KReadableEvent;
15} // namespace Kernel
16
17namespace Service::KernelHelpers {
18class ServiceContext;
19}
20
21namespace Core::HID {
22class EmulatedController;
23} // namespace Core::HID
24
25namespace Service::HID {
26class Palma final : public ControllerBase {
27public:
28 using PalmaOperationData = std::array<u8, 0x140>;
29
30 // This is nn::hid::PalmaOperationType
31 enum class PalmaOperationType {
32 PlayActivity,
33 SetFrModeType,
34 ReadStep,
35 EnableStep,
36 ResetStep,
37 ReadApplicationSection,
38 WriteApplicationSection,
39 ReadUniqueCode,
40 SetUniqueCodeInvalid,
41 WriteActivityEntry,
42 WriteRgbLedPatternEntry,
43 WriteWaveEntry,
44 ReadDataBaseIdentificationVersion,
45 WriteDataBaseIdentificationVersion,
46 SuspendFeature,
47 ReadPlayLog,
48 ResetPlayLog,
49 };
50
51 // This is nn::hid::PalmaWaveSet
52 enum class PalmaWaveSet : u64 {
53 Small,
54 Medium,
55 Large,
56 };
57
58 // This is nn::hid::PalmaFrModeType
59 enum class PalmaFrModeType : u64 {
60 Off,
61 B01,
62 B02,
63 B03,
64 Downloaded,
65 };
66
67 // This is nn::hid::PalmaFeature
68 enum class PalmaFeature : u64 {
69 FrMode,
70 RumbleFeedback,
71 Step,
72 MuteSwitch,
73 };
74
75 // This is nn::hid::PalmaOperationInfo
76 struct PalmaOperationInfo {
77 PalmaOperationType operation{};
78 Result result{PalmaResultSuccess};
79 PalmaOperationData data{};
80 };
81 static_assert(sizeof(PalmaOperationInfo) == 0x148, "PalmaOperationInfo is an invalid size");
82
83 // This is nn::hid::PalmaActivityEntry
84 struct PalmaActivityEntry {
85 u32 rgb_led_pattern_index;
86 INSERT_PADDING_BYTES(2);
87 PalmaWaveSet wave_set;
88 u32 wave_index;
89 INSERT_PADDING_BYTES(12);
90 };
91 static_assert(sizeof(PalmaActivityEntry) == 0x20, "PalmaActivityEntry is an invalid size");
92
93 struct PalmaConnectionHandle {
94 Core::HID::NpadIdType npad_id;
95 INSERT_PADDING_BYTES(4); // Unknown
96 };
97 static_assert(sizeof(PalmaConnectionHandle) == 0x8,
98 "PalmaConnectionHandle has incorrect size.");
99
100 explicit Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_);
101 ~Palma() override;
102
103 // Called when the controller is initialized
104 void OnInit() override;
105
106 // When the controller is released
107 void OnRelease() override;
108
109 // When the controller is requesting an update for the shared memory
110 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
111
112 Result GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id, PalmaConnectionHandle& handle);
113 Result InitializePalma(const PalmaConnectionHandle& handle);
114 Kernel::KReadableEvent& AcquirePalmaOperationCompleteEvent(
115 const PalmaConnectionHandle& handle) const;
116 Result GetPalmaOperationInfo(const PalmaConnectionHandle& handle,
117 PalmaOperationType& operation_type,
118 PalmaOperationData& data) const;
119 Result PlayPalmaActivity(const PalmaConnectionHandle& handle, u64 palma_activity);
120 Result SetPalmaFrModeType(const PalmaConnectionHandle& handle, PalmaFrModeType fr_mode_);
121 Result ReadPalmaStep(const PalmaConnectionHandle& handle);
122 Result EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled);
123 Result ResetPalmaStep(const PalmaConnectionHandle& handle);
124 Result ReadPalmaUniqueCode(const PalmaConnectionHandle& handle);
125 Result SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle);
126 Result WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle, u64 unknown);
127 Result WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave,
128 Common::ProcessAddress t_mem, u64 size);
129 Result SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle,
130 s32 database_id_version_);
131 Result GetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle);
132 Result GetPalmaOperationResult(const PalmaConnectionHandle& handle) const;
133 void SetIsPalmaAllConnectable(bool is_all_connectable);
134 Result PairPalma(const PalmaConnectionHandle& handle);
135 void SetPalmaBoostMode(bool boost_mode);
136
137private:
138 void ReadPalmaApplicationSection();
139 void WritePalmaApplicationSection();
140 void WritePalmaActivityEntry();
141 void SuspendPalmaFeature();
142 void ReadPalmaPlayLog();
143 void ResetPalmaPlayLog();
144 void SetIsPalmaPairedConnectable();
145 void CancelWritePalmaWaveEntry();
146 void EnablePalmaBoostMode();
147 void GetPalmaBluetoothAddress();
148 void SetDisallowedPalmaConnection();
149
150 bool is_connectable{};
151 s32 database_id_version{};
152 PalmaOperationInfo operation{};
153 PalmaFrModeType fr_mode{};
154 PalmaConnectionHandle active_handle{};
155
156 Core::HID::EmulatedController* controller;
157
158 Kernel::KEvent* operation_complete_event;
159 KernelHelpers::ServiceContext& service_context;
160};
161
162} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/seven_six_axis.cpp b/src/core/hle/service/hid/controllers/seven_six_axis.cpp
deleted file mode 100644
index 495568484..000000000
--- a/src/core/hle/service/hid/controllers/seven_six_axis.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <cstring>
5#include "common/common_types.h"
6#include "core/core.h"
7#include "core/core_timing.h"
8#include "core/frontend/emu_window.h"
9#include "core/hid/emulated_console.h"
10#include "core/hid/emulated_devices.h"
11#include "core/hid/hid_core.h"
12#include "core/hle/service/hid/controllers/seven_six_axis.h"
13#include "core/memory.h"
14
15namespace Service::HID {
16SevenSixAxis::SevenSixAxis(Core::System& system_)
17 : ControllerBase{system_.HIDCore()}, system{system_} {
18 console = hid_core.GetEmulatedConsole();
19}
20
21SevenSixAxis::~SevenSixAxis() = default;
22
23void SevenSixAxis::OnInit() {}
24void SevenSixAxis::OnRelease() {}
25
26void SevenSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
27 if (!IsControllerActivated() || transfer_memory == 0) {
28 seven_sixaxis_lifo.buffer_count = 0;
29 seven_sixaxis_lifo.buffer_tail = 0;
30 return;
31 }
32
33 const auto& last_entry = seven_sixaxis_lifo.ReadCurrentEntry().state;
34 next_seven_sixaxis_state.sampling_number = last_entry.sampling_number + 1;
35
36 const auto motion_status = console->GetMotion();
37 last_global_timestamp = core_timing.GetGlobalTimeNs().count();
38
39 // This value increments every time the switch goes to sleep
40 next_seven_sixaxis_state.unknown = 1;
41 next_seven_sixaxis_state.timestamp = last_global_timestamp - last_saved_timestamp;
42 next_seven_sixaxis_state.accel = motion_status.accel;
43 next_seven_sixaxis_state.gyro = motion_status.gyro;
44 next_seven_sixaxis_state.quaternion = {
45 {
46 motion_status.quaternion.xyz.y,
47 motion_status.quaternion.xyz.x,
48 -motion_status.quaternion.w,
49 },
50 -motion_status.quaternion.xyz.z,
51 };
52
53 seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state);
54 system.ApplicationMemory().WriteBlock(transfer_memory, &seven_sixaxis_lifo,
55 sizeof(seven_sixaxis_lifo));
56}
57
58void SevenSixAxis::SetTransferMemoryAddress(Common::ProcessAddress t_mem) {
59 transfer_memory = t_mem;
60}
61
62void SevenSixAxis::ResetTimestamp() {
63 last_saved_timestamp = last_global_timestamp;
64}
65
66} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/seven_six_axis.h b/src/core/hle/service/hid/controllers/seven_six_axis.h
deleted file mode 100644
index 40e3f5d12..000000000
--- a/src/core/hle/service/hid/controllers/seven_six_axis.h
+++ /dev/null
@@ -1,65 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "common/quaternion.h"
8#include "common/typed_address.h"
9#include "core/hle/service/hid/controllers/controller_base.h"
10#include "core/hle/service/hid/ring_lifo.h"
11
12namespace Core {
13class System;
14} // namespace Core
15
16namespace Core::HID {
17class EmulatedConsole;
18} // namespace Core::HID
19
20namespace Service::HID {
21class SevenSixAxis final : public ControllerBase {
22public:
23 explicit SevenSixAxis(Core::System& system_);
24 ~SevenSixAxis() override;
25
26 // Called when the controller is initialized
27 void OnInit() override;
28
29 // When the controller is released
30 void OnRelease() override;
31
32 // When the controller is requesting an update for the shared memory
33 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
34
35 // Called on InitializeSevenSixAxisSensor
36 void SetTransferMemoryAddress(Common::ProcessAddress t_mem);
37
38 // Called on ResetSevenSixAxisSensorTimestamp
39 void ResetTimestamp();
40
41private:
42 struct SevenSixAxisState {
43 INSERT_PADDING_WORDS(2); // unused
44 u64 timestamp{};
45 u64 sampling_number{};
46 u64 unknown{};
47 Common::Vec3f accel{};
48 Common::Vec3f gyro{};
49 Common::Quaternion<f32> quaternion{};
50 };
51 static_assert(sizeof(SevenSixAxisState) == 0x48, "SevenSixAxisState is an invalid size");
52
53 Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{};
54 static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size");
55
56 u64 last_saved_timestamp{};
57 u64 last_global_timestamp{};
58
59 SevenSixAxisState next_seven_sixaxis_state{};
60 Common::ProcessAddress transfer_memory{};
61 Core::HID::EmulatedConsole* console = nullptr;
62
63 Core::System& system;
64};
65} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/shared_memory_holder.cpp b/src/core/hle/service/hid/controllers/shared_memory_holder.cpp
deleted file mode 100644
index 0bc5169c6..000000000
--- a/src/core/hle/service/hid/controllers/shared_memory_holder.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/core.h"
5#include "core/hle/kernel/k_shared_memory.h"
6#include "core/hle/service/hid/controllers/applet_resource.h"
7#include "core/hle/service/hid/controllers/shared_memory_holder.h"
8#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
9#include "core/hle/service/hid/errors.h"
10
11namespace Service::HID {
12SharedMemoryHolder::SharedMemoryHolder() {}
13
14SharedMemoryHolder::~SharedMemoryHolder() {
15 Finalize();
16}
17
18Result SharedMemoryHolder::Initialize(Core::System& system) {
19 shared_memory = Kernel::KSharedMemory::Create(system.Kernel());
20 const Result result = shared_memory->Initialize(
21 system.DeviceMemory(), nullptr, Kernel::Svc::MemoryPermission::None,
22 Kernel::Svc::MemoryPermission::Read, sizeof(SharedMemoryFormat));
23 if (result.IsError()) {
24 return result;
25 }
26 Kernel::KSharedMemory::Register(system.Kernel(), shared_memory);
27
28 is_created = true;
29 is_mapped = true;
30 address = std::construct_at(reinterpret_cast<SharedMemoryFormat*>(shared_memory->GetPointer()));
31 return ResultSuccess;
32}
33
34void SharedMemoryHolder::Finalize() {
35 if (address != nullptr) {
36 shared_memory->Close();
37 }
38 is_created = false;
39 is_mapped = false;
40 address = nullptr;
41}
42
43bool SharedMemoryHolder::IsMapped() {
44 return is_mapped;
45}
46
47SharedMemoryFormat* SharedMemoryHolder::GetAddress() {
48 return address;
49}
50
51Kernel::KSharedMemory* SharedMemoryHolder::GetHandle() {
52 return shared_memory;
53}
54} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/shared_memory_holder.h b/src/core/hle/service/hid/controllers/shared_memory_holder.h
deleted file mode 100644
index 943407c00..000000000
--- a/src/core/hle/service/hid/controllers/shared_memory_holder.h
+++ /dev/null
@@ -1,44 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Core {
9class System;
10}
11
12namespace Kernel {
13class KSharedMemory;
14}
15
16namespace Service::HID {
17struct SharedMemoryFormat;
18
19// This is nn::hid::detail::SharedMemoryHolder
20class SharedMemoryHolder {
21public:
22 SharedMemoryHolder();
23 ~SharedMemoryHolder();
24
25 Result Initialize(Core::System& system);
26 void Finalize();
27
28 bool IsMapped();
29 SharedMemoryFormat* GetAddress();
30 Kernel::KSharedMemory* GetHandle();
31
32private:
33 bool is_owner{};
34 bool is_created{};
35 bool is_mapped{};
36 INSERT_PADDING_BYTES(0x5);
37 Kernel::KSharedMemory* shared_memory;
38 INSERT_PADDING_BYTES(0x38);
39 SharedMemoryFormat* address = nullptr;
40};
41// Correct size is 0x50 bytes
42static_assert(sizeof(SharedMemoryHolder) == 0x50, "SharedMemoryHolder is an invalid size");
43
44} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/six_axis.cpp b/src/core/hle/service/hid/controllers/six_axis.cpp
deleted file mode 100644
index adab60911..000000000
--- a/src/core/hle/service/hid/controllers/six_axis.cpp
+++ /dev/null
@@ -1,421 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/common_types.h"
5#include "core/core_timing.h"
6#include "core/hid/emulated_controller.h"
7#include "core/hid/hid_core.h"
8#include "core/hle/service/hid/controllers/npad.h"
9#include "core/hle/service/hid/controllers/six_axis.h"
10#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
11#include "core/hle/service/hid/errors.h"
12#include "core/hle/service/hid/hid_util.h"
13
14namespace Service::HID {
15
16SixAxis::SixAxis(Core::HID::HIDCore& hid_core_, std::shared_ptr<NPad> npad_)
17 : ControllerBase{hid_core_}, npad{npad_} {
18 for (std::size_t i = 0; i < controller_data.size(); ++i) {
19 auto& controller = controller_data[i];
20 controller.device = hid_core.GetEmulatedControllerByIndex(i);
21 }
22}
23
24SixAxis::~SixAxis() = default;
25
26void SixAxis::OnInit() {}
27void SixAxis::OnRelease() {}
28
29void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
30 std::scoped_lock shared_lock{*shared_mutex};
31 const u64 aruid = applet_resource->GetActiveAruid();
32 auto* data = applet_resource->GetAruidData(aruid);
33
34 if (data == nullptr || !data->flag.is_assigned) {
35 return;
36 }
37
38 if (!IsControllerActivated()) {
39 return;
40 }
41
42 for (std::size_t i = 0; i < controller_data.size(); ++i) {
43 NpadSharedMemoryEntry& shared_memory = data->shared_memory_format->npad.npad_entry[i];
44 auto& controller = controller_data[i];
45 const auto& controller_type = controller.device->GetNpadStyleIndex();
46
47 if (controller_type == Core::HID::NpadStyleIndex::None ||
48 !controller.device->IsConnected()) {
49 continue;
50 }
51
52 const auto& motion_state = controller.device->GetMotions();
53 auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state;
54 auto& sixaxis_handheld_state = controller.sixaxis_handheld_state;
55 auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state;
56 auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state;
57 auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state;
58 auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state;
59
60 auto& sixaxis_fullkey_lifo = shared_memory.internal_state.sixaxis_fullkey_lifo;
61 auto& sixaxis_handheld_lifo = shared_memory.internal_state.sixaxis_handheld_lifo;
62 auto& sixaxis_dual_left_lifo = shared_memory.internal_state.sixaxis_dual_left_lifo;
63 auto& sixaxis_dual_right_lifo = shared_memory.internal_state.sixaxis_dual_right_lifo;
64 auto& sixaxis_left_lifo = shared_memory.internal_state.sixaxis_left_lifo;
65 auto& sixaxis_right_lifo = shared_memory.internal_state.sixaxis_right_lifo;
66
67 // Clear previous state
68 sixaxis_fullkey_state = {};
69 sixaxis_handheld_state = {};
70 sixaxis_dual_left_state = {};
71 sixaxis_dual_right_state = {};
72 sixaxis_left_lifo_state = {};
73 sixaxis_right_lifo_state = {};
74
75 if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) {
76 controller.sixaxis_at_rest = true;
77 for (std::size_t e = 0; e < motion_state.size(); ++e) {
78 controller.sixaxis_at_rest =
79 controller.sixaxis_at_rest && motion_state[e].is_at_rest;
80 }
81 }
82
83 const auto set_motion_state = [&](Core::HID::SixAxisSensorState& state,
84 const Core::HID::ControllerMotion& hid_state) {
85 using namespace std::literals::chrono_literals;
86 static constexpr Core::HID::SixAxisSensorState default_motion_state = {
87 .delta_time = std::chrono::nanoseconds(5ms).count(),
88 .accel = {0, 0, -1.0f},
89 .orientation =
90 {
91 Common::Vec3f{1.0f, 0, 0},
92 Common::Vec3f{0, 1.0f, 0},
93 Common::Vec3f{0, 0, 1.0f},
94 },
95 .attribute = {1},
96 };
97 if (!controller.sixaxis_sensor_enabled) {
98 state = default_motion_state;
99 return;
100 }
101 if (!Settings::values.motion_enabled.GetValue()) {
102 state = default_motion_state;
103 return;
104 }
105 state.attribute.is_connected.Assign(1);
106 state.delta_time = std::chrono::nanoseconds(5ms).count();
107 state.accel = hid_state.accel;
108 state.gyro = hid_state.gyro;
109 state.rotation = hid_state.rotation;
110 state.orientation = hid_state.orientation;
111 };
112
113 switch (controller_type) {
114 case Core::HID::NpadStyleIndex::None:
115 ASSERT(false);
116 break;
117 case Core::HID::NpadStyleIndex::ProController:
118 set_motion_state(sixaxis_fullkey_state, motion_state[0]);
119 break;
120 case Core::HID::NpadStyleIndex::Handheld:
121 set_motion_state(sixaxis_handheld_state, motion_state[0]);
122 break;
123 case Core::HID::NpadStyleIndex::JoyconDual:
124 set_motion_state(sixaxis_dual_left_state, motion_state[0]);
125 set_motion_state(sixaxis_dual_right_state, motion_state[1]);
126 break;
127 case Core::HID::NpadStyleIndex::JoyconLeft:
128 set_motion_state(sixaxis_left_lifo_state, motion_state[0]);
129 break;
130 case Core::HID::NpadStyleIndex::JoyconRight:
131 set_motion_state(sixaxis_right_lifo_state, motion_state[1]);
132 break;
133 case Core::HID::NpadStyleIndex::Pokeball:
134 using namespace std::literals::chrono_literals;
135 set_motion_state(sixaxis_fullkey_state, motion_state[0]);
136 sixaxis_fullkey_state.delta_time = std::chrono::nanoseconds(15ms).count();
137 break;
138 default:
139 break;
140 }
141
142 sixaxis_fullkey_state.sampling_number =
143 sixaxis_fullkey_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
144 sixaxis_handheld_state.sampling_number =
145 sixaxis_handheld_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
146 sixaxis_dual_left_state.sampling_number =
147 sixaxis_dual_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
148 sixaxis_dual_right_state.sampling_number =
149 sixaxis_dual_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
150 sixaxis_left_lifo_state.sampling_number =
151 sixaxis_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
152 sixaxis_right_lifo_state.sampling_number =
153 sixaxis_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
154
155 if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
156 // This buffer only is updated on handheld on HW
157 sixaxis_handheld_lifo.lifo.WriteNextEntry(sixaxis_handheld_state);
158 } else {
159 // Handheld doesn't update this buffer on HW
160 sixaxis_fullkey_lifo.lifo.WriteNextEntry(sixaxis_fullkey_state);
161 }
162
163 sixaxis_dual_left_lifo.lifo.WriteNextEntry(sixaxis_dual_left_state);
164 sixaxis_dual_right_lifo.lifo.WriteNextEntry(sixaxis_dual_right_state);
165 sixaxis_left_lifo.lifo.WriteNextEntry(sixaxis_left_lifo_state);
166 sixaxis_right_lifo.lifo.WriteNextEntry(sixaxis_right_lifo_state);
167 }
168}
169
170Result SixAxis::SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
171 Core::HID::GyroscopeZeroDriftMode drift_mode) {
172 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
173 if (is_valid.IsError()) {
174 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
175 return is_valid;
176 }
177
178 auto& sixaxis = GetSixaxisState(sixaxis_handle);
179 auto& controller = GetControllerFromHandle(sixaxis_handle);
180 sixaxis.gyroscope_zero_drift_mode = drift_mode;
181 controller.device->SetGyroscopeZeroDriftMode(drift_mode);
182
183 return ResultSuccess;
184}
185
186Result SixAxis::GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
187 Core::HID::GyroscopeZeroDriftMode& drift_mode) const {
188 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
189 if (is_valid.IsError()) {
190 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
191 return is_valid;
192 }
193
194 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
195 drift_mode = sixaxis.gyroscope_zero_drift_mode;
196
197 return ResultSuccess;
198}
199
200Result SixAxis::IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
201 bool& is_at_rest) const {
202 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
203 if (is_valid.IsError()) {
204 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
205 return is_valid;
206 }
207
208 const auto& controller = GetControllerFromHandle(sixaxis_handle);
209 is_at_rest = controller.sixaxis_at_rest;
210 return ResultSuccess;
211}
212
213Result SixAxis::LoadSixAxisSensorCalibrationParameter(
214 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
215 Core::HID::SixAxisSensorCalibrationParameter& calibration) const {
216 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
217 if (is_valid.IsError()) {
218 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
219 return is_valid;
220 }
221
222 // TODO: Request this data to the controller. On error return 0xd8ca
223 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
224 calibration = sixaxis.calibration;
225 return ResultSuccess;
226}
227
228Result SixAxis::GetSixAxisSensorIcInformation(
229 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
230 Core::HID::SixAxisSensorIcInformation& ic_information) const {
231 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
232 if (is_valid.IsError()) {
233 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
234 return is_valid;
235 }
236
237 // TODO: Request this data to the controller. On error return 0xd8ca
238 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
239 ic_information = sixaxis.ic_information;
240 return ResultSuccess;
241}
242
243Result SixAxis::EnableSixAxisSensorUnalteredPassthrough(
244 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled) {
245 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
246 if (is_valid.IsError()) {
247 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
248 return is_valid;
249 }
250
251 auto& sixaxis = GetSixaxisState(sixaxis_handle);
252 sixaxis.unaltered_passtrough = is_enabled;
253 return ResultSuccess;
254}
255
256Result SixAxis::IsSixAxisSensorUnalteredPassthroughEnabled(
257 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const {
258 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
259 if (is_valid.IsError()) {
260 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
261 return is_valid;
262 }
263
264 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
265 is_enabled = sixaxis.unaltered_passtrough;
266 return ResultSuccess;
267}
268
269Result SixAxis::SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
270 bool sixaxis_status) {
271 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
272 if (is_valid.IsError()) {
273 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
274 return is_valid;
275 }
276
277 auto& controller = GetControllerFromHandle(sixaxis_handle);
278 controller.sixaxis_sensor_enabled = sixaxis_status;
279 return ResultSuccess;
280}
281
282Result SixAxis::IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
283 bool& is_fusion_enabled) const {
284 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
285 if (is_valid.IsError()) {
286 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
287 return is_valid;
288 }
289
290 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
291 is_fusion_enabled = sixaxis.is_fusion_enabled;
292
293 return ResultSuccess;
294}
295Result SixAxis::SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
296 bool is_fusion_enabled) {
297 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
298 if (is_valid.IsError()) {
299 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
300 return is_valid;
301 }
302
303 auto& sixaxis = GetSixaxisState(sixaxis_handle);
304 sixaxis.is_fusion_enabled = is_fusion_enabled;
305
306 return ResultSuccess;
307}
308
309Result SixAxis::SetSixAxisFusionParameters(
310 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
311 Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) {
312 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
313 if (is_valid.IsError()) {
314 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
315 return is_valid;
316 }
317
318 const auto param1 = sixaxis_fusion_parameters.parameter1;
319 if (param1 < 0.0f || param1 > 1.0f) {
320 return InvalidSixAxisFusionRange;
321 }
322
323 auto& sixaxis = GetSixaxisState(sixaxis_handle);
324 sixaxis.fusion = sixaxis_fusion_parameters;
325
326 return ResultSuccess;
327}
328
329Result SixAxis::GetSixAxisFusionParameters(
330 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
331 Core::HID::SixAxisSensorFusionParameters& parameters) const {
332 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
333 if (is_valid.IsError()) {
334 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
335 return is_valid;
336 }
337
338 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
339 parameters = sixaxis.fusion;
340
341 return ResultSuccess;
342}
343
344SixAxis::SixaxisParameters& SixAxis::GetSixaxisState(
345 const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
346 auto& controller = GetControllerFromHandle(sixaxis_handle);
347 switch (sixaxis_handle.npad_type) {
348 case Core::HID::NpadStyleIndex::ProController:
349 case Core::HID::NpadStyleIndex::Pokeball:
350 return controller.sixaxis_fullkey;
351 case Core::HID::NpadStyleIndex::Handheld:
352 return controller.sixaxis_handheld;
353 case Core::HID::NpadStyleIndex::JoyconDual:
354 if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
355 return controller.sixaxis_dual_left;
356 }
357 return controller.sixaxis_dual_right;
358 case Core::HID::NpadStyleIndex::JoyconLeft:
359 return controller.sixaxis_left;
360 case Core::HID::NpadStyleIndex::JoyconRight:
361 return controller.sixaxis_right;
362 default:
363 return controller.sixaxis_unknown;
364 }
365}
366
367const SixAxis::SixaxisParameters& SixAxis::GetSixaxisState(
368 const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
369 const auto& controller = GetControllerFromHandle(sixaxis_handle);
370 switch (sixaxis_handle.npad_type) {
371 case Core::HID::NpadStyleIndex::ProController:
372 case Core::HID::NpadStyleIndex::Pokeball:
373 return controller.sixaxis_fullkey;
374 case Core::HID::NpadStyleIndex::Handheld:
375 return controller.sixaxis_handheld;
376 case Core::HID::NpadStyleIndex::JoyconDual:
377 if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
378 return controller.sixaxis_dual_left;
379 }
380 return controller.sixaxis_dual_right;
381 case Core::HID::NpadStyleIndex::JoyconLeft:
382 return controller.sixaxis_left;
383 case Core::HID::NpadStyleIndex::JoyconRight:
384 return controller.sixaxis_right;
385 default:
386 return controller.sixaxis_unknown;
387 }
388}
389
390SixAxis::NpadControllerData& SixAxis::GetControllerFromHandle(
391 const Core::HID::SixAxisSensorHandle& device_handle) {
392 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
393 return GetControllerFromNpadIdType(npad_id);
394}
395
396const SixAxis::NpadControllerData& SixAxis::GetControllerFromHandle(
397 const Core::HID::SixAxisSensorHandle& device_handle) const {
398 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
399 return GetControllerFromNpadIdType(npad_id);
400}
401
402SixAxis::NpadControllerData& SixAxis::GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) {
403 if (!IsNpadIdValid(npad_id)) {
404 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
405 npad_id = Core::HID::NpadIdType::Player1;
406 }
407 const auto npad_index = NpadIdTypeToIndex(npad_id);
408 return controller_data[npad_index];
409}
410
411const SixAxis::NpadControllerData& SixAxis::GetControllerFromNpadIdType(
412 Core::HID::NpadIdType npad_id) const {
413 if (!IsNpadIdValid(npad_id)) {
414 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
415 npad_id = Core::HID::NpadIdType::Player1;
416 }
417 const auto npad_index = NpadIdTypeToIndex(npad_id);
418 return controller_data[npad_index];
419}
420
421} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/six_axis.h b/src/core/hle/service/hid/controllers/six_axis.h
deleted file mode 100644
index 4c4f5dc7b..000000000
--- a/src/core/hle/service/hid/controllers/six_axis.h
+++ /dev/null
@@ -1,111 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hid/hid_types.h"
8#include "core/hle/service/hid/controllers/controller_base.h"
9#include "core/hle/service/hid/ring_lifo.h"
10
11namespace Core::HID {
12class EmulatedController;
13} // namespace Core::HID
14
15namespace Service::HID {
16class NPad;
17
18class SixAxis final : public ControllerBase {
19public:
20 explicit SixAxis(Core::HID::HIDCore& hid_core_, std::shared_ptr<NPad> npad_);
21 ~SixAxis() override;
22
23 // Called when the controller is initialized
24 void OnInit() override;
25
26 // When the controller is released
27 void OnRelease() override;
28
29 // When the controller is requesting an update for the shared memory
30 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
31
32 Result SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
33 Core::HID::GyroscopeZeroDriftMode drift_mode);
34 Result GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
35 Core::HID::GyroscopeZeroDriftMode& drift_mode) const;
36 Result IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
37 bool& is_at_rest) const;
38 Result EnableSixAxisSensorUnalteredPassthrough(
39 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled);
40 Result IsSixAxisSensorUnalteredPassthroughEnabled(
41 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const;
42 Result LoadSixAxisSensorCalibrationParameter(
43 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
44 Core::HID::SixAxisSensorCalibrationParameter& calibration) const;
45 Result GetSixAxisSensorIcInformation(
46 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
47 Core::HID::SixAxisSensorIcInformation& ic_information) const;
48 Result SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
49 bool sixaxis_status);
50 Result IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
51 bool& is_fusion_enabled) const;
52 Result SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
53 bool is_fusion_enabled);
54 Result SetSixAxisFusionParameters(
55 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
56 Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters);
57 Result GetSixAxisFusionParameters(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
58 Core::HID::SixAxisSensorFusionParameters& parameters) const;
59
60private:
61 static constexpr std::size_t NPAD_COUNT = 10;
62
63 struct SixaxisParameters {
64 bool is_fusion_enabled{true};
65 bool unaltered_passtrough{false};
66 Core::HID::SixAxisSensorFusionParameters fusion{};
67 Core::HID::SixAxisSensorCalibrationParameter calibration{};
68 Core::HID::SixAxisSensorIcInformation ic_information{};
69 Core::HID::GyroscopeZeroDriftMode gyroscope_zero_drift_mode{
70 Core::HID::GyroscopeZeroDriftMode::Standard};
71 };
72
73 struct NpadControllerData {
74 Core::HID::EmulatedController* device = nullptr;
75
76 // Motion parameters
77 bool sixaxis_at_rest{true};
78 bool sixaxis_sensor_enabled{true};
79 SixaxisParameters sixaxis_fullkey{};
80 SixaxisParameters sixaxis_handheld{};
81 SixaxisParameters sixaxis_dual_left{};
82 SixaxisParameters sixaxis_dual_right{};
83 SixaxisParameters sixaxis_left{};
84 SixaxisParameters sixaxis_right{};
85 SixaxisParameters sixaxis_unknown{};
86
87 // Current pad state
88 Core::HID::SixAxisSensorState sixaxis_fullkey_state{};
89 Core::HID::SixAxisSensorState sixaxis_handheld_state{};
90 Core::HID::SixAxisSensorState sixaxis_dual_left_state{};
91 Core::HID::SixAxisSensorState sixaxis_dual_right_state{};
92 Core::HID::SixAxisSensorState sixaxis_left_lifo_state{};
93 Core::HID::SixAxisSensorState sixaxis_right_lifo_state{};
94 int callback_key{};
95 };
96
97 SixaxisParameters& GetSixaxisState(const Core::HID::SixAxisSensorHandle& device_handle);
98 const SixaxisParameters& GetSixaxisState(
99 const Core::HID::SixAxisSensorHandle& device_handle) const;
100
101 NpadControllerData& GetControllerFromHandle(
102 const Core::HID::SixAxisSensorHandle& device_handle);
103 const NpadControllerData& GetControllerFromHandle(
104 const Core::HID::SixAxisSensorHandle& device_handle) const;
105 NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id);
106 const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const;
107
108 std::shared_ptr<NPad> npad;
109 std::array<NpadControllerData, NPAD_COUNT> controller_data{};
110};
111} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/sleep_button.cpp b/src/core/hle/service/hid/controllers/sleep_button.cpp
deleted file mode 100644
index d44b1f4cc..000000000
--- a/src/core/hle/service/hid/controllers/sleep_button.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core_timing.h"
5#include "core/hle/service/hid/controllers/applet_resource.h"
6#include "core/hle/service/hid/controllers/sleep_button.h"
7#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
8
9namespace Service::HID {
10
11SleepButton::SleepButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
12
13SleepButton::~SleepButton() = default;
14
15void SleepButton::OnInit() {}
16
17void SleepButton::OnRelease() {}
18
19void SleepButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
20 if (!smart_update) {
21 return;
22 }
23
24 std::scoped_lock shared_lock{*shared_mutex};
25 const u64 aruid = applet_resource->GetActiveAruid();
26 auto* data = applet_resource->GetAruidData(aruid);
27
28 if (data == nullptr || !data->flag.is_assigned) {
29 return;
30 }
31
32 auto& header = data->shared_memory_format->capture_button.header;
33 header.timestamp = core_timing.GetGlobalTimeNs().count();
34 header.total_entry_count = 17;
35 header.entry_count = 0;
36 header.last_entry_index = 0;
37}
38
39} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/sleep_button.h b/src/core/hle/service/hid/controllers/sleep_button.h
deleted file mode 100644
index 59964bf63..000000000
--- a/src/core/hle/service/hid/controllers/sleep_button.h
+++ /dev/null
@@ -1,27 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/hid/controllers/controller_base.h"
7
8namespace Service::HID {
9
10class SleepButton final : public ControllerBase {
11public:
12 explicit SleepButton(Core::HID::HIDCore& hid_core_);
13 ~SleepButton() override;
14
15 // Called when the controller is initialized
16 void OnInit() override;
17
18 // When the controller is released
19 void OnRelease() override;
20
21 // When the controller is requesting an update for the shared memory
22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
23
24private:
25 bool smart_update{};
26};
27} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
deleted file mode 100644
index b585a5829..000000000
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include "common/common_types.h"
6#include "common/settings.h"
7#include "core/core_timing.h"
8#include "core/frontend/emu_window.h"
9#include "core/hid/emulated_console.h"
10#include "core/hid/hid_core.h"
11#include "core/hle/service/hid/controllers/applet_resource.h"
12#include "core/hle/service/hid/controllers/touchscreen.h"
13#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
14
15namespace Service::HID {
16
17TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_)
18 : ControllerBase{hid_core_}, touchscreen_width(Layout::ScreenUndocked::Width),
19 touchscreen_height(Layout::ScreenUndocked::Height) {
20 console = hid_core.GetEmulatedConsole();
21}
22
23TouchScreen::~TouchScreen() = default;
24
25void TouchScreen::OnInit() {}
26
27void TouchScreen::OnRelease() {}
28
29void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
30 const u64 aruid = applet_resource->GetActiveAruid();
31 auto* data = applet_resource->GetAruidData(aruid);
32
33 if (data == nullptr || !data->flag.is_assigned) {
34 return;
35 }
36
37 TouchScreenSharedMemoryFormat& shared_memory = data->shared_memory_format->touch_screen;
38 shared_memory.touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count();
39
40 if (!IsControllerActivated()) {
41 shared_memory.touch_screen_lifo.buffer_count = 0;
42 shared_memory.touch_screen_lifo.buffer_tail = 0;
43 return;
44 }
45
46 const auto touch_status = console->GetTouch();
47 for (std::size_t id = 0; id < MAX_FINGERS; id++) {
48 const auto& current_touch = touch_status[id];
49 auto& finger = fingers[id];
50 finger.id = current_touch.id;
51
52 if (finger.attribute.start_touch) {
53 finger.attribute.raw = 0;
54 continue;
55 }
56
57 if (finger.attribute.end_touch) {
58 finger.attribute.raw = 0;
59 finger.pressed = false;
60 continue;
61 }
62
63 if (!finger.pressed && current_touch.pressed) {
64 // Ignore all touch fingers if disabled
65 if (!Settings::values.touchscreen.enabled) {
66 continue;
67 }
68
69 finger.attribute.start_touch.Assign(1);
70 finger.pressed = true;
71 finger.position = current_touch.position;
72 continue;
73 }
74
75 if (finger.pressed && !current_touch.pressed) {
76 finger.attribute.raw = 0;
77 finger.attribute.end_touch.Assign(1);
78 continue;
79 }
80
81 // Only update position if touch is not on a special frame
82 finger.position = current_touch.position;
83 }
84
85 std::array<Core::HID::TouchFinger, MAX_FINGERS> active_fingers;
86 const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),
87 [](const auto& finger) { return finger.pressed; });
88 const auto active_fingers_count =
89 static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
90
91 const u64 timestamp = static_cast<u64>(core_timing.GetGlobalTimeNs().count());
92 const auto& last_entry = shared_memory.touch_screen_lifo.ReadCurrentEntry().state;
93
94 next_state.sampling_number = last_entry.sampling_number + 1;
95 next_state.entry_count = static_cast<s32>(active_fingers_count);
96
97 for (std::size_t id = 0; id < MAX_FINGERS; ++id) {
98 auto& touch_entry = next_state.states[id];
99 if (id < active_fingers_count) {
100 const auto& [active_x, active_y] = active_fingers[id].position;
101 touch_entry.position = {
102 .x = static_cast<u16>(active_x * static_cast<float>(touchscreen_width)),
103 .y = static_cast<u16>(active_y * static_cast<float>(touchscreen_height)),
104 };
105 touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
106 touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
107 touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
108 touch_entry.delta_time = timestamp - active_fingers[id].last_touch;
109 fingers[active_fingers[id].id].last_touch = timestamp;
110 touch_entry.finger = active_fingers[id].id;
111 touch_entry.attribute.raw = active_fingers[id].attribute.raw;
112 } else {
113 // Clear touch entry
114 touch_entry.attribute.raw = 0;
115 touch_entry.position = {};
116 touch_entry.diameter_x = 0;
117 touch_entry.diameter_y = 0;
118 touch_entry.rotation_angle = 0;
119 touch_entry.delta_time = 0;
120 touch_entry.finger = 0;
121 }
122 }
123
124 shared_memory.touch_screen_lifo.WriteNextEntry(next_state);
125}
126
127void TouchScreen::SetTouchscreenDimensions(u32 width, u32 height) {
128 touchscreen_width = width;
129 touchscreen_height = height;
130}
131
132} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
deleted file mode 100644
index 945d359be..000000000
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ /dev/null
@@ -1,43 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "core/hid/hid_types.h"
9#include "core/hle/service/hid/controllers/controller_base.h"
10#include "core/hle/service/hid/controllers/types/touch_types.h"
11
12namespace Core::HID {
13class EmulatedConsole;
14} // namespace Core::HID
15
16namespace Service::HID {
17struct TouchScreenSharedMemoryFormat;
18
19class TouchScreen final : public ControllerBase {
20public:
21 explicit TouchScreen(Core::HID::HIDCore& hid_core_);
22 ~TouchScreen() override;
23
24 // Called when the controller is initialized
25 void OnInit() override;
26
27 // When the controller is released
28 void OnRelease() override;
29
30 // When the controller is requesting an update for the shared memory
31 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
32
33 void SetTouchscreenDimensions(u32 width, u32 height);
34
35private:
36 TouchScreenState next_state{};
37 Core::HID::EmulatedConsole* console = nullptr;
38
39 std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{};
40 u32 touchscreen_width;
41 u32 touchscreen_height;
42};
43} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/debug_pad_types.h b/src/core/hle/service/hid/controllers/types/debug_pad_types.h
deleted file mode 100644
index a96171b62..000000000
--- a/src/core/hle/service/hid/controllers/types/debug_pad_types.h
+++ /dev/null
@@ -1,31 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/bit_field.h"
7#include "common/common_types.h"
8#include "core/hid/hid_types.h"
9
10namespace Service::HID {
11
12// This is nn::hid::DebugPadAttribute
13struct DebugPadAttribute {
14 union {
15 u32 raw{};
16 BitField<0, 1, u32> connected;
17 };
18};
19static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size");
20
21// This is nn::hid::DebugPadState
22struct DebugPadState {
23 s64 sampling_number{};
24 DebugPadAttribute attribute{};
25 Core::HID::DebugPadButton pad_state{};
26 Core::HID::AnalogStickState r_stick{};
27 Core::HID::AnalogStickState l_stick{};
28};
29static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
30
31} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/gesture_types.h b/src/core/hle/service/hid/controllers/types/gesture_types.h
deleted file mode 100644
index b4f034cd3..000000000
--- a/src/core/hle/service/hid/controllers/types/gesture_types.h
+++ /dev/null
@@ -1,77 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7#include "common/bit_field.h"
8#include "common/common_types.h"
9#include "common/point.h"
10
11namespace Service::HID {
12static constexpr size_t MAX_FINGERS = 16;
13static constexpr size_t MAX_POINTS = 4;
14
15// This is nn::hid::GestureType
16enum class GestureType : u32 {
17 Idle, // Nothing touching the screen
18 Complete, // Set at the end of a touch event
19 Cancel, // Set when the number of fingers change
20 Touch, // A finger just touched the screen
21 Press, // Set if last type is touch and the finger hasn't moved
22 Tap, // Fast press then release
23 Pan, // All points moving together across the screen
24 Swipe, // Fast press movement and release of a single point
25 Pinch, // All points moving away/closer to the midpoint
26 Rotate, // All points rotating from the midpoint
27};
28
29// This is nn::hid::GestureDirection
30enum class GestureDirection : u32 {
31 None,
32 Left,
33 Up,
34 Right,
35 Down,
36};
37
38// This is nn::hid::GestureAttribute
39struct GestureAttribute {
40 union {
41 u32 raw{};
42
43 BitField<4, 1, u32> is_new_touch;
44 BitField<8, 1, u32> is_double_tap;
45 };
46};
47static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
48
49// This is nn::hid::GestureState
50struct GestureState {
51 s64 sampling_number{};
52 s64 detection_count{};
53 GestureType type{GestureType::Idle};
54 GestureDirection direction{GestureDirection::None};
55 Common::Point<s32> pos{};
56 Common::Point<s32> delta{};
57 f32 vel_x{};
58 f32 vel_y{};
59 GestureAttribute attributes{};
60 f32 scale{};
61 f32 rotation_angle{};
62 s32 point_count{};
63 std::array<Common::Point<s32>, 4> points{};
64};
65static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
66
67struct GestureProperties {
68 std::array<Common::Point<s32>, MAX_POINTS> points{};
69 std::size_t active_points{};
70 Common::Point<s32> mid_point{};
71 s64 detection_count{};
72 u64 delta_time{};
73 f32 average_distance{};
74 f32 angle{};
75};
76
77} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/keyboard_types.h b/src/core/hle/service/hid/controllers/types/keyboard_types.h
deleted file mode 100644
index f44a536b9..000000000
--- a/src/core/hle/service/hid/controllers/types/keyboard_types.h
+++ /dev/null
@@ -1,20 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hid/hid_types.h"
8
9namespace Service::HID {
10
11// This is nn::hid::detail::KeyboardState
12struct KeyboardState {
13 s64 sampling_number{};
14 Core::HID::KeyboardModifier modifier{};
15 Core::HID::KeyboardAttribute attribute{};
16 Core::HID::KeyboardKey key{};
17};
18static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
19
20} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/mouse_types.h b/src/core/hle/service/hid/controllers/types/mouse_types.h
deleted file mode 100644
index 8bd6e167c..000000000
--- a/src/core/hle/service/hid/controllers/types/mouse_types.h
+++ /dev/null
@@ -1,8 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7
8namespace Service::HID {} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/npad_types.h b/src/core/hle/service/hid/controllers/types/npad_types.h
deleted file mode 100644
index 419c33a8c..000000000
--- a/src/core/hle/service/hid/controllers/types/npad_types.h
+++ /dev/null
@@ -1,255 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/bit_field.h"
7#include "common/common_funcs.h"
8#include "common/common_types.h"
9#include "core/hid/hid_types.h"
10
11namespace Service::HID {
12static constexpr std::size_t MaxSupportedNpadIdTypes = 10;
13static constexpr std::size_t StyleIndexCount = 7;
14
15// This is nn::hid::NpadJoyHoldType
16enum class NpadJoyHoldType : u64 {
17 Vertical = 0,
18 Horizontal = 1,
19};
20
21// This is nn::hid::NpadJoyAssignmentMode
22enum class NpadJoyAssignmentMode : u32 {
23 Dual = 0,
24 Single = 1,
25};
26
27// This is nn::hid::NpadJoyDeviceType
28enum class NpadJoyDeviceType : s64 {
29 Left = 0,
30 Right = 1,
31};
32
33// This is nn::hid::NpadHandheldActivationMode
34enum class NpadHandheldActivationMode : u64 {
35 Dual = 0,
36 Single = 1,
37 None = 2,
38 MaxActivationMode = 3,
39};
40
41// This is nn::hid::system::AppletFooterUiAttributesSet
42struct AppletFooterUiAttributes {
43 INSERT_PADDING_BYTES(0x4);
44};
45
46// This is nn::hid::system::AppletFooterUiType
47enum class AppletFooterUiType : u8 {
48 None = 0,
49 HandheldNone = 1,
50 HandheldJoyConLeftOnly = 2,
51 HandheldJoyConRightOnly = 3,
52 HandheldJoyConLeftJoyConRight = 4,
53 JoyDual = 5,
54 JoyDualLeftOnly = 6,
55 JoyDualRightOnly = 7,
56 JoyLeftHorizontal = 8,
57 JoyLeftVertical = 9,
58 JoyRightHorizontal = 10,
59 JoyRightVertical = 11,
60 SwitchProController = 12,
61 CompatibleProController = 13,
62 CompatibleJoyCon = 14,
63 LarkHvc1 = 15,
64 LarkHvc2 = 16,
65 LarkNesLeft = 17,
66 LarkNesRight = 18,
67 Lucia = 19,
68 Verification = 20,
69 Lagon = 21,
70};
71
72using AppletFooterUiVariant = u8;
73
74// This is "nn::hid::system::AppletDetailedUiType".
75struct AppletDetailedUiType {
76 AppletFooterUiVariant ui_variant;
77 INSERT_PADDING_BYTES(0x2);
78 AppletFooterUiType footer;
79};
80static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size");
81// This is nn::hid::NpadCommunicationMode
82enum class NpadCommunicationMode : u64 {
83 Mode_5ms = 0,
84 Mode_10ms = 1,
85 Mode_15ms = 2,
86 Default = 3,
87};
88
89enum class NpadRevision : u32 {
90 Revision0 = 0,
91 Revision1 = 1,
92 Revision2 = 2,
93 Revision3 = 3,
94};
95
96// This is nn::hid::detail::ColorAttribute
97enum class ColorAttribute : u32 {
98 Ok = 0,
99 ReadError = 1,
100 NoController = 2,
101};
102static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
103
104// This is nn::hid::detail::NpadFullKeyColorState
105struct NpadFullKeyColorState {
106 ColorAttribute attribute{ColorAttribute::NoController};
107 Core::HID::NpadControllerColor fullkey{};
108};
109static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
110
111// This is nn::hid::detail::NpadJoyColorState
112struct NpadJoyColorState {
113 ColorAttribute attribute{ColorAttribute::NoController};
114 Core::HID::NpadControllerColor left{};
115 Core::HID::NpadControllerColor right{};
116};
117static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
118
119// This is nn::hid::NpadAttribute
120struct NpadAttribute {
121 union {
122 u32 raw{};
123 BitField<0, 1, u32> is_connected;
124 BitField<1, 1, u32> is_wired;
125 BitField<2, 1, u32> is_left_connected;
126 BitField<3, 1, u32> is_left_wired;
127 BitField<4, 1, u32> is_right_connected;
128 BitField<5, 1, u32> is_right_wired;
129 };
130};
131static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
132
133// This is nn::hid::NpadFullKeyState
134// This is nn::hid::NpadHandheldState
135// This is nn::hid::NpadJoyDualState
136// This is nn::hid::NpadJoyLeftState
137// This is nn::hid::NpadJoyRightState
138// This is nn::hid::NpadPalmaState
139// This is nn::hid::NpadSystemExtState
140struct NPadGenericState {
141 s64_le sampling_number{};
142 Core::HID::NpadButtonState npad_buttons{};
143 Core::HID::AnalogStickState l_stick{};
144 Core::HID::AnalogStickState r_stick{};
145 NpadAttribute connection_status{};
146 INSERT_PADDING_BYTES(4); // Reserved
147};
148static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
149
150// This is nn::hid::server::NpadGcTriggerState
151struct NpadGcTriggerState {
152 s64 sampling_number{};
153 s32 l_analog{};
154 s32 r_analog{};
155};
156static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
157
158// This is nn::hid::NpadSystemProperties
159struct NPadSystemProperties {
160 union {
161 s64 raw{};
162 BitField<0, 1, s64> is_charging_joy_dual;
163 BitField<1, 1, s64> is_charging_joy_left;
164 BitField<2, 1, s64> is_charging_joy_right;
165 BitField<3, 1, s64> is_powered_joy_dual;
166 BitField<4, 1, s64> is_powered_joy_left;
167 BitField<5, 1, s64> is_powered_joy_right;
168 BitField<9, 1, s64> is_system_unsupported_button;
169 BitField<10, 1, s64> is_system_ext_unsupported_button;
170 BitField<11, 1, s64> is_vertical;
171 BitField<12, 1, s64> is_horizontal;
172 BitField<13, 1, s64> use_plus;
173 BitField<14, 1, s64> use_minus;
174 BitField<15, 1, s64> use_directional_buttons;
175 };
176};
177static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
178
179// This is nn::hid::NpadSystemButtonProperties
180struct NpadSystemButtonProperties {
181 union {
182 s32 raw{};
183 BitField<0, 1, s32> is_home_button_protection_enabled;
184 };
185};
186static_assert(sizeof(NpadSystemButtonProperties) == 0x4, "NPadButtonProperties is an invalid size");
187
188// This is nn::hid::system::DeviceType
189struct DeviceType {
190 union {
191 u32 raw{};
192 BitField<0, 1, s32> fullkey;
193 BitField<1, 1, s32> debug_pad;
194 BitField<2, 1, s32> handheld_left;
195 BitField<3, 1, s32> handheld_right;
196 BitField<4, 1, s32> joycon_left;
197 BitField<5, 1, s32> joycon_right;
198 BitField<6, 1, s32> palma;
199 BitField<7, 1, s32> lark_hvc_left;
200 BitField<8, 1, s32> lark_hvc_right;
201 BitField<9, 1, s32> lark_nes_left;
202 BitField<10, 1, s32> lark_nes_right;
203 BitField<11, 1, s32> handheld_lark_hvc_left;
204 BitField<12, 1, s32> handheld_lark_hvc_right;
205 BitField<13, 1, s32> handheld_lark_nes_left;
206 BitField<14, 1, s32> handheld_lark_nes_right;
207 BitField<15, 1, s32> lucia;
208 BitField<16, 1, s32> lagon;
209 BitField<17, 1, s32> lager;
210 BitField<31, 1, s32> system;
211 };
212};
213
214// This is nn::hid::detail::NfcXcdDeviceHandleStateImpl
215struct NfcXcdDeviceHandleStateImpl {
216 u64 handle{};
217 bool is_available{};
218 bool is_activated{};
219 INSERT_PADDING_BYTES(0x6); // Reserved
220 u64 sampling_number{};
221};
222static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
223 "NfcXcdDeviceHandleStateImpl is an invalid size");
224
225// This is nn::hid::NpadLarkType
226enum class NpadLarkType : u32 {
227 Invalid,
228 H1,
229 H2,
230 NL,
231 NR,
232};
233
234// This is nn::hid::NpadLuciaType
235enum class NpadLuciaType : u32 {
236 Invalid,
237 J,
238 E,
239 U,
240};
241
242// This is nn::hid::NpadLagonType
243enum class NpadLagonType : u32 {
244 Invalid,
245};
246
247// This is nn::hid::NpadLagerType
248enum class NpadLagerType : u32 {
249 Invalid,
250 J,
251 E,
252 U,
253};
254
255} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/shared_memory_format.h b/src/core/hle/service/hid/controllers/types/shared_memory_format.h
deleted file mode 100644
index 976043b9c..000000000
--- a/src/core/hle/service/hid/controllers/types/shared_memory_format.h
+++ /dev/null
@@ -1,240 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8#include "common/vector_math.h"
9#include "core/hid/hid_types.h"
10#include "core/hle/service/hid//controllers/types/debug_pad_types.h"
11#include "core/hle/service/hid//controllers/types/keyboard_types.h"
12#include "core/hle/service/hid//controllers/types/mouse_types.h"
13#include "core/hle/service/hid//controllers/types/npad_types.h"
14#include "core/hle/service/hid//controllers/types/touch_types.h"
15#include "core/hle/service/hid/ring_lifo.h"
16
17namespace Service::HID {
18static const std::size_t HidEntryCount = 17;
19
20struct CommonHeader {
21 s64 timestamp{};
22 s64 total_entry_count{};
23 s64 last_entry_index{};
24 s64 entry_count{};
25};
26static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
27
28// This is nn::hid::detail::DebugPadSharedMemoryFormat
29struct DebugPadSharedMemoryFormat {
30 // This is nn::hid::detail::DebugPadLifo
31 Lifo<DebugPadState, HidEntryCount> debug_pad_lifo{};
32 static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
33 INSERT_PADDING_WORDS(0x4E);
34};
35static_assert(sizeof(DebugPadSharedMemoryFormat) == 0x400,
36 "DebugPadSharedMemoryFormat is an invalid size");
37
38// This is nn::hid::detail::TouchScreenSharedMemoryFormat
39struct TouchScreenSharedMemoryFormat {
40 // This is nn::hid::detail::TouchScreenLifo
41 Lifo<TouchScreenState, HidEntryCount> touch_screen_lifo{};
42 static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
43 INSERT_PADDING_WORDS(0xF2);
44};
45static_assert(sizeof(TouchScreenSharedMemoryFormat) == 0x3000,
46 "TouchScreenSharedMemoryFormat is an invalid size");
47
48// This is nn::hid::detail::MouseSharedMemoryFormat
49struct MouseSharedMemoryFormat {
50 // This is nn::hid::detail::MouseLifo
51 Lifo<Core::HID::MouseState, HidEntryCount> mouse_lifo{};
52 static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
53 INSERT_PADDING_WORDS(0x2C);
54};
55static_assert(sizeof(MouseSharedMemoryFormat) == 0x400,
56 "MouseSharedMemoryFormat is an invalid size");
57
58// This is nn::hid::detail::KeyboardSharedMemoryFormat
59struct KeyboardSharedMemoryFormat {
60 // This is nn::hid::detail::KeyboardLifo
61 Lifo<KeyboardState, HidEntryCount> keyboard_lifo{};
62 static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
63 INSERT_PADDING_WORDS(0xA);
64};
65static_assert(sizeof(KeyboardSharedMemoryFormat) == 0x400,
66 "KeyboardSharedMemoryFormat is an invalid size");
67
68// This is nn::hid::detail::DigitizerSharedMemoryFormat
69struct DigitizerSharedMemoryFormat {
70 CommonHeader header;
71 INSERT_PADDING_BYTES(0xFE0);
72};
73static_assert(sizeof(DigitizerSharedMemoryFormat) == 0x1000,
74 "DigitizerSharedMemoryFormat is an invalid size");
75
76// This is nn::hid::detail::HomeButtonSharedMemoryFormat
77struct HomeButtonSharedMemoryFormat {
78 CommonHeader header;
79 INSERT_PADDING_BYTES(0x1E0);
80};
81static_assert(sizeof(HomeButtonSharedMemoryFormat) == 0x200,
82 "HomeButtonSharedMemoryFormat is an invalid size");
83
84// This is nn::hid::detail::SleepButtonSharedMemoryFormat
85struct SleepButtonSharedMemoryFormat {
86 CommonHeader header;
87 INSERT_PADDING_BYTES(0x1E0);
88};
89static_assert(sizeof(SleepButtonSharedMemoryFormat) == 0x200,
90 "SleepButtonSharedMemoryFormat is an invalid size");
91
92// This is nn::hid::detail::CaptureButtonSharedMemoryFormat
93struct CaptureButtonSharedMemoryFormat {
94 CommonHeader header;
95 INSERT_PADDING_BYTES(0x1E0);
96};
97static_assert(sizeof(CaptureButtonSharedMemoryFormat) == 0x200,
98 "CaptureButtonSharedMemoryFormat is an invalid size");
99
100// This is nn::hid::detail::InputDetectorSharedMemoryFormat
101struct InputDetectorSharedMemoryFormat {
102 CommonHeader header;
103 INSERT_PADDING_BYTES(0x7E0);
104};
105static_assert(sizeof(InputDetectorSharedMemoryFormat) == 0x800,
106 "InputDetectorSharedMemoryFormat is an invalid size");
107
108// This is nn::hid::detail::UniquePadSharedMemoryFormat
109struct UniquePadSharedMemoryFormat {
110 CommonHeader header;
111 INSERT_PADDING_BYTES(0x3FE0);
112};
113static_assert(sizeof(UniquePadSharedMemoryFormat) == 0x4000,
114 "UniquePadSharedMemoryFormat is an invalid size");
115
116// This is nn::hid::detail::NpadSixAxisSensorLifo
117struct NpadSixAxisSensorLifo {
118 Lifo<Core::HID::SixAxisSensorState, HidEntryCount> lifo;
119};
120
121// This is nn::hid::detail::NpadInternalState
122struct NpadInternalState {
123 Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None};
124 NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
125 NpadFullKeyColorState fullkey_color{};
126 NpadJoyColorState joycon_color{};
127 Lifo<NPadGenericState, HidEntryCount> fullkey_lifo{};
128 Lifo<NPadGenericState, HidEntryCount> handheld_lifo{};
129 Lifo<NPadGenericState, HidEntryCount> joy_dual_lifo{};
130 Lifo<NPadGenericState, HidEntryCount> joy_left_lifo{};
131 Lifo<NPadGenericState, HidEntryCount> joy_right_lifo{};
132 Lifo<NPadGenericState, HidEntryCount> palma_lifo{};
133 Lifo<NPadGenericState, HidEntryCount> system_ext_lifo{};
134 NpadSixAxisSensorLifo sixaxis_fullkey_lifo{};
135 NpadSixAxisSensorLifo sixaxis_handheld_lifo{};
136 NpadSixAxisSensorLifo sixaxis_dual_left_lifo{};
137 NpadSixAxisSensorLifo sixaxis_dual_right_lifo{};
138 NpadSixAxisSensorLifo sixaxis_left_lifo{};
139 NpadSixAxisSensorLifo sixaxis_right_lifo{};
140 DeviceType device_type{};
141 INSERT_PADDING_BYTES(0x4); // Reserved
142 NPadSystemProperties system_properties{};
143 NpadSystemButtonProperties button_properties{};
144 Core::HID::NpadBatteryLevel battery_level_dual{};
145 Core::HID::NpadBatteryLevel battery_level_left{};
146 Core::HID::NpadBatteryLevel battery_level_right{};
147 AppletFooterUiAttributes applet_footer_attributes{};
148 AppletFooterUiType applet_footer_type{AppletFooterUiType::None};
149 INSERT_PADDING_BYTES(0x5B); // Reserved
150 INSERT_PADDING_BYTES(0x20); // Unknown
151 Lifo<NpadGcTriggerState, HidEntryCount> gc_trigger_lifo{};
152 NpadLarkType lark_type_l_and_main{};
153 NpadLarkType lark_type_r{};
154 NpadLuciaType lucia_type{};
155 NpadLagerType lager_type{};
156 Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties;
157 Core::HID::SixAxisSensorProperties sixaxis_handheld_properties;
158 Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties;
159 Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties;
160 Core::HID::SixAxisSensorProperties sixaxis_left_properties;
161 Core::HID::SixAxisSensorProperties sixaxis_right_properties;
162};
163static_assert(sizeof(NpadInternalState) == 0x43F8, "NpadInternalState is an invalid size");
164
165// This is nn::hid::detail::NpadSharedMemoryEntry
166struct NpadSharedMemoryEntry {
167 NpadInternalState internal_state;
168 INSERT_PADDING_BYTES(0xC08);
169};
170static_assert(sizeof(NpadSharedMemoryEntry) == 0x5000, "NpadSharedMemoryEntry is an invalid size");
171
172// This is nn::hid::detail::NpadSharedMemoryFormat
173struct NpadSharedMemoryFormat {
174 std::array<NpadSharedMemoryEntry, MaxSupportedNpadIdTypes> npad_entry;
175};
176static_assert(sizeof(NpadSharedMemoryFormat) == 0x32000,
177 "NpadSharedMemoryFormat is an invalid size");
178
179// This is nn::hid::detail::GestureSharedMemoryFormat
180struct GestureSharedMemoryFormat {
181 // This is nn::hid::detail::GestureLifo
182 Lifo<GestureState, HidEntryCount> gesture_lifo{};
183 static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
184 INSERT_PADDING_WORDS(0x3E);
185};
186static_assert(sizeof(GestureSharedMemoryFormat) == 0x800,
187 "GestureSharedMemoryFormat is an invalid size");
188
189// This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
190struct ConsoleSixAxisSensorSharedMemoryFormat {
191 u64 sampling_number{};
192 bool is_seven_six_axis_sensor_at_rest{};
193 INSERT_PADDING_BYTES(3); // padding
194 f32 verticalization_error{};
195 Common::Vec3f gyro_bias{};
196 INSERT_PADDING_BYTES(4); // padding
197};
198static_assert(sizeof(ConsoleSixAxisSensorSharedMemoryFormat) == 0x20,
199 "ConsoleSixAxisSensorSharedMemoryFormat is an invalid size");
200
201// This is nn::hid::detail::SharedMemoryFormat
202struct SharedMemoryFormat {
203 void Initialize() {}
204
205 DebugPadSharedMemoryFormat debug_pad;
206 TouchScreenSharedMemoryFormat touch_screen;
207 MouseSharedMemoryFormat mouse;
208 KeyboardSharedMemoryFormat keyboard;
209 DigitizerSharedMemoryFormat digitizer;
210 HomeButtonSharedMemoryFormat home_button;
211 SleepButtonSharedMemoryFormat sleep_button;
212 CaptureButtonSharedMemoryFormat capture_button;
213 InputDetectorSharedMemoryFormat input_detector;
214 UniquePadSharedMemoryFormat unique_pad;
215 NpadSharedMemoryFormat npad;
216 GestureSharedMemoryFormat gesture;
217 ConsoleSixAxisSensorSharedMemoryFormat console;
218 INSERT_PADDING_BYTES(0x19E0);
219 MouseSharedMemoryFormat debug_mouse;
220 INSERT_PADDING_BYTES(0x2000);
221};
222static_assert(offsetof(SharedMemoryFormat, debug_pad) == 0x0, "debug_pad has wrong offset");
223static_assert(offsetof(SharedMemoryFormat, touch_screen) == 0x400, "touch_screen has wrong offset");
224static_assert(offsetof(SharedMemoryFormat, mouse) == 0x3400, "mouse has wrong offset");
225static_assert(offsetof(SharedMemoryFormat, keyboard) == 0x3800, "keyboard has wrong offset");
226static_assert(offsetof(SharedMemoryFormat, digitizer) == 0x3C00, "digitizer has wrong offset");
227static_assert(offsetof(SharedMemoryFormat, home_button) == 0x4C00, "home_button has wrong offset");
228static_assert(offsetof(SharedMemoryFormat, sleep_button) == 0x4E00,
229 "sleep_button has wrong offset");
230static_assert(offsetof(SharedMemoryFormat, capture_button) == 0x5000,
231 "capture_button has wrong offset");
232static_assert(offsetof(SharedMemoryFormat, input_detector) == 0x5200,
233 "input_detector has wrong offset");
234static_assert(offsetof(SharedMemoryFormat, npad) == 0x9A00, "npad has wrong offset");
235static_assert(offsetof(SharedMemoryFormat, gesture) == 0x3BA00, "gesture has wrong offset");
236static_assert(offsetof(SharedMemoryFormat, console) == 0x3C200, "console has wrong offset");
237static_assert(offsetof(SharedMemoryFormat, debug_mouse) == 0x3DC00, "debug_mouse has wrong offset");
238static_assert(sizeof(SharedMemoryFormat) == 0x40000, "SharedMemoryFormat is an invalid size");
239
240} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/touch_types.h b/src/core/hle/service/hid/controllers/types/touch_types.h
deleted file mode 100644
index efeaa796d..000000000
--- a/src/core/hle/service/hid/controllers/types/touch_types.h
+++ /dev/null
@@ -1,90 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include <array>
9#include "common/bit_field.h"
10#include "common/common_funcs.h"
11#include "common/common_types.h"
12#include "common/point.h"
13#include "core/hid/hid_types.h"
14
15namespace Service::HID {
16static constexpr std::size_t MAX_FINGERS = 16;
17static constexpr size_t MAX_POINTS = 4;
18
19// This is nn::hid::GestureType
20enum class GestureType : u32 {
21 Idle, // Nothing touching the screen
22 Complete, // Set at the end of a touch event
23 Cancel, // Set when the number of fingers change
24 Touch, // A finger just touched the screen
25 Press, // Set if last type is touch and the finger hasn't moved
26 Tap, // Fast press then release
27 Pan, // All points moving together across the screen
28 Swipe, // Fast press movement and release of a single point
29 Pinch, // All points moving away/closer to the midpoint
30 Rotate, // All points rotating from the midpoint
31};
32
33// This is nn::hid::GestureDirection
34enum class GestureDirection : u32 {
35 None,
36 Left,
37 Up,
38 Right,
39 Down,
40};
41
42// This is nn::hid::GestureAttribute
43struct GestureAttribute {
44 union {
45 u32 raw{};
46
47 BitField<4, 1, u32> is_new_touch;
48 BitField<8, 1, u32> is_double_tap;
49 };
50};
51static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
52
53// This is nn::hid::GestureState
54struct GestureState {
55 s64 sampling_number{};
56 s64 detection_count{};
57 GestureType type{GestureType::Idle};
58 GestureDirection direction{GestureDirection::None};
59 Common::Point<s32> pos{};
60 Common::Point<s32> delta{};
61 f32 vel_x{};
62 f32 vel_y{};
63 GestureAttribute attributes{};
64 f32 scale{};
65 f32 rotation_angle{};
66 s32 point_count{};
67 std::array<Common::Point<s32>, 4> points{};
68};
69static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
70
71struct GestureProperties {
72 std::array<Common::Point<s32>, MAX_POINTS> points{};
73 std::size_t active_points{};
74 Common::Point<s32> mid_point{};
75 s64 detection_count{};
76 u64 delta_time{};
77 f32 average_distance{};
78 f32 angle{};
79};
80
81// This is nn::hid::TouchScreenState
82struct TouchScreenState {
83 s64 sampling_number{};
84 s32 entry_count{};
85 INSERT_PADDING_BYTES(4); // Reserved
86 std::array<Core::HID::TouchState, MAX_FINGERS> states{};
87};
88static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
89
90} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/unique_pad.cpp b/src/core/hle/service/hid/controllers/unique_pad.cpp
deleted file mode 100644
index 6c543031d..000000000
--- a/src/core/hle/service/hid/controllers/unique_pad.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core_timing.h"
5#include "core/hle/service/hid/controllers/applet_resource.h"
6#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
7#include "core/hle/service/hid/controllers/unique_pad.h"
8
9namespace Service::HID {
10
11UniquePad::UniquePad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
12
13UniquePad::~UniquePad() = default;
14
15void UniquePad::OnInit() {}
16
17void UniquePad::OnRelease() {}
18
19void UniquePad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
20 if (!smart_update) {
21 return;
22 }
23
24 const u64 aruid = applet_resource->GetActiveAruid();
25 auto* data = applet_resource->GetAruidData(aruid);
26
27 if (data == nullptr || !data->flag.is_assigned) {
28 return;
29 }
30
31 auto& header = data->shared_memory_format->capture_button.header;
32 header.timestamp = core_timing.GetGlobalTimeNs().count();
33 header.total_entry_count = 17;
34 header.entry_count = 0;
35 header.last_entry_index = 0;
36}
37
38} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/unique_pad.h b/src/core/hle/service/hid/controllers/unique_pad.h
deleted file mode 100644
index 966368264..000000000
--- a/src/core/hle/service/hid/controllers/unique_pad.h
+++ /dev/null
@@ -1,27 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/hid/controllers/controller_base.h"
7
8namespace Service::HID {
9
10class UniquePad final : public ControllerBase {
11public:
12 explicit UniquePad(Core::HID::HIDCore& hid_core_);
13 ~UniquePad() override;
14
15 // Called when the controller is initialized
16 void OnInit() override;
17
18 // When the controller is released
19 void OnRelease() override;
20
21 // When the controller is requesting an update for the shared memory
22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
23
24private:
25 bool smart_update{};
26};
27} // namespace Service::HID
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h
deleted file mode 100644
index bb14aa61e..000000000
--- a/src/core/hle/service/hid/errors.h
+++ /dev/null
@@ -1,59 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::HID {
9
10constexpr Result PalmaResultSuccess{ErrorModule::HID, 0};
11constexpr Result NpadInvalidHandle{ErrorModule::HID, 100};
12constexpr Result NpadDeviceIndexOutOfRange{ErrorModule::HID, 107};
13
14constexpr Result ResultVibrationNotInitialized{ErrorModule::HID, 121};
15constexpr Result ResultVibrationInvalidStyleIndex{ErrorModule::HID, 122};
16constexpr Result ResultVibrationInvalidNpadId{ErrorModule::HID, 123};
17constexpr Result ResultVibrationDeviceIndexOutOfRange{ErrorModule::HID, 124};
18constexpr Result ResultVibrationStrenghtOutOfRange{ErrorModule::HID, 126};
19constexpr Result ResultVibrationArraySizeMismatch{ErrorModule::HID, 131};
20
21constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423};
22
23constexpr Result ResultNfcIsNotReady{ErrorModule::HID, 461};
24constexpr Result ResultNfcXcdHandleIsNotInitialized{ErrorModule::HID, 464};
25constexpr Result ResultIrSensorIsNotReady{ErrorModule::HID, 501};
26constexpr Result ResultMcuIsNotReady{ErrorModule::HID, 541};
27
28constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601};
29constexpr Result NpadIsSameType{ErrorModule::HID, 602};
30constexpr Result ResultNpadIsNotProController{ErrorModule::HID, 604};
31
32constexpr Result ResultInvalidNpadId{ErrorModule::HID, 709};
33constexpr Result ResultNpadNotConnected{ErrorModule::HID, 710};
34constexpr Result ResultNpadHandlerOverflow{ErrorModule::HID, 711};
35constexpr Result ResultNpadHandlerNotInitialized{ErrorModule::HID, 712};
36constexpr Result ResultInvalidArraySize{ErrorModule::HID, 715};
37constexpr Result ResultUndefinedStyleset{ErrorModule::HID, 716};
38constexpr Result ResultMultipleStyleSetSelected{ErrorModule::HID, 717};
39
40constexpr Result ResultAppletResourceOverflow{ErrorModule::HID, 1041};
41constexpr Result ResultAppletResourceNotInitialized{ErrorModule::HID, 1042};
42constexpr Result ResultSharedMemoryNotInitialized{ErrorModule::HID, 1043};
43constexpr Result ResultAruidNoAvailableEntries{ErrorModule::HID, 1044};
44constexpr Result ResultAruidAlreadyRegistered{ErrorModule::HID, 1046};
45constexpr Result ResultAruidNotRegistered{ErrorModule::HID, 1047};
46
47constexpr Result ResultNpadResourceOverflow{ErrorModule::HID, 2001};
48constexpr Result ResultNpadResourceNotInitialized{ErrorModule::HID, 2002};
49
50constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302};
51
52} // namespace Service::HID
53
54namespace Service::IRS {
55
56constexpr Result InvalidProcessorState{ErrorModule::Irsensor, 78};
57constexpr Result InvalidIrCameraHandle{ErrorModule::Irsensor, 204};
58
59} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index bd2873181..fc8a3ab66 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -5,14 +5,14 @@
5#include "core/hle/kernel/kernel.h" 5#include "core/hle/kernel/kernel.h"
6#include "core/hle/service/hid/hid.h" 6#include "core/hle/service/hid/hid.h"
7#include "core/hle/service/hid/hid_debug_server.h" 7#include "core/hle/service/hid/hid_debug_server.h"
8#include "core/hle/service/hid/hid_firmware_settings.h"
9#include "core/hle/service/hid/hid_server.h" 8#include "core/hle/service/hid/hid_server.h"
10#include "core/hle/service/hid/hid_system_server.h" 9#include "core/hle/service/hid/hid_system_server.h"
11#include "core/hle/service/hid/hidbus.h" 10#include "core/hle/service/hid/hidbus.h"
12#include "core/hle/service/hid/irs.h" 11#include "core/hle/service/hid/irs.h"
13#include "core/hle/service/hid/resource_manager.h"
14#include "core/hle/service/hid/xcd.h" 12#include "core/hle/service/hid/xcd.h"
15#include "core/hle/service/server_manager.h" 13#include "core/hle/service/server_manager.h"
14#include "hid_core/resource_manager.h"
15#include "hid_core/resources/hid_firmware_settings.h"
16 16
17namespace Service::HID { 17namespace Service::HID {
18 18
diff --git a/src/core/hle/service/hid/hid_debug_server.cpp b/src/core/hle/service/hid/hid_debug_server.cpp
index 6294f3dfb..f2a767d37 100644
--- a/src/core/hle/service/hid/hid_debug_server.cpp
+++ b/src/core/hle/service/hid/hid_debug_server.cpp
@@ -2,8 +2,8 @@
2// SPDX-License-Identifier: GPL-3.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#include "core/hle/service/hid/hid_debug_server.h" 4#include "core/hle/service/hid/hid_debug_server.h"
5#include "core/hle/service/hid/resource_manager.h"
6#include "core/hle/service/ipc_helpers.h" 5#include "core/hle/service/ipc_helpers.h"
6#include "hid_core/resource_manager.h"
7 7
8namespace Service::HID { 8namespace Service::HID {
9 9
diff --git a/src/core/hle/service/hid/hid_firmware_settings.cpp b/src/core/hle/service/hid/hid_firmware_settings.cpp
deleted file mode 100644
index 59bd6825c..000000000
--- a/src/core/hle/service/hid/hid_firmware_settings.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/hid/hid_firmware_settings.h"
5
6namespace Service::HID {
7
8HidFirmwareSettings::HidFirmwareSettings() {
9 LoadSettings(true);
10}
11
12void HidFirmwareSettings::Reload() {
13 LoadSettings(true);
14}
15
16void HidFirmwareSettings::LoadSettings(bool reload_config) {
17 if (is_initalized && !reload_config) {
18 return;
19 }
20
21 // TODO: Use nn::settings::fwdbg::GetSettingsItemValue to load config values
22
23 is_debug_pad_enabled = true;
24 is_device_managed = true;
25 is_touch_i2c_managed = is_device_managed;
26 is_future_devices_emulated = false;
27 is_mcu_hardware_error_emulated = false;
28 is_rail_enabled = true;
29 is_firmware_update_failure_emulated = false;
30 is_firmware_update_failure = {};
31 is_ble_disabled = false;
32 is_dscale_disabled = false;
33 is_handheld_forced = true;
34 features_per_id_disabled = {};
35 is_touch_firmware_auto_update_disabled = false;
36 is_initalized = true;
37}
38
39bool HidFirmwareSettings::IsDebugPadEnabled() {
40 LoadSettings(false);
41 return is_debug_pad_enabled;
42}
43
44bool HidFirmwareSettings::IsDeviceManaged() {
45 LoadSettings(false);
46 return is_device_managed;
47}
48
49bool HidFirmwareSettings::IsEmulateFutureDevice() {
50 LoadSettings(false);
51 return is_future_devices_emulated;
52}
53
54bool HidFirmwareSettings::IsTouchI2cManaged() {
55 LoadSettings(false);
56 return is_touch_i2c_managed;
57}
58
59bool HidFirmwareSettings::IsHandheldForced() {
60 LoadSettings(false);
61 return is_handheld_forced;
62}
63
64bool HidFirmwareSettings::IsRailEnabled() {
65 LoadSettings(false);
66 return is_rail_enabled;
67}
68
69bool HidFirmwareSettings::IsHardwareErrorEmulated() {
70 LoadSettings(false);
71 return is_mcu_hardware_error_emulated;
72}
73
74bool HidFirmwareSettings::IsBleDisabled() {
75 LoadSettings(false);
76 return is_ble_disabled;
77}
78
79bool HidFirmwareSettings::IsDscaleDisabled() {
80 LoadSettings(false);
81 return is_dscale_disabled;
82}
83
84bool HidFirmwareSettings::IsTouchAutoUpdateDisabled() {
85 LoadSettings(false);
86 return is_touch_firmware_auto_update_disabled;
87}
88
89HidFirmwareSettings::FirmwareSetting HidFirmwareSettings::GetFirmwareUpdateFailure() {
90 LoadSettings(false);
91 return is_firmware_update_failure;
92}
93
94HidFirmwareSettings::FeaturesPerId HidFirmwareSettings::FeaturesDisabledPerId() {
95 LoadSettings(false);
96 return features_per_id_disabled;
97}
98
99} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid_firmware_settings.h b/src/core/hle/service/hid/hid_firmware_settings.h
deleted file mode 100644
index 6c10c440b..000000000
--- a/src/core/hle/service/hid/hid_firmware_settings.h
+++ /dev/null
@@ -1,54 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7
8namespace Service::HID {
9
10/// Loads firmware config from nn::settings::fwdbg
11class HidFirmwareSettings {
12public:
13 using FirmwareSetting = std::array<u8, 4>;
14 using FeaturesPerId = std::array<bool, 0xA8>;
15
16 HidFirmwareSettings();
17
18 void Reload();
19 void LoadSettings(bool reload_config);
20
21 bool IsDebugPadEnabled();
22 bool IsDeviceManaged();
23 bool IsEmulateFutureDevice();
24 bool IsTouchI2cManaged();
25 bool IsHandheldForced();
26 bool IsRailEnabled();
27 bool IsHardwareErrorEmulated();
28 bool IsBleDisabled();
29 bool IsDscaleDisabled();
30 bool IsTouchAutoUpdateDisabled();
31
32 FirmwareSetting GetFirmwareUpdateFailure();
33 FeaturesPerId FeaturesDisabledPerId();
34
35private:
36 bool is_initalized{};
37
38 // Debug settings
39 bool is_debug_pad_enabled{};
40 bool is_device_managed{};
41 bool is_touch_i2c_managed{};
42 bool is_future_devices_emulated{};
43 bool is_mcu_hardware_error_emulated{};
44 bool is_rail_enabled{};
45 bool is_firmware_update_failure_emulated{};
46 bool is_ble_disabled{};
47 bool is_dscale_disabled{};
48 bool is_handheld_forced{};
49 bool is_touch_firmware_auto_update_disabled{};
50 FirmwareSetting is_firmware_update_failure{};
51 FeaturesPerId features_per_id_disabled{};
52};
53
54} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp
index a953c92b3..2ff00d30d 100644
--- a/src/core/hle/service/hid/hid_server.cpp
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -5,30 +5,29 @@
5#include "common/common_types.h" 5#include "common/common_types.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "common/settings.h" 7#include "common/settings.h"
8#include "core/hid/hid_core.h"
9#include "core/hle/kernel/k_shared_memory.h" 8#include "core/hle/kernel/k_shared_memory.h"
10#include "core/hle/kernel/k_transfer_memory.h" 9#include "core/hle/kernel/k_transfer_memory.h"
11#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
12#include "core/hle/service/hid/errors.h"
13#include "core/hle/service/hid/hid_firmware_settings.h"
14#include "core/hle/service/hid/hid_server.h" 11#include "core/hle/service/hid/hid_server.h"
15#include "core/hle/service/hid/hid_util.h"
16#include "core/hle/service/hid/resource_manager.h"
17#include "core/hle/service/ipc_helpers.h" 12#include "core/hle/service/ipc_helpers.h"
18#include "core/memory.h" 13#include "core/memory.h"
19 14#include "hid_core/hid_result.h"
20#include "core/hle/service/hid/controllers/console_six_axis.h" 15#include "hid_core/hid_util.h"
21#include "core/hle/service/hid/controllers/controller_base.h" 16#include "hid_core/resource_manager.h"
22#include "core/hle/service/hid/controllers/debug_pad.h" 17#include "hid_core/resources/hid_firmware_settings.h"
23#include "core/hle/service/hid/controllers/gesture.h" 18
24#include "core/hle/service/hid/controllers/keyboard.h" 19#include "hid_core/resources/controller_base.h"
25#include "core/hle/service/hid/controllers/mouse.h" 20#include "hid_core/resources/debug_pad/debug_pad.h"
26#include "core/hle/service/hid/controllers/npad.h" 21#include "hid_core/resources/keyboard/keyboard.h"
27#include "core/hle/service/hid/controllers/palma.h" 22#include "hid_core/resources/mouse/mouse.h"
28#include "core/hle/service/hid/controllers/seven_six_axis.h" 23#include "hid_core/resources/npad/npad.h"
29#include "core/hle/service/hid/controllers/six_axis.h" 24#include "hid_core/resources/npad/npad_types.h"
30#include "core/hle/service/hid/controllers/touchscreen.h" 25#include "hid_core/resources/palma/palma.h"
31#include "core/hle/service/hid/controllers/types/npad_types.h" 26#include "hid_core/resources/six_axis/console_six_axis.h"
27#include "hid_core/resources/six_axis/seven_six_axis.h"
28#include "hid_core/resources/six_axis/six_axis.h"
29#include "hid_core/resources/touch_screen/gesture.h"
30#include "hid_core/resources/touch_screen/touch_screen.h"
32 31
33namespace Service::HID { 32namespace Service::HID {
34 33
diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp
index 4823de743..027c56025 100644
--- a/src/core/hle/service/hid/hid_system_server.cpp
+++ b/src/core/hle/service/hid/hid_system_server.cpp
@@ -1,15 +1,14 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#include "core/hid/hid_core.h"
5#include "core/hle/service/hid/controllers/npad.h"
6#include "core/hle/service/hid/controllers/palma.h"
7#include "core/hle/service/hid/controllers/touchscreen.h"
8#include "core/hle/service/hid/controllers/types/npad_types.h"
9#include "core/hle/service/hid/errors.h"
10#include "core/hle/service/hid/hid_system_server.h" 4#include "core/hle/service/hid/hid_system_server.h"
11#include "core/hle/service/hid/resource_manager.h"
12#include "core/hle/service/ipc_helpers.h" 5#include "core/hle/service/ipc_helpers.h"
6#include "hid_core/hid_result.h"
7#include "hid_core/resource_manager.h"
8#include "hid_core/resources/npad/npad.h"
9#include "hid_core/resources/npad/npad_types.h"
10#include "hid_core/resources/palma/palma.h"
11#include "hid_core/resources/touch_screen/touch_screen.h"
13 12
14namespace Service::HID { 13namespace Service::HID {
15 14
@@ -270,7 +269,7 @@ void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) {
270 269
271 IPC::ResponseBuilder rb{ctx, 3}; 270 IPC::ResponseBuilder rb{ctx, 3};
272 rb.Push(ResultSuccess); 271 rb.Push(ResultSuccess);
273 rb.PushEnum(system.HIDCore().GetLastActiveController()); 272 rb.Push(0); // Dont forget to fix this
274} 273}
275 274
276void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) { 275void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) {
diff --git a/src/core/hle/service/hid/hid_util.h b/src/core/hle/service/hid/hid_util.h
deleted file mode 100644
index 6a2ed287a..000000000
--- a/src/core/hle/service/hid/hid_util.h
+++ /dev/null
@@ -1,146 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hid/hid_types.h"
7#include "core/hle/service/hid/errors.h"
8
9namespace Service::HID {
10
11constexpr bool IsNpadIdValid(const Core::HID::NpadIdType npad_id) {
12 switch (npad_id) {
13 case Core::HID::NpadIdType::Player1:
14 case Core::HID::NpadIdType::Player2:
15 case Core::HID::NpadIdType::Player3:
16 case Core::HID::NpadIdType::Player4:
17 case Core::HID::NpadIdType::Player5:
18 case Core::HID::NpadIdType::Player6:
19 case Core::HID::NpadIdType::Player7:
20 case Core::HID::NpadIdType::Player8:
21 case Core::HID::NpadIdType::Other:
22 case Core::HID::NpadIdType::Handheld:
23 return true;
24 default:
25 return false;
26 }
27}
28
29constexpr Result IsSixaxisHandleValid(const Core::HID::SixAxisSensorHandle& handle) {
30 const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(handle.npad_id));
31 const bool device_index = handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
32
33 if (!npad_id) {
34 return ResultInvalidNpadId;
35 }
36 if (!device_index) {
37 return NpadDeviceIndexOutOfRange;
38 }
39
40 return ResultSuccess;
41}
42
43constexpr Result IsVibrationHandleValid(const Core::HID::VibrationDeviceHandle& handle) {
44 switch (handle.npad_type) {
45 case Core::HID::NpadStyleIndex::ProController:
46 case Core::HID::NpadStyleIndex::Handheld:
47 case Core::HID::NpadStyleIndex::JoyconDual:
48 case Core::HID::NpadStyleIndex::JoyconLeft:
49 case Core::HID::NpadStyleIndex::JoyconRight:
50 case Core::HID::NpadStyleIndex::GameCube:
51 case Core::HID::NpadStyleIndex::N64:
52 case Core::HID::NpadStyleIndex::SystemExt:
53 case Core::HID::NpadStyleIndex::System:
54 // These support vibration
55 break;
56 default:
57 return ResultVibrationInvalidStyleIndex;
58 }
59
60 if (!IsNpadIdValid(static_cast<Core::HID::NpadIdType>(handle.npad_id))) {
61 return ResultVibrationInvalidNpadId;
62 }
63
64 if (handle.device_index >= Core::HID::DeviceIndex::MaxDeviceIndex) {
65 return ResultVibrationDeviceIndexOutOfRange;
66 }
67
68 return ResultSuccess;
69}
70
71/// Converts a Core::HID::NpadIdType to an array index.
72constexpr size_t NpadIdTypeToIndex(Core::HID::NpadIdType npad_id_type) {
73 switch (npad_id_type) {
74 case Core::HID::NpadIdType::Player1:
75 return 0;
76 case Core::HID::NpadIdType::Player2:
77 return 1;
78 case Core::HID::NpadIdType::Player3:
79 return 2;
80 case Core::HID::NpadIdType::Player4:
81 return 3;
82 case Core::HID::NpadIdType::Player5:
83 return 4;
84 case Core::HID::NpadIdType::Player6:
85 return 5;
86 case Core::HID::NpadIdType::Player7:
87 return 6;
88 case Core::HID::NpadIdType::Player8:
89 return 7;
90 case Core::HID::NpadIdType::Handheld:
91 return 8;
92 case Core::HID::NpadIdType::Other:
93 return 9;
94 default:
95 return 8;
96 }
97}
98
99/// Converts an array index to a Core::HID::NpadIdType
100constexpr Core::HID::NpadIdType IndexToNpadIdType(size_t index) {
101 switch (index) {
102 case 0:
103 return Core::HID::NpadIdType::Player1;
104 case 1:
105 return Core::HID::NpadIdType::Player2;
106 case 2:
107 return Core::HID::NpadIdType::Player3;
108 case 3:
109 return Core::HID::NpadIdType::Player4;
110 case 4:
111 return Core::HID::NpadIdType::Player5;
112 case 5:
113 return Core::HID::NpadIdType::Player6;
114 case 6:
115 return Core::HID::NpadIdType::Player7;
116 case 7:
117 return Core::HID::NpadIdType::Player8;
118 case 8:
119 return Core::HID::NpadIdType::Handheld;
120 case 9:
121 return Core::HID::NpadIdType::Other;
122 default:
123 return Core::HID::NpadIdType::Invalid;
124 }
125}
126
127constexpr Core::HID::NpadStyleSet GetStylesetByIndex(std::size_t index) {
128 switch (index) {
129 case 0:
130 return Core::HID::NpadStyleSet::Fullkey;
131 case 1:
132 return Core::HID::NpadStyleSet::Handheld;
133 case 2:
134 return Core::HID::NpadStyleSet::JoyDual;
135 case 3:
136 return Core::HID::NpadStyleSet::JoyLeft;
137 case 4:
138 return Core::HID::NpadStyleSet::JoyRight;
139 case 5:
140 return Core::HID::NpadStyleSet::Palma;
141 default:
142 return Core::HID::NpadStyleSet::None;
143 }
144}
145
146} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp
index ffa7e144d..46f503d38 100644
--- a/src/core/hle/service/hid/hidbus.cpp
+++ b/src/core/hle/service/hid/hidbus.cpp
@@ -5,18 +5,18 @@
5#include "common/settings.h" 5#include "common/settings.h"
6#include "core/core.h" 6#include "core/core.h"
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/hid/hid_types.h"
9#include "core/hle/kernel/k_event.h" 8#include "core/hle/kernel/k_event.h"
10#include "core/hle/kernel/k_readable_event.h" 9#include "core/hle/kernel/k_readable_event.h"
11#include "core/hle/kernel/k_shared_memory.h" 10#include "core/hle/kernel/k_shared_memory.h"
12#include "core/hle/kernel/k_transfer_memory.h" 11#include "core/hle/kernel/k_transfer_memory.h"
13#include "core/hle/service/hid/hidbus.h" 12#include "core/hle/service/hid/hidbus.h"
14#include "core/hle/service/hid/hidbus/ringcon.h"
15#include "core/hle/service/hid/hidbus/starlink.h"
16#include "core/hle/service/hid/hidbus/stubbed.h"
17#include "core/hle/service/ipc_helpers.h" 13#include "core/hle/service/ipc_helpers.h"
18#include "core/hle/service/service.h" 14#include "core/hle/service/service.h"
19#include "core/memory.h" 15#include "core/memory.h"
16#include "hid_core/hid_types.h"
17#include "hid_core/hidbus/ringcon.h"
18#include "hid_core/hidbus/starlink.h"
19#include "hid_core/hidbus/stubbed.h"
20 20
21namespace Service::HID { 21namespace Service::HID {
22// (15ms, 66Hz) 22// (15ms, 66Hz)
diff --git a/src/core/hle/service/hid/hidbus.h b/src/core/hle/service/hid/hidbus.h
index 85a1df133..05f62f634 100644
--- a/src/core/hle/service/hid/hidbus.h
+++ b/src/core/hle/service/hid/hidbus.h
@@ -5,9 +5,9 @@
5 5
6#include <functional> 6#include <functional>
7 7
8#include "core/hle/service/hid/hidbus/hidbus_base.h"
9#include "core/hle/service/kernel_helpers.h" 8#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
10#include "hid_core/hidbus/hidbus_base.h"
11 11
12namespace Core::Timing { 12namespace Core::Timing {
13struct EventType; 13struct EventType;
diff --git a/src/core/hle/service/hid/hidbus/hidbus_base.cpp b/src/core/hle/service/hid/hidbus/hidbus_base.cpp
deleted file mode 100644
index 8c44f93e8..000000000
--- a/src/core/hle/service/hid/hidbus/hidbus_base.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hid/hid_core.h"
5#include "core/hle/kernel/k_event.h"
6#include "core/hle/kernel/k_readable_event.h"
7#include "core/hle/service/hid/hidbus/hidbus_base.h"
8#include "core/hle/service/kernel_helpers.h"
9
10namespace Service::HID {
11
12HidbusBase::HidbusBase(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
13 : system(system_), service_context(service_context_) {
14 send_command_async_event = service_context.CreateEvent("hidbus:SendCommandAsyncEvent");
15}
16
17HidbusBase::~HidbusBase() {
18 service_context.CloseEvent(send_command_async_event);
19};
20
21void HidbusBase::ActivateDevice() {
22 if (is_activated) {
23 return;
24 }
25 is_activated = true;
26 OnInit();
27}
28
29void HidbusBase::DeactivateDevice() {
30 if (is_activated) {
31 OnRelease();
32 }
33 is_activated = false;
34}
35
36bool HidbusBase::IsDeviceActivated() const {
37 return is_activated;
38}
39
40void HidbusBase::Enable(bool enable) {
41 device_enabled = enable;
42}
43
44bool HidbusBase::IsEnabled() const {
45 return device_enabled;
46}
47
48bool HidbusBase::IsPollingMode() const {
49 return polling_mode_enabled;
50}
51
52JoyPollingMode HidbusBase::GetPollingMode() const {
53 return polling_mode;
54}
55
56void HidbusBase::SetPollingMode(JoyPollingMode mode) {
57 polling_mode = mode;
58 polling_mode_enabled = true;
59}
60
61void HidbusBase::DisablePollingMode() {
62 polling_mode_enabled = false;
63}
64
65void HidbusBase::SetTransferMemoryAddress(Common::ProcessAddress t_mem) {
66 transfer_memory = t_mem;
67}
68
69Kernel::KReadableEvent& HidbusBase::GetSendCommandAsycEvent() const {
70 return send_command_async_event->GetReadableEvent();
71}
72
73} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hidbus/hidbus_base.h b/src/core/hle/service/hid/hidbus/hidbus_base.h
deleted file mode 100644
index ec41684e1..000000000
--- a/src/core/hle/service/hid/hidbus/hidbus_base.h
+++ /dev/null
@@ -1,183 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 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 "common/typed_address.h"
9#include "core/hle/result.h"
10
11namespace Core {
12class System;
13}
14
15namespace Kernel {
16class KEvent;
17class KReadableEvent;
18} // namespace Kernel
19
20namespace Service::KernelHelpers {
21class ServiceContext;
22}
23
24namespace Service::HID {
25
26// This is nn::hidbus::JoyPollingMode
27enum class JoyPollingMode : u32 {
28 SixAxisSensorDisable,
29 SixAxisSensorEnable,
30 ButtonOnly,
31};
32
33struct DataAccessorHeader {
34 Result result{ResultUnknown};
35 INSERT_PADDING_WORDS(0x1);
36 std::array<u8, 0x18> unused{};
37 u64 latest_entry{};
38 u64 total_entries{};
39};
40static_assert(sizeof(DataAccessorHeader) == 0x30, "DataAccessorHeader is an invalid size");
41
42struct JoyDisableSixAxisPollingData {
43 std::array<u8, 0x26> data;
44 u8 out_size;
45 INSERT_PADDING_BYTES(0x1);
46 u64 sampling_number;
47};
48static_assert(sizeof(JoyDisableSixAxisPollingData) == 0x30,
49 "JoyDisableSixAxisPollingData is an invalid size");
50
51struct JoyEnableSixAxisPollingData {
52 std::array<u8, 0x8> data;
53 u8 out_size;
54 INSERT_PADDING_BYTES(0x7);
55 u64 sampling_number;
56};
57static_assert(sizeof(JoyEnableSixAxisPollingData) == 0x18,
58 "JoyEnableSixAxisPollingData is an invalid size");
59
60struct JoyButtonOnlyPollingData {
61 std::array<u8, 0x2c> data;
62 u8 out_size;
63 INSERT_PADDING_BYTES(0x3);
64 u64 sampling_number;
65};
66static_assert(sizeof(JoyButtonOnlyPollingData) == 0x38,
67 "JoyButtonOnlyPollingData is an invalid size");
68
69struct JoyDisableSixAxisPollingEntry {
70 u64 sampling_number;
71 JoyDisableSixAxisPollingData polling_data;
72};
73static_assert(sizeof(JoyDisableSixAxisPollingEntry) == 0x38,
74 "JoyDisableSixAxisPollingEntry is an invalid size");
75
76struct JoyEnableSixAxisPollingEntry {
77 u64 sampling_number;
78 JoyEnableSixAxisPollingData polling_data;
79};
80static_assert(sizeof(JoyEnableSixAxisPollingEntry) == 0x20,
81 "JoyEnableSixAxisPollingEntry is an invalid size");
82
83struct JoyButtonOnlyPollingEntry {
84 u64 sampling_number;
85 JoyButtonOnlyPollingData polling_data;
86};
87static_assert(sizeof(JoyButtonOnlyPollingEntry) == 0x40,
88 "JoyButtonOnlyPollingEntry is an invalid size");
89
90struct JoyDisableSixAxisDataAccessor {
91 DataAccessorHeader header{};
92 std::array<JoyDisableSixAxisPollingEntry, 0xb> entries{};
93};
94static_assert(sizeof(JoyDisableSixAxisDataAccessor) == 0x298,
95 "JoyDisableSixAxisDataAccessor is an invalid size");
96
97struct JoyEnableSixAxisDataAccessor {
98 DataAccessorHeader header{};
99 std::array<JoyEnableSixAxisPollingEntry, 0xb> entries{};
100};
101static_assert(sizeof(JoyEnableSixAxisDataAccessor) == 0x190,
102 "JoyEnableSixAxisDataAccessor is an invalid size");
103
104struct ButtonOnlyPollingDataAccessor {
105 DataAccessorHeader header;
106 std::array<JoyButtonOnlyPollingEntry, 0xb> entries;
107};
108static_assert(sizeof(ButtonOnlyPollingDataAccessor) == 0x2F0,
109 "ButtonOnlyPollingDataAccessor is an invalid size");
110
111class HidbusBase {
112public:
113 explicit HidbusBase(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
114 virtual ~HidbusBase();
115
116 void ActivateDevice();
117
118 void DeactivateDevice();
119
120 bool IsDeviceActivated() const;
121
122 // Enables/disables the device
123 void Enable(bool enable);
124
125 // returns true if device is enabled
126 bool IsEnabled() const;
127
128 // returns true if polling mode is enabled
129 bool IsPollingMode() const;
130
131 // returns polling mode
132 JoyPollingMode GetPollingMode() const;
133
134 // Sets and enables JoyPollingMode
135 void SetPollingMode(JoyPollingMode mode);
136
137 // Disables JoyPollingMode
138 void DisablePollingMode();
139
140 // Called on EnableJoyPollingReceiveMode
141 void SetTransferMemoryAddress(Common::ProcessAddress t_mem);
142
143 Kernel::KReadableEvent& GetSendCommandAsycEvent() const;
144
145 virtual void OnInit() {}
146
147 virtual void OnRelease() {}
148
149 // Updates device transfer memory
150 virtual void OnUpdate() {}
151
152 // Returns the device ID of the joycon
153 virtual u8 GetDeviceId() const {
154 return {};
155 }
156
157 // Assigns a command from data
158 virtual bool SetCommand(std::span<const u8> data) {
159 return {};
160 }
161
162 // Returns a reply from a command
163 virtual std::vector<u8> GetReply() const {
164 return {};
165 }
166
167protected:
168 bool is_activated{};
169 bool device_enabled{};
170 bool polling_mode_enabled{};
171 JoyPollingMode polling_mode = {};
172 // TODO(German77): All data accessors need to be replaced with a ring lifo object
173 JoyDisableSixAxisDataAccessor disable_sixaxis_data{};
174 JoyEnableSixAxisDataAccessor enable_sixaxis_data{};
175 ButtonOnlyPollingDataAccessor button_only_data{};
176
177 Common::ProcessAddress transfer_memory{};
178
179 Core::System& system;
180 Kernel::KEvent* send_command_async_event;
181 KernelHelpers::ServiceContext& service_context;
182};
183} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hidbus/ringcon.cpp b/src/core/hle/service/hid/hidbus/ringcon.cpp
deleted file mode 100644
index 378108012..000000000
--- a/src/core/hle/service/hid/hidbus/ringcon.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hid/emulated_controller.h"
6#include "core/hid/hid_core.h"
7#include "core/hle/kernel/k_event.h"
8#include "core/hle/kernel/k_readable_event.h"
9#include "core/hle/service/hid/hidbus/ringcon.h"
10#include "core/memory.h"
11
12namespace Service::HID {
13
14RingController::RingController(Core::System& system_,
15 KernelHelpers::ServiceContext& service_context_)
16 : HidbusBase(system_, service_context_) {
17 input = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
18}
19
20RingController::~RingController() = default;
21
22void RingController::OnInit() {
23 input->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
24 Common::Input::PollingMode::Ring);
25 return;
26}
27
28void RingController::OnRelease() {
29 input->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
30 Common::Input::PollingMode::Active);
31 return;
32};
33
34void RingController::OnUpdate() {
35 if (!is_activated) {
36 return;
37 }
38
39 if (!device_enabled) {
40 return;
41 }
42
43 if (!polling_mode_enabled || transfer_memory == 0) {
44 return;
45 }
46
47 // TODO: Increment multitasking counters from motion and sensor data
48
49 switch (polling_mode) {
50 case JoyPollingMode::SixAxisSensorEnable: {
51 enable_sixaxis_data.header.total_entries = 10;
52 enable_sixaxis_data.header.result = ResultSuccess;
53 const auto& last_entry =
54 enable_sixaxis_data.entries[enable_sixaxis_data.header.latest_entry];
55
56 enable_sixaxis_data.header.latest_entry =
57 (enable_sixaxis_data.header.latest_entry + 1) % 10;
58 auto& curr_entry = enable_sixaxis_data.entries[enable_sixaxis_data.header.latest_entry];
59
60 curr_entry.sampling_number = last_entry.sampling_number + 1;
61 curr_entry.polling_data.sampling_number = curr_entry.sampling_number;
62
63 const RingConData ringcon_value = GetSensorValue();
64 curr_entry.polling_data.out_size = sizeof(ringcon_value);
65 std::memcpy(curr_entry.polling_data.data.data(), &ringcon_value, sizeof(ringcon_value));
66
67 system.ApplicationMemory().WriteBlock(transfer_memory, &enable_sixaxis_data,
68 sizeof(enable_sixaxis_data));
69 break;
70 }
71 default:
72 LOG_ERROR(Service_HID, "Polling mode not supported {}", polling_mode);
73 break;
74 }
75}
76
77RingController::RingConData RingController::GetSensorValue() const {
78 RingConData ringcon_sensor_value{
79 .status = DataValid::Valid,
80 .data = 0,
81 };
82
83 const f32 force_value = input->GetRingSensorForce().force * range;
84 ringcon_sensor_value.data = static_cast<s16>(force_value) + idle_value;
85
86 return ringcon_sensor_value;
87}
88
89u8 RingController::GetDeviceId() const {
90 return device_id;
91}
92
93std::vector<u8> RingController::GetReply() const {
94 const RingConCommands current_command = command;
95
96 switch (current_command) {
97 case RingConCommands::GetFirmwareVersion:
98 return GetFirmwareVersionReply();
99 case RingConCommands::ReadId:
100 return GetReadIdReply();
101 case RingConCommands::c20105:
102 return GetC020105Reply();
103 case RingConCommands::ReadUnkCal:
104 return GetReadUnkCalReply();
105 case RingConCommands::ReadFactoryCal:
106 return GetReadFactoryCalReply();
107 case RingConCommands::ReadUserCal:
108 return GetReadUserCalReply();
109 case RingConCommands::ReadRepCount:
110 return GetReadRepCountReply();
111 case RingConCommands::ReadTotalPushCount:
112 return GetReadTotalPushCountReply();
113 case RingConCommands::ResetRepCount:
114 return GetResetRepCountReply();
115 case RingConCommands::SaveCalData:
116 return GetSaveDataReply();
117 default:
118 return GetErrorReply();
119 }
120}
121
122bool RingController::SetCommand(std::span<const u8> data) {
123 if (data.size() < 4) {
124 LOG_ERROR(Service_HID, "Command size not supported {}", data.size());
125 command = RingConCommands::Error;
126 return false;
127 }
128
129 std::memcpy(&command, data.data(), sizeof(RingConCommands));
130
131 switch (command) {
132 case RingConCommands::GetFirmwareVersion:
133 case RingConCommands::ReadId:
134 case RingConCommands::c20105:
135 case RingConCommands::ReadUnkCal:
136 case RingConCommands::ReadFactoryCal:
137 case RingConCommands::ReadUserCal:
138 case RingConCommands::ReadRepCount:
139 case RingConCommands::ReadTotalPushCount:
140 ASSERT_MSG(data.size() == 0x4, "data.size is not 0x4 bytes");
141 send_command_async_event->Signal();
142 return true;
143 case RingConCommands::ResetRepCount:
144 ASSERT_MSG(data.size() == 0x4, "data.size is not 0x4 bytes");
145 total_rep_count = 0;
146 send_command_async_event->Signal();
147 return true;
148 case RingConCommands::SaveCalData: {
149 ASSERT_MSG(data.size() == 0x14, "data.size is not 0x14 bytes");
150
151 SaveCalData save_info{};
152 std::memcpy(&save_info, data.data(), sizeof(SaveCalData));
153 user_calibration = save_info.calibration;
154 send_command_async_event->Signal();
155 return true;
156 }
157 default:
158 LOG_ERROR(Service_HID, "Command not implemented {}", command);
159 command = RingConCommands::Error;
160 // Signal a reply to avoid softlocking the game
161 send_command_async_event->Signal();
162 return false;
163 }
164}
165
166std::vector<u8> RingController::GetFirmwareVersionReply() const {
167 const FirmwareVersionReply reply{
168 .status = DataValid::Valid,
169 .firmware = version,
170 };
171
172 return GetDataVector(reply);
173}
174
175std::vector<u8> RingController::GetReadIdReply() const {
176 // The values are hardcoded from a real joycon
177 const ReadIdReply reply{
178 .status = DataValid::Valid,
179 .id_l_x0 = 8,
180 .id_l_x0_2 = 41,
181 .id_l_x4 = 22294,
182 .id_h_x0 = 19777,
183 .id_h_x0_2 = 13621,
184 .id_h_x4 = 8245,
185 };
186
187 return GetDataVector(reply);
188}
189
190std::vector<u8> RingController::GetC020105Reply() const {
191 const Cmd020105Reply reply{
192 .status = DataValid::Valid,
193 .data = 1,
194 };
195
196 return GetDataVector(reply);
197}
198
199std::vector<u8> RingController::GetReadUnkCalReply() const {
200 const ReadUnkCalReply reply{
201 .status = DataValid::Valid,
202 .data = 0,
203 };
204
205 return GetDataVector(reply);
206}
207
208std::vector<u8> RingController::GetReadFactoryCalReply() const {
209 const ReadFactoryCalReply reply{
210 .status = DataValid::Valid,
211 .calibration = factory_calibration,
212 };
213
214 return GetDataVector(reply);
215}
216
217std::vector<u8> RingController::GetReadUserCalReply() const {
218 const ReadUserCalReply reply{
219 .status = DataValid::Valid,
220 .calibration = user_calibration,
221 };
222
223 return GetDataVector(reply);
224}
225
226std::vector<u8> RingController::GetReadRepCountReply() const {
227 const GetThreeByteReply reply{
228 .status = DataValid::Valid,
229 .data = {total_rep_count, 0, 0},
230 .crc = GetCrcValue({total_rep_count, 0, 0, 0}),
231 };
232
233 return GetDataVector(reply);
234}
235
236std::vector<u8> RingController::GetReadTotalPushCountReply() const {
237 const GetThreeByteReply reply{
238 .status = DataValid::Valid,
239 .data = {total_push_count, 0, 0},
240 .crc = GetCrcValue({total_push_count, 0, 0, 0}),
241 };
242
243 return GetDataVector(reply);
244}
245
246std::vector<u8> RingController::GetResetRepCountReply() const {
247 return GetReadRepCountReply();
248}
249
250std::vector<u8> RingController::GetSaveDataReply() const {
251 const StatusReply reply{
252 .status = DataValid::Valid,
253 };
254
255 return GetDataVector(reply);
256}
257
258std::vector<u8> RingController::GetErrorReply() const {
259 const ErrorReply reply{
260 .status = DataValid::BadCRC,
261 };
262
263 return GetDataVector(reply);
264}
265
266u8 RingController::GetCrcValue(const std::vector<u8>& data) const {
267 u8 crc = 0;
268 for (std::size_t index = 0; index < data.size(); index++) {
269 for (u8 i = 0x80; i > 0; i >>= 1) {
270 bool bit = (crc & 0x80) != 0;
271 if ((data[index] & i) != 0) {
272 bit = !bit;
273 }
274 crc <<= 1;
275 if (bit) {
276 crc ^= 0x8d;
277 }
278 }
279 }
280 return crc;
281}
282
283template <typename T>
284std::vector<u8> RingController::GetDataVector(const T& reply) const {
285 static_assert(std::is_trivially_copyable_v<T>);
286 std::vector<u8> data;
287 data.resize(sizeof(reply));
288 std::memcpy(data.data(), &reply, sizeof(reply));
289 return data;
290}
291
292} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hidbus/ringcon.h b/src/core/hle/service/hid/hidbus/ringcon.h
deleted file mode 100644
index f42f3ea41..000000000
--- a/src/core/hle/service/hid/hidbus/ringcon.h
+++ /dev/null
@@ -1,253 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <span>
8
9#include "common/common_types.h"
10#include "core/hle/service/hid/hidbus/hidbus_base.h"
11
12namespace Core::HID {
13class EmulatedController;
14} // namespace Core::HID
15
16namespace Service::HID {
17
18class RingController final : public HidbusBase {
19public:
20 explicit RingController(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
21 ~RingController() override;
22
23 void OnInit() override;
24
25 void OnRelease() override;
26
27 // Updates ringcon transfer memory
28 void OnUpdate() override;
29
30 // Returns the device ID of the joycon
31 u8 GetDeviceId() const override;
32
33 // Assigns a command from data
34 bool SetCommand(std::span<const u8> data) override;
35
36 // Returns a reply from a command
37 std::vector<u8> GetReply() const override;
38
39private:
40 // These values are obtained from a real ring controller
41 static constexpr s16 idle_value = 2280;
42 static constexpr s16 idle_deadzone = 120;
43 static constexpr s16 range = 2500;
44
45 // Most missing command names are leftovers from other firmware versions
46 enum class RingConCommands : u32 {
47 GetFirmwareVersion = 0x00020000,
48 ReadId = 0x00020100,
49 JoyPolling = 0x00020101,
50 Unknown1 = 0x00020104,
51 c20105 = 0x00020105,
52 Unknown2 = 0x00020204,
53 Unknown3 = 0x00020304,
54 Unknown4 = 0x00020404,
55 ReadUnkCal = 0x00020504,
56 ReadFactoryCal = 0x00020A04,
57 Unknown5 = 0x00021104,
58 Unknown6 = 0x00021204,
59 Unknown7 = 0x00021304,
60 ReadUserCal = 0x00021A04,
61 ReadRepCount = 0x00023104,
62 ReadTotalPushCount = 0x00023204,
63 ResetRepCount = 0x04013104,
64 Unknown8 = 0x04011104,
65 Unknown9 = 0x04011204,
66 Unknown10 = 0x04011304,
67 SaveCalData = 0x10011A04,
68 Error = 0xFFFFFFFF,
69 };
70
71 enum class DataValid : u32 {
72 Valid,
73 BadCRC,
74 Cal,
75 };
76
77 struct FirmwareVersion {
78 u8 sub;
79 u8 main;
80 };
81 static_assert(sizeof(FirmwareVersion) == 0x2, "FirmwareVersion is an invalid size");
82
83 struct FactoryCalibration {
84 s32_le os_max;
85 s32_le hk_max;
86 s32_le zero_min;
87 s32_le zero_max;
88 };
89 static_assert(sizeof(FactoryCalibration) == 0x10, "FactoryCalibration is an invalid size");
90
91 struct CalibrationValue {
92 s16 value;
93 u16 crc;
94 };
95 static_assert(sizeof(CalibrationValue) == 0x4, "CalibrationValue is an invalid size");
96
97 struct UserCalibration {
98 CalibrationValue os_max;
99 CalibrationValue hk_max;
100 CalibrationValue zero;
101 };
102 static_assert(sizeof(UserCalibration) == 0xC, "UserCalibration is an invalid size");
103
104 struct SaveCalData {
105 RingConCommands command;
106 UserCalibration calibration;
107 INSERT_PADDING_BYTES_NOINIT(4);
108 };
109 static_assert(sizeof(SaveCalData) == 0x14, "SaveCalData is an invalid size");
110 static_assert(std::is_trivially_copyable_v<SaveCalData>,
111 "SaveCalData must be trivially copyable");
112
113 struct FirmwareVersionReply {
114 DataValid status;
115 FirmwareVersion firmware;
116 INSERT_PADDING_BYTES(0x2);
117 };
118 static_assert(sizeof(FirmwareVersionReply) == 0x8, "FirmwareVersionReply is an invalid size");
119
120 struct Cmd020105Reply {
121 DataValid status;
122 u8 data;
123 INSERT_PADDING_BYTES(0x3);
124 };
125 static_assert(sizeof(Cmd020105Reply) == 0x8, "Cmd020105Reply is an invalid size");
126
127 struct StatusReply {
128 DataValid status;
129 };
130 static_assert(sizeof(StatusReply) == 0x4, "StatusReply is an invalid size");
131
132 struct GetThreeByteReply {
133 DataValid status;
134 std::array<u8, 3> data;
135 u8 crc;
136 };
137 static_assert(sizeof(GetThreeByteReply) == 0x8, "GetThreeByteReply is an invalid size");
138
139 struct ReadUnkCalReply {
140 DataValid status;
141 u16 data;
142 INSERT_PADDING_BYTES(0x2);
143 };
144 static_assert(sizeof(ReadUnkCalReply) == 0x8, "ReadUnkCalReply is an invalid size");
145
146 struct ReadFactoryCalReply {
147 DataValid status;
148 FactoryCalibration calibration;
149 };
150 static_assert(sizeof(ReadFactoryCalReply) == 0x14, "ReadFactoryCalReply is an invalid size");
151
152 struct ReadUserCalReply {
153 DataValid status;
154 UserCalibration calibration;
155 INSERT_PADDING_BYTES(0x4);
156 };
157 static_assert(sizeof(ReadUserCalReply) == 0x14, "ReadUserCalReply is an invalid size");
158
159 struct ReadIdReply {
160 DataValid status;
161 u16 id_l_x0;
162 u16 id_l_x0_2;
163 u16 id_l_x4;
164 u16 id_h_x0;
165 u16 id_h_x0_2;
166 u16 id_h_x4;
167 };
168 static_assert(sizeof(ReadIdReply) == 0x10, "ReadIdReply is an invalid size");
169
170 struct ErrorReply {
171 DataValid status;
172 INSERT_PADDING_BYTES(0x3);
173 };
174 static_assert(sizeof(ErrorReply) == 0x8, "ErrorReply is an invalid size");
175
176 struct RingConData {
177 DataValid status;
178 s16_le data;
179 INSERT_PADDING_BYTES(0x2);
180 };
181 static_assert(sizeof(RingConData) == 0x8, "RingConData is an invalid size");
182
183 // Returns RingConData struct with pressure sensor values
184 RingConData GetSensorValue() const;
185
186 // Returns 8 byte reply with firmware version
187 std::vector<u8> GetFirmwareVersionReply() const;
188
189 // Returns 16 byte reply with ID values
190 std::vector<u8> GetReadIdReply() const;
191
192 // (STUBBED) Returns 8 byte reply
193 std::vector<u8> GetC020105Reply() const;
194
195 // (STUBBED) Returns 8 byte empty reply
196 std::vector<u8> GetReadUnkCalReply() const;
197
198 // Returns 20 byte reply with factory calibration values
199 std::vector<u8> GetReadFactoryCalReply() const;
200
201 // Returns 20 byte reply with user calibration values
202 std::vector<u8> GetReadUserCalReply() const;
203
204 // Returns 8 byte reply
205 std::vector<u8> GetReadRepCountReply() const;
206
207 // Returns 8 byte reply
208 std::vector<u8> GetReadTotalPushCountReply() const;
209
210 // Returns 8 byte reply
211 std::vector<u8> GetResetRepCountReply() const;
212
213 // Returns 4 byte save data reply
214 std::vector<u8> GetSaveDataReply() const;
215
216 // Returns 8 byte error reply
217 std::vector<u8> GetErrorReply() const;
218
219 // Returns 8 bit redundancy check from provided data
220 u8 GetCrcValue(const std::vector<u8>& data) const;
221
222 // Converts structs to an u8 vector equivalent
223 template <typename T>
224 std::vector<u8> GetDataVector(const T& reply) const;
225
226 RingConCommands command{RingConCommands::Error};
227
228 // These counters are used in multitasking mode while the switch is sleeping
229 // Total steps taken
230 u8 total_rep_count = 0;
231 // Total times the ring was pushed
232 u8 total_push_count = 0;
233
234 const u8 device_id = 0x20;
235 const FirmwareVersion version = {
236 .sub = 0x0,
237 .main = 0x2c,
238 };
239 const FactoryCalibration factory_calibration = {
240 .os_max = idle_value + range + idle_deadzone,
241 .hk_max = idle_value - range - idle_deadzone,
242 .zero_min = idle_value - idle_deadzone,
243 .zero_max = idle_value + idle_deadzone,
244 };
245 UserCalibration user_calibration = {
246 .os_max = {.value = range, .crc = 228},
247 .hk_max = {.value = -range, .crc = 239},
248 .zero = {.value = idle_value, .crc = 225},
249 };
250
251 Core::HID::EmulatedController* input;
252};
253} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hidbus/starlink.cpp b/src/core/hle/service/hid/hidbus/starlink.cpp
deleted file mode 100644
index 36573274e..000000000
--- a/src/core/hle/service/hid/hidbus/starlink.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hid/emulated_controller.h"
5#include "core/hid/hid_core.h"
6#include "core/hle/service/hid/hidbus/starlink.h"
7
8namespace Service::HID {
9constexpr u8 DEVICE_ID = 0x28;
10
11Starlink::Starlink(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
12 : HidbusBase(system_, service_context_) {}
13Starlink::~Starlink() = default;
14
15void Starlink::OnInit() {
16 return;
17}
18
19void Starlink::OnRelease() {
20 return;
21};
22
23void Starlink::OnUpdate() {
24 if (!is_activated) {
25 return;
26 }
27 if (!device_enabled) {
28 return;
29 }
30 if (!polling_mode_enabled || transfer_memory == 0) {
31 return;
32 }
33
34 LOG_ERROR(Service_HID, "Polling mode not supported {}", polling_mode);
35}
36
37u8 Starlink::GetDeviceId() const {
38 return DEVICE_ID;
39}
40
41std::vector<u8> Starlink::GetReply() const {
42 return {};
43}
44
45bool Starlink::SetCommand(std::span<const u8> data) {
46 LOG_ERROR(Service_HID, "Command not implemented");
47 return false;
48}
49
50} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hidbus/starlink.h b/src/core/hle/service/hid/hidbus/starlink.h
deleted file mode 100644
index a276aa88f..000000000
--- a/src/core/hle/service/hid/hidbus/starlink.h
+++ /dev/null
@@ -1,37 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/service/hid/hidbus/hidbus_base.h"
8
9namespace Core::HID {
10class EmulatedController;
11} // namespace Core::HID
12
13namespace Service::HID {
14
15class Starlink final : public HidbusBase {
16public:
17 explicit Starlink(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
18 ~Starlink() override;
19
20 void OnInit() override;
21
22 void OnRelease() override;
23
24 // Updates ringcon transfer memory
25 void OnUpdate() override;
26
27 // Returns the device ID of the joycon
28 u8 GetDeviceId() const override;
29
30 // Assigns a command from data
31 bool SetCommand(std::span<const u8> data) override;
32
33 // Returns a reply from a command
34 std::vector<u8> GetReply() const override;
35};
36
37} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hidbus/stubbed.cpp b/src/core/hle/service/hid/hidbus/stubbed.cpp
deleted file mode 100644
index 8160b7218..000000000
--- a/src/core/hle/service/hid/hidbus/stubbed.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hid/emulated_controller.h"
5#include "core/hid/hid_core.h"
6#include "core/hle/service/hid/hidbus/stubbed.h"
7
8namespace Service::HID {
9constexpr u8 DEVICE_ID = 0xFF;
10
11HidbusStubbed::HidbusStubbed(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
12 : HidbusBase(system_, service_context_) {}
13HidbusStubbed::~HidbusStubbed() = default;
14
15void HidbusStubbed::OnInit() {
16 return;
17}
18
19void HidbusStubbed::OnRelease() {
20 return;
21};
22
23void HidbusStubbed::OnUpdate() {
24 if (!is_activated) {
25 return;
26 }
27 if (!device_enabled) {
28 return;
29 }
30 if (!polling_mode_enabled || transfer_memory == 0) {
31 return;
32 }
33
34 LOG_ERROR(Service_HID, "Polling mode not supported {}", polling_mode);
35}
36
37u8 HidbusStubbed::GetDeviceId() const {
38 return DEVICE_ID;
39}
40
41std::vector<u8> HidbusStubbed::GetReply() const {
42 return {};
43}
44
45bool HidbusStubbed::SetCommand(std::span<const u8> data) {
46 LOG_ERROR(Service_HID, "Command not implemented");
47 return false;
48}
49
50} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hidbus/stubbed.h b/src/core/hle/service/hid/hidbus/stubbed.h
deleted file mode 100644
index 2e58d42fc..000000000
--- a/src/core/hle/service/hid/hidbus/stubbed.h
+++ /dev/null
@@ -1,37 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/service/hid/hidbus/hidbus_base.h"
8
9namespace Core::HID {
10class EmulatedController;
11} // namespace Core::HID
12
13namespace Service::HID {
14
15class HidbusStubbed final : public HidbusBase {
16public:
17 explicit HidbusStubbed(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
18 ~HidbusStubbed() override;
19
20 void OnInit() override;
21
22 void OnRelease() override;
23
24 // Updates ringcon transfer memory
25 void OnUpdate() override;
26
27 // Returns the device ID of the joycon
28 u8 GetDeviceId() const override;
29
30 // Assigns a command from data
31 bool SetCommand(std::span<const u8> data) override;
32
33 // Returns a reply from a command
34 std::vector<u8> GetReply() const override;
35};
36
37} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index 05ed31273..18e544f2f 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -6,22 +6,22 @@
6 6
7#include "core/core.h" 7#include "core/core.h"
8#include "core/core_timing.h" 8#include "core/core_timing.h"
9#include "core/hid/emulated_controller.h"
10#include "core/hid/hid_core.h"
11#include "core/hle/kernel/k_shared_memory.h" 9#include "core/hle/kernel/k_shared_memory.h"
12#include "core/hle/kernel/k_transfer_memory.h" 10#include "core/hle/kernel/k_transfer_memory.h"
13#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
14#include "core/hle/service/hid/errors.h"
15#include "core/hle/service/hid/hid_util.h"
16#include "core/hle/service/hid/irs.h" 12#include "core/hle/service/hid/irs.h"
17#include "core/hle/service/hid/irsensor/clustering_processor.h"
18#include "core/hle/service/hid/irsensor/image_transfer_processor.h"
19#include "core/hle/service/hid/irsensor/ir_led_processor.h"
20#include "core/hle/service/hid/irsensor/moment_processor.h"
21#include "core/hle/service/hid/irsensor/pointing_processor.h"
22#include "core/hle/service/hid/irsensor/tera_plugin_processor.h"
23#include "core/hle/service/ipc_helpers.h" 13#include "core/hle/service/ipc_helpers.h"
24#include "core/memory.h" 14#include "core/memory.h"
15#include "hid_core/frontend/emulated_controller.h"
16#include "hid_core/hid_core.h"
17#include "hid_core/hid_result.h"
18#include "hid_core/hid_util.h"
19#include "hid_core/irsensor/clustering_processor.h"
20#include "hid_core/irsensor/image_transfer_processor.h"
21#include "hid_core/irsensor/ir_led_processor.h"
22#include "hid_core/irsensor/moment_processor.h"
23#include "hid_core/irsensor/pointing_processor.h"
24#include "hid_core/irsensor/tera_plugin_processor.h"
25 25
26namespace Service::IRS { 26namespace Service::IRS {
27 27
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h
index c8e6dab17..06b7279ee 100644
--- a/src/core/hle/service/hid/irs.h
+++ b/src/core/hle/service/hid/irs.h
@@ -4,10 +4,10 @@
4#pragma once 4#pragma once
5 5
6#include "core/core.h" 6#include "core/core.h"
7#include "core/hid/hid_types.h"
8#include "core/hid/irs_types.h"
9#include "core/hle/service/hid/irsensor/processor_base.h"
10#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8#include "hid_core/hid_types.h"
9#include "hid_core/irsensor/irs_types.h"
10#include "hid_core/irsensor/processor_base.h"
11 11
12namespace Core::HID { 12namespace Core::HID {
13class EmulatedController; 13class EmulatedController;
diff --git a/src/core/hle/service/hid/irs_ring_lifo.h b/src/core/hle/service/hid/irs_ring_lifo.h
deleted file mode 100644
index 255d1d296..000000000
--- a/src/core/hle/service/hid/irs_ring_lifo.h
+++ /dev/null
@@ -1,47 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "common/common_types.h"
9
10namespace Service::IRS {
11
12template <typename State, std::size_t max_buffer_size>
13struct Lifo {
14 s64 sampling_number{};
15 s64 buffer_count{};
16 std::array<State, max_buffer_size> entries{};
17
18 const State& ReadCurrentEntry() const {
19 return entries[GetBufferTail()];
20 }
21
22 const State& ReadPreviousEntry() const {
23 return entries[GetPreviousEntryIndex()];
24 }
25
26 s64 GetBufferTail() const {
27 return sampling_number % max_buffer_size;
28 }
29
30 std::size_t GetPreviousEntryIndex() const {
31 return static_cast<size_t>((GetBufferTail() + max_buffer_size - 1) % max_buffer_size);
32 }
33
34 std::size_t GetNextEntryIndex() const {
35 return static_cast<size_t>((GetBufferTail() + 1) % max_buffer_size);
36 }
37
38 void WriteNextEntry(const State& new_state) {
39 if (buffer_count < static_cast<s64>(max_buffer_size)) {
40 buffer_count++;
41 }
42 sampling_number++;
43 entries[GetBufferTail()] = new_state;
44 }
45};
46
47} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/irsensor/clustering_processor.cpp b/src/core/hle/service/hid/irsensor/clustering_processor.cpp
deleted file mode 100644
index c559eb0d5..000000000
--- a/src/core/hle/service/hid/irsensor/clustering_processor.cpp
+++ /dev/null
@@ -1,267 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <queue>
5
6#include "core/core.h"
7#include "core/core_timing.h"
8#include "core/hid/emulated_controller.h"
9#include "core/hid/hid_core.h"
10#include "core/hle/service/hid/irsensor/clustering_processor.h"
11
12namespace Service::IRS {
13ClusteringProcessor::ClusteringProcessor(Core::System& system_,
14 Core::IrSensor::DeviceFormat& device_format,
15 std::size_t npad_index)
16 : device{device_format}, system{system_} {
17 npad_device = system.HIDCore().GetEmulatedControllerByIndex(npad_index);
18
19 device.mode = Core::IrSensor::IrSensorMode::ClusteringProcessor;
20 device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
21 device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
22 SetDefaultConfig();
23
24 shared_memory = std::construct_at(
25 reinterpret_cast<ClusteringSharedMemory*>(&device_format.state.processor_raw_data));
26
27 Core::HID::ControllerUpdateCallback engine_callback{
28 .on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); },
29 .is_npad_service = true,
30 };
31 callback_key = npad_device->SetCallback(engine_callback);
32}
33
34ClusteringProcessor::~ClusteringProcessor() {
35 npad_device->DeleteCallback(callback_key);
36};
37
38void ClusteringProcessor::StartProcessor() {
39 device.camera_status = Core::IrSensor::IrCameraStatus::Available;
40 device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready;
41}
42
43void ClusteringProcessor::SuspendProcessor() {}
44
45void ClusteringProcessor::StopProcessor() {}
46
47void ClusteringProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type) {
48 if (type != Core::HID::ControllerTriggerType::IrSensor) {
49 return;
50 }
51
52 next_state = {};
53 const auto& camera_data = npad_device->GetCamera();
54 auto filtered_image = camera_data.data;
55
56 RemoveLowIntensityData(filtered_image);
57
58 const auto window_start_x = static_cast<std::size_t>(current_config.window_of_interest.x);
59 const auto window_start_y = static_cast<std::size_t>(current_config.window_of_interest.y);
60 const auto window_end_x =
61 window_start_x + static_cast<std::size_t>(current_config.window_of_interest.width);
62 const auto window_end_y =
63 window_start_y + static_cast<std::size_t>(current_config.window_of_interest.height);
64
65 for (std::size_t y = window_start_y; y < window_end_y; y++) {
66 for (std::size_t x = window_start_x; x < window_end_x; x++) {
67 u8 pixel = GetPixel(filtered_image, x, y);
68 if (pixel == 0) {
69 continue;
70 }
71 const auto cluster = GetClusterProperties(filtered_image, x, y);
72 if (cluster.pixel_count > current_config.pixel_count_max) {
73 continue;
74 }
75 if (cluster.pixel_count < current_config.pixel_count_min) {
76 continue;
77 }
78 // Cluster object limit reached
79 if (next_state.object_count >= next_state.data.size()) {
80 continue;
81 }
82 next_state.data[next_state.object_count] = cluster;
83 next_state.object_count++;
84 }
85 }
86
87 next_state.sampling_number = camera_data.sample;
88 next_state.timestamp = system.CoreTiming().GetGlobalTimeNs().count();
89 next_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low;
90 shared_memory->clustering_lifo.WriteNextEntry(next_state);
91
92 if (!IsProcessorActive()) {
93 StartProcessor();
94 }
95}
96
97void ClusteringProcessor::RemoveLowIntensityData(std::vector<u8>& data) {
98 for (u8& pixel : data) {
99 if (pixel < current_config.pixel_count_min) {
100 pixel = 0;
101 }
102 }
103}
104
105ClusteringProcessor::ClusteringData ClusteringProcessor::GetClusterProperties(std::vector<u8>& data,
106 std::size_t x,
107 std::size_t y) {
108 using DataPoint = Common::Point<std::size_t>;
109 std::queue<DataPoint> search_points{};
110 ClusteringData current_cluster = GetPixelProperties(data, x, y);
111 SetPixel(data, x, y, 0);
112 search_points.emplace<DataPoint>({x, y});
113
114 while (!search_points.empty()) {
115 const auto point = search_points.front();
116 search_points.pop();
117
118 // Avoid negative numbers
119 if (point.x == 0 || point.y == 0) {
120 continue;
121 }
122
123 std::array<DataPoint, 4> new_points{
124 DataPoint{point.x - 1, point.y},
125 {point.x, point.y - 1},
126 {point.x + 1, point.y},
127 {point.x, point.y + 1},
128 };
129
130 for (const auto new_point : new_points) {
131 if (new_point.x >= width) {
132 continue;
133 }
134 if (new_point.y >= height) {
135 continue;
136 }
137 if (GetPixel(data, new_point.x, new_point.y) < current_config.object_intensity_min) {
138 continue;
139 }
140 const ClusteringData cluster = GetPixelProperties(data, new_point.x, new_point.y);
141 current_cluster = MergeCluster(current_cluster, cluster);
142 SetPixel(data, new_point.x, new_point.y, 0);
143 search_points.emplace<DataPoint>({new_point.x, new_point.y});
144 }
145 }
146
147 return current_cluster;
148}
149
150ClusteringProcessor::ClusteringData ClusteringProcessor::GetPixelProperties(
151 const std::vector<u8>& data, std::size_t x, std::size_t y) const {
152 return {
153 .average_intensity = GetPixel(data, x, y) / 255.0f,
154 .centroid =
155 {
156 .x = static_cast<f32>(x),
157 .y = static_cast<f32>(y),
158
159 },
160 .pixel_count = 1,
161 .bound =
162 {
163 .x = static_cast<s16>(x),
164 .y = static_cast<s16>(y),
165 .width = 1,
166 .height = 1,
167 },
168 };
169}
170
171ClusteringProcessor::ClusteringData ClusteringProcessor::MergeCluster(
172 const ClusteringData a, const ClusteringData b) const {
173 const f32 a_pixel_count = static_cast<f32>(a.pixel_count);
174 const f32 b_pixel_count = static_cast<f32>(b.pixel_count);
175 const f32 pixel_count = a_pixel_count + b_pixel_count;
176 const f32 average_intensity =
177 (a.average_intensity * a_pixel_count + b.average_intensity * b_pixel_count) / pixel_count;
178 const Core::IrSensor::IrsCentroid centroid = {
179 .x = (a.centroid.x * a_pixel_count + b.centroid.x * b_pixel_count) / pixel_count,
180 .y = (a.centroid.y * a_pixel_count + b.centroid.y * b_pixel_count) / pixel_count,
181 };
182 s16 bound_start_x = a.bound.x < b.bound.x ? a.bound.x : b.bound.x;
183 s16 bound_start_y = a.bound.y < b.bound.y ? a.bound.y : b.bound.y;
184 s16 a_bound_end_x = a.bound.x + a.bound.width;
185 s16 a_bound_end_y = a.bound.y + a.bound.height;
186 s16 b_bound_end_x = b.bound.x + b.bound.width;
187 s16 b_bound_end_y = b.bound.y + b.bound.height;
188
189 const Core::IrSensor::IrsRect bound = {
190 .x = bound_start_x,
191 .y = bound_start_y,
192 .width = a_bound_end_x > b_bound_end_x ? static_cast<s16>(a_bound_end_x - bound_start_x)
193 : static_cast<s16>(b_bound_end_x - bound_start_x),
194 .height = a_bound_end_y > b_bound_end_y ? static_cast<s16>(a_bound_end_y - bound_start_y)
195 : static_cast<s16>(b_bound_end_y - bound_start_y),
196 };
197
198 return {
199 .average_intensity = average_intensity,
200 .centroid = centroid,
201 .pixel_count = static_cast<u32>(pixel_count),
202 .bound = bound,
203 };
204}
205
206u8 ClusteringProcessor::GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const {
207 if ((y * width) + x >= data.size()) {
208 return 0;
209 }
210 return data[(y * width) + x];
211}
212
213void ClusteringProcessor::SetPixel(std::vector<u8>& data, std::size_t x, std::size_t y, u8 value) {
214 if ((y * width) + x >= data.size()) {
215 return;
216 }
217 data[(y * width) + x] = value;
218}
219
220void ClusteringProcessor::SetDefaultConfig() {
221 using namespace std::literals::chrono_literals;
222 current_config.camera_config.exposure_time = std::chrono::microseconds(200ms).count();
223 current_config.camera_config.gain = 2;
224 current_config.camera_config.is_negative_used = false;
225 current_config.camera_config.light_target = Core::IrSensor::CameraLightTarget::BrightLeds;
226 current_config.window_of_interest = {
227 .x = 0,
228 .y = 0,
229 .width = width,
230 .height = height,
231 };
232 current_config.pixel_count_min = 3;
233 current_config.pixel_count_max = static_cast<u32>(GetDataSize(format));
234 current_config.is_external_light_filter_enabled = true;
235 current_config.object_intensity_min = 150;
236
237 npad_device->SetCameraFormat(format);
238}
239
240void ClusteringProcessor::SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config) {
241 current_config.camera_config.exposure_time = config.camera_config.exposure_time;
242 current_config.camera_config.gain = config.camera_config.gain;
243 current_config.camera_config.is_negative_used = config.camera_config.is_negative_used;
244 current_config.camera_config.light_target =
245 static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target);
246 current_config.window_of_interest = config.window_of_interest;
247 current_config.pixel_count_min = config.pixel_count_min;
248 current_config.pixel_count_max = config.pixel_count_max;
249 current_config.is_external_light_filter_enabled = config.is_external_light_filter_enabled;
250 current_config.object_intensity_min = config.object_intensity_min;
251
252 LOG_INFO(Service_IRS,
253 "Processor config, exposure_time={}, gain={}, is_negative_used={}, "
254 "light_target={}, window_of_interest=({}, {}, {}, {}), pixel_count_min={}, "
255 "pixel_count_max={}, is_external_light_filter_enabled={}, object_intensity_min={}",
256 current_config.camera_config.exposure_time, current_config.camera_config.gain,
257 current_config.camera_config.is_negative_used,
258 current_config.camera_config.light_target, current_config.window_of_interest.x,
259 current_config.window_of_interest.y, current_config.window_of_interest.width,
260 current_config.window_of_interest.height, current_config.pixel_count_min,
261 current_config.pixel_count_max, current_config.is_external_light_filter_enabled,
262 current_config.object_intensity_min);
263
264 npad_device->SetCameraFormat(format);
265}
266
267} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/irsensor/clustering_processor.h b/src/core/hle/service/hid/irsensor/clustering_processor.h
deleted file mode 100644
index 83f34734a..000000000
--- a/src/core/hle/service/hid/irsensor/clustering_processor.h
+++ /dev/null
@@ -1,115 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hid/irs_types.h"
8#include "core/hle/service/hid/irs_ring_lifo.h"
9#include "core/hle/service/hid/irsensor/processor_base.h"
10
11namespace Core {
12class System;
13}
14
15namespace Core::HID {
16class EmulatedController;
17} // namespace Core::HID
18
19namespace Service::IRS {
20class ClusteringProcessor final : public ProcessorBase {
21public:
22 explicit ClusteringProcessor(Core::System& system_, Core::IrSensor::DeviceFormat& device_format,
23 std::size_t npad_index);
24 ~ClusteringProcessor() override;
25
26 // Called when the processor is initialized
27 void StartProcessor() override;
28
29 // Called when the processor is suspended
30 void SuspendProcessor() override;
31
32 // Called when the processor is stopped
33 void StopProcessor() override;
34
35 // Sets config parameters of the camera
36 void SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config);
37
38private:
39 static constexpr auto format = Core::IrSensor::ImageTransferProcessorFormat::Size320x240;
40 static constexpr std::size_t width = 320;
41 static constexpr std::size_t height = 240;
42
43 // This is nn::irsensor::ClusteringProcessorConfig
44 struct ClusteringProcessorConfig {
45 Core::IrSensor::CameraConfig camera_config;
46 Core::IrSensor::IrsRect window_of_interest;
47 u32 pixel_count_min;
48 u32 pixel_count_max;
49 u32 object_intensity_min;
50 bool is_external_light_filter_enabled;
51 INSERT_PADDING_BYTES(3);
52 };
53 static_assert(sizeof(ClusteringProcessorConfig) == 0x30,
54 "ClusteringProcessorConfig is an invalid size");
55
56 // This is nn::irsensor::AdaptiveClusteringProcessorConfig
57 struct AdaptiveClusteringProcessorConfig {
58 Core::IrSensor::AdaptiveClusteringMode mode;
59 Core::IrSensor::AdaptiveClusteringTargetDistance target_distance;
60 };
61 static_assert(sizeof(AdaptiveClusteringProcessorConfig) == 0x8,
62 "AdaptiveClusteringProcessorConfig is an invalid size");
63
64 // This is nn::irsensor::ClusteringData
65 struct ClusteringData {
66 f32 average_intensity;
67 Core::IrSensor::IrsCentroid centroid;
68 u32 pixel_count;
69 Core::IrSensor::IrsRect bound;
70 };
71 static_assert(sizeof(ClusteringData) == 0x18, "ClusteringData is an invalid size");
72
73 // This is nn::irsensor::ClusteringProcessorState
74 struct ClusteringProcessorState {
75 s64 sampling_number;
76 u64 timestamp;
77 u8 object_count;
78 INSERT_PADDING_BYTES(3);
79 Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level;
80 std::array<ClusteringData, 0x10> data;
81 };
82 static_assert(sizeof(ClusteringProcessorState) == 0x198,
83 "ClusteringProcessorState is an invalid size");
84
85 struct ClusteringSharedMemory {
86 Service::IRS::Lifo<ClusteringProcessorState, 6> clustering_lifo;
87 static_assert(sizeof(clustering_lifo) == 0x9A0, "clustering_lifo is an invalid size");
88 INSERT_PADDING_WORDS(0x11F);
89 };
90 static_assert(sizeof(ClusteringSharedMemory) == 0xE20,
91 "ClusteringSharedMemory is an invalid size");
92
93 void OnControllerUpdate(Core::HID::ControllerTriggerType type);
94 void RemoveLowIntensityData(std::vector<u8>& data);
95 ClusteringData GetClusterProperties(std::vector<u8>& data, std::size_t x, std::size_t y);
96 ClusteringData GetPixelProperties(const std::vector<u8>& data, std::size_t x,
97 std::size_t y) const;
98 ClusteringData MergeCluster(const ClusteringData a, const ClusteringData b) const;
99 u8 GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const;
100 void SetPixel(std::vector<u8>& data, std::size_t x, std::size_t y, u8 value);
101
102 // Sets config parameters of the camera
103 void SetDefaultConfig();
104
105 ClusteringSharedMemory* shared_memory = nullptr;
106 ClusteringProcessorState next_state{};
107
108 ClusteringProcessorConfig current_config{};
109 Core::IrSensor::DeviceFormat& device;
110 Core::HID::EmulatedController* npad_device;
111 int callback_key{};
112
113 Core::System& system;
114};
115} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp b/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp
deleted file mode 100644
index 22067a591..000000000
--- a/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/core.h"
5#include "core/hid/emulated_controller.h"
6#include "core/hid/hid_core.h"
7#include "core/hle/service/hid/irsensor/image_transfer_processor.h"
8#include "core/memory.h"
9
10namespace Service::IRS {
11ImageTransferProcessor::ImageTransferProcessor(Core::System& system_,
12 Core::IrSensor::DeviceFormat& device_format,
13 std::size_t npad_index)
14 : device{device_format}, system{system_} {
15 npad_device = system.HIDCore().GetEmulatedControllerByIndex(npad_index);
16
17 Core::HID::ControllerUpdateCallback engine_callback{
18 .on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); },
19 .is_npad_service = true,
20 };
21 callback_key = npad_device->SetCallback(engine_callback);
22
23 device.mode = Core::IrSensor::IrSensorMode::ImageTransferProcessor;
24 device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
25 device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
26}
27
28ImageTransferProcessor::~ImageTransferProcessor() {
29 npad_device->DeleteCallback(callback_key);
30};
31
32void ImageTransferProcessor::StartProcessor() {
33 is_active = true;
34 device.camera_status = Core::IrSensor::IrCameraStatus::Available;
35 device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready;
36 processor_state.sampling_number = 0;
37 processor_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low;
38}
39
40void ImageTransferProcessor::SuspendProcessor() {}
41
42void ImageTransferProcessor::StopProcessor() {}
43
44void ImageTransferProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type) {
45 if (type != Core::HID::ControllerTriggerType::IrSensor) {
46 return;
47 }
48 if (transfer_memory == 0) {
49 return;
50 }
51
52 const auto& camera_data = npad_device->GetCamera();
53
54 // This indicates how much ambient light is present
55 processor_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low;
56 processor_state.sampling_number = camera_data.sample;
57
58 if (camera_data.format != current_config.origin_format) {
59 LOG_WARNING(Service_IRS, "Wrong Input format {} expected {}", camera_data.format,
60 current_config.origin_format);
61 system.ApplicationMemory().ZeroBlock(transfer_memory,
62 GetDataSize(current_config.trimming_format));
63 return;
64 }
65
66 if (current_config.origin_format > current_config.trimming_format) {
67 LOG_WARNING(Service_IRS, "Origin format {} is smaller than trimming format {}",
68 current_config.origin_format, current_config.trimming_format);
69 system.ApplicationMemory().ZeroBlock(transfer_memory,
70 GetDataSize(current_config.trimming_format));
71 return;
72 }
73
74 std::vector<u8> window_data{};
75 const auto origin_width = GetDataWidth(current_config.origin_format);
76 const auto origin_height = GetDataHeight(current_config.origin_format);
77 const auto trimming_width = GetDataWidth(current_config.trimming_format);
78 const auto trimming_height = GetDataHeight(current_config.trimming_format);
79 window_data.resize(GetDataSize(current_config.trimming_format));
80
81 if (trimming_width + current_config.trimming_start_x > origin_width ||
82 trimming_height + current_config.trimming_start_y > origin_height) {
83 LOG_WARNING(Service_IRS,
84 "Trimming area ({}, {}, {}, {}) is outside of origin area ({}, {})",
85 current_config.trimming_start_x, current_config.trimming_start_y,
86 trimming_width, trimming_height, origin_width, origin_height);
87 system.ApplicationMemory().ZeroBlock(transfer_memory,
88 GetDataSize(current_config.trimming_format));
89 return;
90 }
91
92 for (std::size_t y = 0; y < trimming_height; y++) {
93 for (std::size_t x = 0; x < trimming_width; x++) {
94 const std::size_t window_index = (y * trimming_width) + x;
95 const std::size_t origin_index =
96 ((y + current_config.trimming_start_y) * origin_width) + x +
97 current_config.trimming_start_x;
98 window_data[window_index] = camera_data.data[origin_index];
99 }
100 }
101
102 system.ApplicationMemory().WriteBlock(transfer_memory, window_data.data(),
103 GetDataSize(current_config.trimming_format));
104
105 if (!IsProcessorActive()) {
106 StartProcessor();
107 }
108}
109
110void ImageTransferProcessor::SetConfig(Core::IrSensor::PackedImageTransferProcessorConfig config) {
111 current_config.camera_config.exposure_time = config.camera_config.exposure_time;
112 current_config.camera_config.gain = config.camera_config.gain;
113 current_config.camera_config.is_negative_used = config.camera_config.is_negative_used;
114 current_config.camera_config.light_target =
115 static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target);
116 current_config.origin_format =
117 static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.format);
118 current_config.trimming_format =
119 static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.format);
120 current_config.trimming_start_x = 0;
121 current_config.trimming_start_y = 0;
122
123 npad_device->SetCameraFormat(current_config.origin_format);
124}
125
126void ImageTransferProcessor::SetConfig(
127 Core::IrSensor::PackedImageTransferProcessorExConfig config) {
128 current_config.camera_config.exposure_time = config.camera_config.exposure_time;
129 current_config.camera_config.gain = config.camera_config.gain;
130 current_config.camera_config.is_negative_used = config.camera_config.is_negative_used;
131 current_config.camera_config.light_target =
132 static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target);
133 current_config.origin_format =
134 static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.origin_format);
135 current_config.trimming_format =
136 static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.trimming_format);
137 current_config.trimming_start_x = config.trimming_start_x;
138 current_config.trimming_start_y = config.trimming_start_y;
139
140 npad_device->SetCameraFormat(current_config.origin_format);
141}
142
143void ImageTransferProcessor::SetTransferMemoryAddress(Common::ProcessAddress t_mem) {
144 transfer_memory = t_mem;
145}
146
147Core::IrSensor::ImageTransferProcessorState ImageTransferProcessor::GetState(
148 std::vector<u8>& data) const {
149 const auto size = GetDataSize(current_config.trimming_format);
150 data.resize(size);
151 system.ApplicationMemory().ReadBlock(transfer_memory, data.data(), size);
152 return processor_state;
153}
154
155} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/irsensor/image_transfer_processor.h b/src/core/hle/service/hid/irsensor/image_transfer_processor.h
deleted file mode 100644
index 7f42d8453..000000000
--- a/src/core/hle/service/hid/irsensor/image_transfer_processor.h
+++ /dev/null
@@ -1,77 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/typed_address.h"
7#include "core/hid/irs_types.h"
8#include "core/hle/service/hid/irsensor/processor_base.h"
9
10namespace Core {
11class System;
12}
13
14namespace Core::HID {
15class EmulatedController;
16} // namespace Core::HID
17
18namespace Service::IRS {
19class ImageTransferProcessor final : public ProcessorBase {
20public:
21 explicit ImageTransferProcessor(Core::System& system_,
22 Core::IrSensor::DeviceFormat& device_format,
23 std::size_t npad_index);
24 ~ImageTransferProcessor() override;
25
26 // Called when the processor is initialized
27 void StartProcessor() override;
28
29 // Called when the processor is suspended
30 void SuspendProcessor() override;
31
32 // Called when the processor is stopped
33 void StopProcessor() override;
34
35 // Sets config parameters of the camera
36 void SetConfig(Core::IrSensor::PackedImageTransferProcessorConfig config);
37 void SetConfig(Core::IrSensor::PackedImageTransferProcessorExConfig config);
38
39 // Transfer memory where the image data will be stored
40 void SetTransferMemoryAddress(Common::ProcessAddress t_mem);
41
42 Core::IrSensor::ImageTransferProcessorState GetState(std::vector<u8>& data) const;
43
44private:
45 // This is nn::irsensor::ImageTransferProcessorConfig
46 struct ImageTransferProcessorConfig {
47 Core::IrSensor::CameraConfig camera_config;
48 Core::IrSensor::ImageTransferProcessorFormat format;
49 };
50 static_assert(sizeof(ImageTransferProcessorConfig) == 0x20,
51 "ImageTransferProcessorConfig is an invalid size");
52
53 // This is nn::irsensor::ImageTransferProcessorExConfig
54 struct ImageTransferProcessorExConfig {
55 Core::IrSensor::CameraConfig camera_config;
56 Core::IrSensor::ImageTransferProcessorFormat origin_format;
57 Core::IrSensor::ImageTransferProcessorFormat trimming_format;
58 u16 trimming_start_x;
59 u16 trimming_start_y;
60 bool is_external_light_filter_enabled;
61 INSERT_PADDING_BYTES(3);
62 };
63 static_assert(sizeof(ImageTransferProcessorExConfig) == 0x28,
64 "ImageTransferProcessorExConfig is an invalid size");
65
66 void OnControllerUpdate(Core::HID::ControllerTriggerType type);
67
68 ImageTransferProcessorExConfig current_config{};
69 Core::IrSensor::ImageTransferProcessorState processor_state{};
70 Core::IrSensor::DeviceFormat& device;
71 Core::HID::EmulatedController* npad_device;
72 int callback_key{};
73
74 Core::System& system;
75 Common::ProcessAddress transfer_memory{};
76};
77} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/irsensor/ir_led_processor.cpp b/src/core/hle/service/hid/irsensor/ir_led_processor.cpp
deleted file mode 100644
index 8e6dd99e4..000000000
--- a/src/core/hle/service/hid/irsensor/ir_led_processor.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/hid/irsensor/ir_led_processor.h"
5
6namespace Service::IRS {
7IrLedProcessor::IrLedProcessor(Core::IrSensor::DeviceFormat& device_format)
8 : device(device_format) {
9 device.mode = Core::IrSensor::IrSensorMode::IrLedProcessor;
10 device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
11 device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
12}
13
14IrLedProcessor::~IrLedProcessor() = default;
15
16void IrLedProcessor::StartProcessor() {}
17
18void IrLedProcessor::SuspendProcessor() {}
19
20void IrLedProcessor::StopProcessor() {}
21
22void IrLedProcessor::SetConfig(Core::IrSensor::PackedIrLedProcessorConfig config) {
23 current_config.light_target =
24 static_cast<Core::IrSensor::CameraLightTarget>(config.light_target);
25}
26
27} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/irsensor/ir_led_processor.h b/src/core/hle/service/hid/irsensor/ir_led_processor.h
deleted file mode 100644
index c3d8693c9..000000000
--- a/src/core/hle/service/hid/irsensor/ir_led_processor.h
+++ /dev/null
@@ -1,47 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/bit_field.h"
7#include "common/common_types.h"
8#include "core/hid/irs_types.h"
9#include "core/hle/service/hid/irsensor/processor_base.h"
10
11namespace Service::IRS {
12class IrLedProcessor final : public ProcessorBase {
13public:
14 explicit IrLedProcessor(Core::IrSensor::DeviceFormat& device_format);
15 ~IrLedProcessor() override;
16
17 // Called when the processor is initialized
18 void StartProcessor() override;
19
20 // Called when the processor is suspended
21 void SuspendProcessor() override;
22
23 // Called when the processor is stopped
24 void StopProcessor() override;
25
26 // Sets config parameters of the camera
27 void SetConfig(Core::IrSensor::PackedIrLedProcessorConfig config);
28
29private:
30 // This is nn::irsensor::IrLedProcessorConfig
31 struct IrLedProcessorConfig {
32 Core::IrSensor::CameraLightTarget light_target;
33 };
34 static_assert(sizeof(IrLedProcessorConfig) == 0x4, "IrLedProcessorConfig is an invalid size");
35
36 struct IrLedProcessorState {
37 s64 sampling_number;
38 u64 timestamp;
39 std::array<u8, 0x8> data;
40 };
41 static_assert(sizeof(IrLedProcessorState) == 0x18, "IrLedProcessorState is an invalid size");
42
43 IrLedProcessorConfig current_config{};
44 Core::IrSensor::DeviceFormat& device;
45};
46
47} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/irsensor/moment_processor.cpp b/src/core/hle/service/hid/irsensor/moment_processor.cpp
deleted file mode 100644
index cf045bda7..000000000
--- a/src/core/hle/service/hid/irsensor/moment_processor.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/core.h"
5#include "core/core_timing.h"
6#include "core/hid/emulated_controller.h"
7#include "core/hid/hid_core.h"
8#include "core/hle/service/hid/irsensor/moment_processor.h"
9
10namespace Service::IRS {
11static constexpr auto format = Core::IrSensor::ImageTransferProcessorFormat::Size40x30;
12static constexpr std::size_t ImageWidth = 40;
13static constexpr std::size_t ImageHeight = 30;
14
15MomentProcessor::MomentProcessor(Core::System& system_, Core::IrSensor::DeviceFormat& device_format,
16 std::size_t npad_index)
17 : device(device_format), system{system_} {
18 npad_device = system.HIDCore().GetEmulatedControllerByIndex(npad_index);
19
20 device.mode = Core::IrSensor::IrSensorMode::MomentProcessor;
21 device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
22 device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
23
24 shared_memory = std::construct_at(
25 reinterpret_cast<MomentSharedMemory*>(&device_format.state.processor_raw_data));
26
27 Core::HID::ControllerUpdateCallback engine_callback{
28 .on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); },
29 .is_npad_service = true,
30 };
31 callback_key = npad_device->SetCallback(engine_callback);
32}
33
34MomentProcessor::~MomentProcessor() {
35 npad_device->DeleteCallback(callback_key);
36};
37
38void MomentProcessor::StartProcessor() {
39 device.camera_status = Core::IrSensor::IrCameraStatus::Available;
40 device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready;
41}
42
43void MomentProcessor::SuspendProcessor() {}
44
45void MomentProcessor::StopProcessor() {}
46
47void MomentProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type) {
48 if (type != Core::HID::ControllerTriggerType::IrSensor) {
49 return;
50 }
51
52 next_state = {};
53 const auto& camera_data = npad_device->GetCamera();
54
55 const auto window_width = static_cast<std::size_t>(current_config.window_of_interest.width);
56 const auto window_height = static_cast<std::size_t>(current_config.window_of_interest.height);
57 const auto window_start_x = static_cast<std::size_t>(current_config.window_of_interest.x);
58 const auto window_start_y = static_cast<std::size_t>(current_config.window_of_interest.y);
59
60 const std::size_t block_width = window_width / Columns;
61 const std::size_t block_height = window_height / Rows;
62
63 for (std::size_t row = 0; row < Rows; row++) {
64 for (std::size_t column = 0; column < Columns; column++) {
65 const size_t x_pos = (column * block_width) + window_start_x;
66 const size_t y_pos = (row * block_height) + window_start_y;
67 auto& statistic = next_state.statistic[column + (row * Columns)];
68 statistic = GetStatistic(camera_data.data, x_pos, y_pos, block_width, block_height);
69 }
70 }
71
72 next_state.sampling_number = camera_data.sample;
73 next_state.timestamp = system.CoreTiming().GetGlobalTimeNs().count();
74 next_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low;
75 shared_memory->moment_lifo.WriteNextEntry(next_state);
76
77 if (!IsProcessorActive()) {
78 StartProcessor();
79 }
80}
81
82u8 MomentProcessor::GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const {
83 if ((y * ImageWidth) + x >= data.size()) {
84 return 0;
85 }
86 return data[(y * ImageWidth) + x];
87}
88
89MomentProcessor::MomentStatistic MomentProcessor::GetStatistic(const std::vector<u8>& data,
90 std::size_t start_x,
91 std::size_t start_y,
92 std::size_t width,
93 std::size_t height) const {
94 // The actual implementation is always 320x240
95 static constexpr std::size_t RealWidth = 320;
96 static constexpr std::size_t RealHeight = 240;
97 static constexpr std::size_t Threshold = 30;
98 MomentStatistic statistic{};
99 std::size_t active_points{};
100
101 // Sum all data points on the block that meet with the threshold
102 for (std::size_t y = 0; y < width; y++) {
103 for (std::size_t x = 0; x < height; x++) {
104 const size_t x_pos = x + start_x;
105 const size_t y_pos = y + start_y;
106 const auto pixel =
107 GetPixel(data, x_pos * ImageWidth / RealWidth, y_pos * ImageHeight / RealHeight);
108
109 if (pixel < Threshold) {
110 continue;
111 }
112
113 statistic.average_intensity += pixel;
114
115 statistic.centroid.x += static_cast<float>(x_pos);
116 statistic.centroid.y += static_cast<float>(y_pos);
117
118 active_points++;
119 }
120 }
121
122 // Return an empty field if no points were available
123 if (active_points == 0) {
124 return {};
125 }
126
127 // Finally calculate the actual centroid and average intensity
128 statistic.centroid.x /= static_cast<float>(active_points);
129 statistic.centroid.y /= static_cast<float>(active_points);
130 statistic.average_intensity /= static_cast<f32>(width * height);
131
132 return statistic;
133}
134
135void MomentProcessor::SetConfig(Core::IrSensor::PackedMomentProcessorConfig config) {
136 current_config.camera_config.exposure_time = config.camera_config.exposure_time;
137 current_config.camera_config.gain = config.camera_config.gain;
138 current_config.camera_config.is_negative_used = config.camera_config.is_negative_used;
139 current_config.camera_config.light_target =
140 static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target);
141 current_config.window_of_interest = config.window_of_interest;
142 current_config.preprocess =
143 static_cast<Core::IrSensor::MomentProcessorPreprocess>(config.preprocess);
144 current_config.preprocess_intensity_threshold = config.preprocess_intensity_threshold;
145
146 npad_device->SetCameraFormat(format);
147}
148
149} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/irsensor/moment_processor.h b/src/core/hle/service/hid/irsensor/moment_processor.h
deleted file mode 100644
index 398cfbdc1..000000000
--- a/src/core/hle/service/hid/irsensor/moment_processor.h
+++ /dev/null
@@ -1,91 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/bit_field.h"
7#include "common/common_types.h"
8#include "core/hid/irs_types.h"
9#include "core/hle/service/hid/irs_ring_lifo.h"
10#include "core/hle/service/hid/irsensor/processor_base.h"
11
12namespace Core {
13class System;
14}
15
16namespace Core::HID {
17class EmulatedController;
18} // namespace Core::HID
19
20namespace Service::IRS {
21class MomentProcessor final : public ProcessorBase {
22public:
23 explicit MomentProcessor(Core::System& system_, Core::IrSensor::DeviceFormat& device_format,
24 std::size_t npad_index);
25 ~MomentProcessor() override;
26
27 // Called when the processor is initialized
28 void StartProcessor() override;
29
30 // Called when the processor is suspended
31 void SuspendProcessor() override;
32
33 // Called when the processor is stopped
34 void StopProcessor() override;
35
36 // Sets config parameters of the camera
37 void SetConfig(Core::IrSensor::PackedMomentProcessorConfig config);
38
39private:
40 static constexpr std::size_t Columns = 8;
41 static constexpr std::size_t Rows = 6;
42
43 // This is nn::irsensor::MomentProcessorConfig
44 struct MomentProcessorConfig {
45 Core::IrSensor::CameraConfig camera_config;
46 Core::IrSensor::IrsRect window_of_interest;
47 Core::IrSensor::MomentProcessorPreprocess preprocess;
48 u32 preprocess_intensity_threshold;
49 };
50 static_assert(sizeof(MomentProcessorConfig) == 0x28,
51 "MomentProcessorConfig is an invalid size");
52
53 // This is nn::irsensor::MomentStatistic
54 struct MomentStatistic {
55 f32 average_intensity;
56 Core::IrSensor::IrsCentroid centroid;
57 };
58 static_assert(sizeof(MomentStatistic) == 0xC, "MomentStatistic is an invalid size");
59
60 // This is nn::irsensor::MomentProcessorState
61 struct MomentProcessorState {
62 s64 sampling_number;
63 u64 timestamp;
64 Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level;
65 INSERT_PADDING_BYTES(4);
66 std::array<MomentStatistic, Columns * Rows> statistic;
67 };
68 static_assert(sizeof(MomentProcessorState) == 0x258, "MomentProcessorState is an invalid size");
69
70 struct MomentSharedMemory {
71 Service::IRS::Lifo<MomentProcessorState, 6> moment_lifo;
72 };
73 static_assert(sizeof(MomentSharedMemory) == 0xE20, "MomentSharedMemory is an invalid size");
74
75 void OnControllerUpdate(Core::HID::ControllerTriggerType type);
76 u8 GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const;
77 MomentStatistic GetStatistic(const std::vector<u8>& data, std::size_t start_x,
78 std::size_t start_y, std::size_t width, std::size_t height) const;
79
80 MomentSharedMemory* shared_memory = nullptr;
81 MomentProcessorState next_state{};
82
83 MomentProcessorConfig current_config{};
84 Core::IrSensor::DeviceFormat& device;
85 Core::HID::EmulatedController* npad_device;
86 int callback_key{};
87
88 Core::System& system;
89};
90
91} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/irsensor/pointing_processor.cpp b/src/core/hle/service/hid/irsensor/pointing_processor.cpp
deleted file mode 100644
index 929f177fc..000000000
--- a/src/core/hle/service/hid/irsensor/pointing_processor.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/hid/irsensor/pointing_processor.h"
5
6namespace Service::IRS {
7PointingProcessor::PointingProcessor(Core::IrSensor::DeviceFormat& device_format)
8 : device(device_format) {
9 device.mode = Core::IrSensor::IrSensorMode::PointingProcessorMarker;
10 device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
11 device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
12}
13
14PointingProcessor::~PointingProcessor() = default;
15
16void PointingProcessor::StartProcessor() {}
17
18void PointingProcessor::SuspendProcessor() {}
19
20void PointingProcessor::StopProcessor() {}
21
22void PointingProcessor::SetConfig(Core::IrSensor::PackedPointingProcessorConfig config) {
23 current_config.window_of_interest = config.window_of_interest;
24}
25
26} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/irsensor/pointing_processor.h b/src/core/hle/service/hid/irsensor/pointing_processor.h
deleted file mode 100644
index d63423aff..000000000
--- a/src/core/hle/service/hid/irsensor/pointing_processor.h
+++ /dev/null
@@ -1,61 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hid/irs_types.h"
8#include "core/hle/service/hid/irsensor/processor_base.h"
9
10namespace Service::IRS {
11class PointingProcessor final : public ProcessorBase {
12public:
13 explicit PointingProcessor(Core::IrSensor::DeviceFormat& device_format);
14 ~PointingProcessor() override;
15
16 // Called when the processor is initialized
17 void StartProcessor() override;
18
19 // Called when the processor is suspended
20 void SuspendProcessor() override;
21
22 // Called when the processor is stopped
23 void StopProcessor() override;
24
25 // Sets config parameters of the camera
26 void SetConfig(Core::IrSensor::PackedPointingProcessorConfig config);
27
28private:
29 // This is nn::irsensor::PointingProcessorConfig
30 struct PointingProcessorConfig {
31 Core::IrSensor::IrsRect window_of_interest;
32 };
33 static_assert(sizeof(PointingProcessorConfig) == 0x8,
34 "PointingProcessorConfig is an invalid size");
35
36 struct PointingProcessorMarkerData {
37 u8 pointing_status;
38 INSERT_PADDING_BYTES(3);
39 u32 unknown;
40 float unknown_float1;
41 float position_x;
42 float position_y;
43 float unknown_float2;
44 Core::IrSensor::IrsRect window_of_interest;
45 };
46 static_assert(sizeof(PointingProcessorMarkerData) == 0x20,
47 "PointingProcessorMarkerData is an invalid size");
48
49 struct PointingProcessorMarkerState {
50 s64 sampling_number;
51 u64 timestamp;
52 std::array<PointingProcessorMarkerData, 0x3> data;
53 };
54 static_assert(sizeof(PointingProcessorMarkerState) == 0x70,
55 "PointingProcessorMarkerState is an invalid size");
56
57 PointingProcessorConfig current_config{};
58 Core::IrSensor::DeviceFormat& device;
59};
60
61} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/irsensor/processor_base.cpp b/src/core/hle/service/hid/irsensor/processor_base.cpp
deleted file mode 100644
index 4d43ca17a..000000000
--- a/src/core/hle/service/hid/irsensor/processor_base.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/hid/irsensor/processor_base.h"
5
6namespace Service::IRS {
7
8ProcessorBase::ProcessorBase() {}
9ProcessorBase::~ProcessorBase() = default;
10
11bool ProcessorBase::IsProcessorActive() const {
12 return is_active;
13}
14
15std::size_t ProcessorBase::GetDataSize(Core::IrSensor::ImageTransferProcessorFormat format) const {
16 switch (format) {
17 case Core::IrSensor::ImageTransferProcessorFormat::Size320x240:
18 return 320 * 240;
19 case Core::IrSensor::ImageTransferProcessorFormat::Size160x120:
20 return 160 * 120;
21 case Core::IrSensor::ImageTransferProcessorFormat::Size80x60:
22 return 80 * 60;
23 case Core::IrSensor::ImageTransferProcessorFormat::Size40x30:
24 return 40 * 30;
25 case Core::IrSensor::ImageTransferProcessorFormat::Size20x15:
26 return 20 * 15;
27 default:
28 return 0;
29 }
30}
31
32std::size_t ProcessorBase::GetDataWidth(Core::IrSensor::ImageTransferProcessorFormat format) const {
33 switch (format) {
34 case Core::IrSensor::ImageTransferProcessorFormat::Size320x240:
35 return 320;
36 case Core::IrSensor::ImageTransferProcessorFormat::Size160x120:
37 return 160;
38 case Core::IrSensor::ImageTransferProcessorFormat::Size80x60:
39 return 80;
40 case Core::IrSensor::ImageTransferProcessorFormat::Size40x30:
41 return 40;
42 case Core::IrSensor::ImageTransferProcessorFormat::Size20x15:
43 return 20;
44 default:
45 return 0;
46 }
47}
48
49std::size_t ProcessorBase::GetDataHeight(
50 Core::IrSensor::ImageTransferProcessorFormat format) const {
51 switch (format) {
52 case Core::IrSensor::ImageTransferProcessorFormat::Size320x240:
53 return 240;
54 case Core::IrSensor::ImageTransferProcessorFormat::Size160x120:
55 return 120;
56 case Core::IrSensor::ImageTransferProcessorFormat::Size80x60:
57 return 60;
58 case Core::IrSensor::ImageTransferProcessorFormat::Size40x30:
59 return 30;
60 case Core::IrSensor::ImageTransferProcessorFormat::Size20x15:
61 return 15;
62 default:
63 return 0;
64 }
65}
66
67} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/irsensor/processor_base.h b/src/core/hle/service/hid/irsensor/processor_base.h
deleted file mode 100644
index bc0d2977b..000000000
--- a/src/core/hle/service/hid/irsensor/processor_base.h
+++ /dev/null
@@ -1,33 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hid/irs_types.h"
8
9namespace Service::IRS {
10class ProcessorBase {
11public:
12 explicit ProcessorBase();
13 virtual ~ProcessorBase();
14
15 virtual void StartProcessor() = 0;
16 virtual void SuspendProcessor() = 0;
17 virtual void StopProcessor() = 0;
18
19 bool IsProcessorActive() const;
20
21protected:
22 /// Returns the number of bytes the image uses
23 std::size_t GetDataSize(Core::IrSensor::ImageTransferProcessorFormat format) const;
24
25 /// Returns the width of the image
26 std::size_t GetDataWidth(Core::IrSensor::ImageTransferProcessorFormat format) const;
27
28 /// Returns the height of the image
29 std::size_t GetDataHeight(Core::IrSensor::ImageTransferProcessorFormat format) const;
30
31 bool is_active{false};
32};
33} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp b/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp
deleted file mode 100644
index e691c840a..000000000
--- a/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/hid/irsensor/tera_plugin_processor.h"
5
6namespace Service::IRS {
7TeraPluginProcessor::TeraPluginProcessor(Core::IrSensor::DeviceFormat& device_format)
8 : device(device_format) {
9 device.mode = Core::IrSensor::IrSensorMode::TeraPluginProcessor;
10 device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
11 device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
12}
13
14TeraPluginProcessor::~TeraPluginProcessor() = default;
15
16void TeraPluginProcessor::StartProcessor() {}
17
18void TeraPluginProcessor::SuspendProcessor() {}
19
20void TeraPluginProcessor::StopProcessor() {}
21
22void TeraPluginProcessor::SetConfig(Core::IrSensor::PackedTeraPluginProcessorConfig config) {
23 current_config.mode = config.mode;
24 current_config.unknown_1 = config.unknown_1;
25 current_config.unknown_2 = config.unknown_2;
26 current_config.unknown_3 = config.unknown_3;
27}
28
29} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/irsensor/tera_plugin_processor.h b/src/core/hle/service/hid/irsensor/tera_plugin_processor.h
deleted file mode 100644
index bbea7ed0b..000000000
--- a/src/core/hle/service/hid/irsensor/tera_plugin_processor.h
+++ /dev/null
@@ -1,53 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/bit_field.h"
7#include "common/common_types.h"
8#include "core/hid/irs_types.h"
9#include "core/hle/service/hid/irsensor/processor_base.h"
10
11namespace Service::IRS {
12class TeraPluginProcessor final : public ProcessorBase {
13public:
14 explicit TeraPluginProcessor(Core::IrSensor::DeviceFormat& device_format);
15 ~TeraPluginProcessor() override;
16
17 // Called when the processor is initialized
18 void StartProcessor() override;
19
20 // Called when the processor is suspended
21 void SuspendProcessor() override;
22
23 // Called when the processor is stopped
24 void StopProcessor() override;
25
26 // Sets config parameters of the camera
27 void SetConfig(Core::IrSensor::PackedTeraPluginProcessorConfig config);
28
29private:
30 // This is nn::irsensor::TeraPluginProcessorConfig
31 struct TeraPluginProcessorConfig {
32 u8 mode;
33 u8 unknown_1;
34 u8 unknown_2;
35 u8 unknown_3;
36 };
37 static_assert(sizeof(TeraPluginProcessorConfig) == 0x4,
38 "TeraPluginProcessorConfig is an invalid size");
39
40 struct TeraPluginProcessorState {
41 s64 sampling_number;
42 u64 timestamp;
43 Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level;
44 std::array<u8, 0x12c> data;
45 };
46 static_assert(sizeof(TeraPluginProcessorState) == 0x140,
47 "TeraPluginProcessorState is an invalid size");
48
49 TeraPluginProcessorConfig current_config{};
50 Core::IrSensor::DeviceFormat& device;
51};
52
53} // namespace Service::IRS
diff --git a/src/core/hle/service/hid/resource_manager.cpp b/src/core/hle/service/hid/resource_manager.cpp
deleted file mode 100644
index 1f41e645d..000000000
--- a/src/core/hle/service/hid/resource_manager.cpp
+++ /dev/null
@@ -1,362 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/logging/log.h"
5#include "core/core.h"
6#include "core/core_timing.h"
7#include "core/hid/hid_core.h"
8#include "core/hle/kernel/k_shared_memory.h"
9#include "core/hle/service/hid/resource_manager.h"
10#include "core/hle/service/ipc_helpers.h"
11
12#include "core/hle/service/hid/controllers/applet_resource.h"
13#include "core/hle/service/hid/controllers/capture_button.h"
14#include "core/hle/service/hid/controllers/console_six_axis.h"
15#include "core/hle/service/hid/controllers/debug_mouse.h"
16#include "core/hle/service/hid/controllers/debug_pad.h"
17#include "core/hle/service/hid/controllers/digitizer.h"
18#include "core/hle/service/hid/controllers/gesture.h"
19#include "core/hle/service/hid/controllers/home_button.h"
20#include "core/hle/service/hid/controllers/keyboard.h"
21#include "core/hle/service/hid/controllers/mouse.h"
22#include "core/hle/service/hid/controllers/npad.h"
23#include "core/hle/service/hid/controllers/palma.h"
24#include "core/hle/service/hid/controllers/seven_six_axis.h"
25#include "core/hle/service/hid/controllers/six_axis.h"
26#include "core/hle/service/hid/controllers/sleep_button.h"
27#include "core/hle/service/hid/controllers/touchscreen.h"
28#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
29#include "core/hle/service/hid/controllers/unique_pad.h"
30
31namespace Service::HID {
32
33// Updating period for each HID device.
34// Period time is obtained by measuring the number of samples in a second on HW using a homebrew
35// Correct npad_update_ns is 4ms this is overclocked to lower input lag
36constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz)
37constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz)
38constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
39constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
40
41ResourceManager::ResourceManager(Core::System& system_)
42 : system{system_}, service_context{system_, "hid"} {
43 applet_resource = std::make_shared<AppletResource>(system);
44}
45
46ResourceManager::~ResourceManager() = default;
47
48void ResourceManager::Initialize() {
49 if (is_initialized) {
50 return;
51 }
52
53 system.HIDCore().ReloadInputDevices();
54
55 InitializeHidCommonSampler();
56 InitializeTouchScreenSampler();
57 InitializeConsoleSixAxisSampler();
58 InitializeAHidSampler();
59
60 is_initialized = true;
61}
62
63std::shared_ptr<AppletResource> ResourceManager::GetAppletResource() const {
64 return applet_resource;
65}
66
67std::shared_ptr<CaptureButton> ResourceManager::GetCaptureButton() const {
68 return capture_button;
69}
70
71std::shared_ptr<ConsoleSixAxis> ResourceManager::GetConsoleSixAxis() const {
72 return console_six_axis;
73}
74
75std::shared_ptr<DebugMouse> ResourceManager::GetDebugMouse() const {
76 return debug_mouse;
77}
78
79std::shared_ptr<DebugPad> ResourceManager::GetDebugPad() const {
80 return debug_pad;
81}
82
83std::shared_ptr<Digitizer> ResourceManager::GetDigitizer() const {
84 return digitizer;
85}
86
87std::shared_ptr<Gesture> ResourceManager::GetGesture() const {
88 return gesture;
89}
90
91std::shared_ptr<HomeButton> ResourceManager::GetHomeButton() const {
92 return home_button;
93}
94
95std::shared_ptr<Keyboard> ResourceManager::GetKeyboard() const {
96 return keyboard;
97}
98
99std::shared_ptr<Mouse> ResourceManager::GetMouse() const {
100 return mouse;
101}
102
103std::shared_ptr<NPad> ResourceManager::GetNpad() const {
104 return npad;
105}
106
107std::shared_ptr<Palma> ResourceManager::GetPalma() const {
108 return palma;
109}
110
111std::shared_ptr<SevenSixAxis> ResourceManager::GetSevenSixAxis() const {
112 return seven_six_axis;
113}
114
115std::shared_ptr<SixAxis> ResourceManager::GetSixAxis() const {
116 return six_axis;
117}
118
119std::shared_ptr<SleepButton> ResourceManager::GetSleepButton() const {
120 return sleep_button;
121}
122
123std::shared_ptr<TouchScreen> ResourceManager::GetTouchScreen() const {
124 return touch_screen;
125}
126
127std::shared_ptr<UniquePad> ResourceManager::GetUniquePad() const {
128 return unique_pad;
129}
130
131Result ResourceManager::CreateAppletResource(u64 aruid) {
132 if (aruid == SystemAruid) {
133 const auto result = RegisterCoreAppletResource();
134 if (result.IsError()) {
135 return result;
136 }
137 return GetNpad()->ActivateNpadResource();
138 }
139
140 const auto result = CreateAppletResourceImpl(aruid);
141 if (result.IsError()) {
142 return result;
143 }
144
145 // Homebrew doesn't try to activate some controllers, so we activate them by default
146 npad->Activate();
147 six_axis->Activate();
148 touch_screen->Activate();
149
150 return GetNpad()->ActivateNpadResource(aruid);
151}
152
153Result ResourceManager::CreateAppletResourceImpl(u64 aruid) {
154 std::scoped_lock lock{shared_mutex};
155 return applet_resource->CreateAppletResource(aruid);
156}
157
158void ResourceManager::InitializeHidCommonSampler() {
159 debug_pad = std::make_shared<DebugPad>(system.HIDCore());
160 mouse = std::make_shared<Mouse>(system.HIDCore());
161 debug_mouse = std::make_shared<DebugMouse>(system.HIDCore());
162 keyboard = std::make_shared<Keyboard>(system.HIDCore());
163 unique_pad = std::make_shared<UniquePad>(system.HIDCore());
164 npad = std::make_shared<NPad>(system.HIDCore(), service_context);
165 gesture = std::make_shared<Gesture>(system.HIDCore());
166 home_button = std::make_shared<HomeButton>(system.HIDCore());
167 sleep_button = std::make_shared<SleepButton>(system.HIDCore());
168 capture_button = std::make_shared<CaptureButton>(system.HIDCore());
169 digitizer = std::make_shared<Digitizer>(system.HIDCore());
170
171 palma = std::make_shared<Palma>(system.HIDCore(), service_context);
172 six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad);
173
174 debug_pad->SetAppletResource(applet_resource, &shared_mutex);
175 digitizer->SetAppletResource(applet_resource, &shared_mutex);
176 keyboard->SetAppletResource(applet_resource, &shared_mutex);
177 npad->SetNpadExternals(applet_resource, &shared_mutex);
178 six_axis->SetAppletResource(applet_resource, &shared_mutex);
179 mouse->SetAppletResource(applet_resource, &shared_mutex);
180 debug_mouse->SetAppletResource(applet_resource, &shared_mutex);
181 home_button->SetAppletResource(applet_resource, &shared_mutex);
182 sleep_button->SetAppletResource(applet_resource, &shared_mutex);
183 capture_button->SetAppletResource(applet_resource, &shared_mutex);
184}
185
186void ResourceManager::InitializeTouchScreenSampler() {
187 gesture = std::make_shared<Gesture>(system.HIDCore());
188 touch_screen = std::make_shared<TouchScreen>(system.HIDCore());
189
190 touch_screen->SetAppletResource(applet_resource, &shared_mutex);
191 gesture->SetAppletResource(applet_resource, &shared_mutex);
192}
193
194void ResourceManager::InitializeConsoleSixAxisSampler() {
195 console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore());
196 seven_six_axis = std::make_shared<SevenSixAxis>(system);
197
198 console_six_axis->SetAppletResource(applet_resource, &shared_mutex);
199}
200
201void ResourceManager::InitializeAHidSampler() {
202 // TODO
203}
204
205Result ResourceManager::RegisterCoreAppletResource() {
206 std::scoped_lock lock{shared_mutex};
207 return applet_resource->RegisterCoreAppletResource();
208}
209
210Result ResourceManager::UnregisterCoreAppletResource() {
211 std::scoped_lock lock{shared_mutex};
212 return applet_resource->UnregisterCoreAppletResource();
213}
214
215Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) {
216 std::scoped_lock lock{shared_mutex};
217 auto result = applet_resource->RegisterAppletResourceUserId(aruid, bool_value);
218 if (result.IsSuccess()) {
219 result = npad->RegisterAppletResourceUserId(aruid);
220 }
221 return result;
222}
223
224void ResourceManager::UnregisterAppletResourceUserId(u64 aruid) {
225 std::scoped_lock lock{shared_mutex};
226 applet_resource->UnregisterAppletResourceUserId(aruid);
227}
228
229Result ResourceManager::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) {
230 std::scoped_lock lock{shared_mutex};
231 return applet_resource->GetSharedMemoryHandle(out_handle, aruid);
232}
233
234void ResourceManager::FreeAppletResourceId(u64 aruid) {
235 std::scoped_lock lock{shared_mutex};
236 applet_resource->FreeAppletResourceId(aruid);
237}
238
239void ResourceManager::EnableInput(u64 aruid, bool is_enabled) {
240 std::scoped_lock lock{shared_mutex};
241 applet_resource->EnableInput(aruid, is_enabled);
242}
243
244void ResourceManager::EnableSixAxisSensor(u64 aruid, bool is_enabled) {
245 std::scoped_lock lock{shared_mutex};
246 applet_resource->EnableSixAxisSensor(aruid, is_enabled);
247}
248
249void ResourceManager::EnablePadInput(u64 aruid, bool is_enabled) {
250 std::scoped_lock lock{shared_mutex};
251 applet_resource->EnablePadInput(aruid, is_enabled);
252}
253
254void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) {
255 std::scoped_lock lock{shared_mutex};
256 applet_resource->EnableTouchScreen(aruid, is_enabled);
257}
258
259void ResourceManager::UpdateControllers(std::chrono::nanoseconds ns_late) {
260 auto& core_timing = system.CoreTiming();
261 debug_pad->OnUpdate(core_timing);
262 digitizer->OnUpdate(core_timing);
263 unique_pad->OnUpdate(core_timing);
264 gesture->OnUpdate(core_timing);
265 touch_screen->OnUpdate(core_timing);
266 palma->OnUpdate(core_timing);
267 home_button->OnUpdate(core_timing);
268 sleep_button->OnUpdate(core_timing);
269 capture_button->OnUpdate(core_timing);
270}
271
272void ResourceManager::UpdateNpad(std::chrono::nanoseconds ns_late) {
273 auto& core_timing = system.CoreTiming();
274 npad->OnUpdate(core_timing);
275}
276
277void ResourceManager::UpdateMouseKeyboard(std::chrono::nanoseconds ns_late) {
278 auto& core_timing = system.CoreTiming();
279 mouse->OnUpdate(core_timing);
280 debug_mouse->OnUpdate(core_timing);
281 keyboard->OnUpdate(core_timing);
282}
283
284void ResourceManager::UpdateMotion(std::chrono::nanoseconds ns_late) {
285 auto& core_timing = system.CoreTiming();
286 six_axis->OnUpdate(core_timing);
287 seven_six_axis->OnUpdate(core_timing);
288 console_six_axis->OnUpdate(core_timing);
289}
290
291IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource,
292 u64 applet_resource_user_id)
293 : ServiceFramework{system_, "IAppletResource"}, aruid{applet_resource_user_id},
294 resource_manager{resource} {
295 static const FunctionInfo functions[] = {
296 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
297 };
298 RegisterHandlers(functions);
299
300 // Register update callbacks
301 npad_update_event = Core::Timing::CreateEvent(
302 "HID::UpdatePadCallback",
303 [this, resource](
304 s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
305 const auto guard = LockService();
306 resource->UpdateNpad(ns_late);
307 return std::nullopt;
308 });
309 default_update_event = Core::Timing::CreateEvent(
310 "HID::UpdateDefaultCallback",
311 [this, resource](
312 s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
313 const auto guard = LockService();
314 resource->UpdateControllers(ns_late);
315 return std::nullopt;
316 });
317 mouse_keyboard_update_event = Core::Timing::CreateEvent(
318 "HID::UpdateMouseKeyboardCallback",
319 [this, resource](
320 s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
321 const auto guard = LockService();
322 resource->UpdateMouseKeyboard(ns_late);
323 return std::nullopt;
324 });
325 motion_update_event = Core::Timing::CreateEvent(
326 "HID::UpdateMotionCallback",
327 [this, resource](
328 s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
329 const auto guard = LockService();
330 resource->UpdateMotion(ns_late);
331 return std::nullopt;
332 });
333
334 system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
335 system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
336 default_update_event);
337 system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
338 mouse_keyboard_update_event);
339 system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
340 motion_update_event);
341}
342
343IAppletResource::~IAppletResource() {
344 system.CoreTiming().UnscheduleEvent(npad_update_event);
345 system.CoreTiming().UnscheduleEvent(default_update_event);
346 system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event);
347 system.CoreTiming().UnscheduleEvent(motion_update_event);
348 resource_manager->FreeAppletResourceId(aruid);
349}
350
351void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) {
352 Kernel::KSharedMemory* handle;
353 const auto result = resource_manager->GetSharedMemoryHandle(&handle, aruid);
354
355 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}", aruid, result.raw);
356
357 IPC::ResponseBuilder rb{ctx, 2, 1};
358 rb.Push(result);
359 rb.PushCopyObjects(handle);
360}
361
362} // namespace Service::HID
diff --git a/src/core/hle/service/hid/resource_manager.h b/src/core/hle/service/hid/resource_manager.h
deleted file mode 100644
index 7a21d8eb8..000000000
--- a/src/core/hle/service/hid/resource_manager.h
+++ /dev/null
@@ -1,149 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Core::Timing {
14struct EventType;
15}
16
17namespace Kernel {
18class KSharedMemory;
19}
20
21namespace Service::HID {
22class AppletResource;
23class CaptureButton;
24class Controller_Stubbed;
25class ConsoleSixAxis;
26class DebugMouse;
27class DebugPad;
28class Digitizer;
29class Gesture;
30class HomeButton;
31class Keyboard;
32class Mouse;
33class NPad;
34class Palma;
35class SevenSixAxis;
36class SixAxis;
37class SleepButton;
38class TouchScreen;
39class UniquePad;
40
41class ResourceManager {
42
43public:
44 explicit ResourceManager(Core::System& system_);
45 ~ResourceManager();
46
47 void Initialize();
48
49 std::shared_ptr<AppletResource> GetAppletResource() const;
50 std::shared_ptr<CaptureButton> GetCaptureButton() const;
51 std::shared_ptr<ConsoleSixAxis> GetConsoleSixAxis() const;
52 std::shared_ptr<DebugMouse> GetDebugMouse() const;
53 std::shared_ptr<DebugPad> GetDebugPad() const;
54 std::shared_ptr<Digitizer> GetDigitizer() const;
55 std::shared_ptr<Gesture> GetGesture() const;
56 std::shared_ptr<HomeButton> GetHomeButton() const;
57 std::shared_ptr<Keyboard> GetKeyboard() const;
58 std::shared_ptr<Mouse> GetMouse() const;
59 std::shared_ptr<NPad> GetNpad() const;
60 std::shared_ptr<Palma> GetPalma() const;
61 std::shared_ptr<SevenSixAxis> GetSevenSixAxis() const;
62 std::shared_ptr<SixAxis> GetSixAxis() const;
63 std::shared_ptr<SleepButton> GetSleepButton() const;
64 std::shared_ptr<TouchScreen> GetTouchScreen() const;
65 std::shared_ptr<UniquePad> GetUniquePad() const;
66
67 Result CreateAppletResource(u64 aruid);
68
69 Result RegisterCoreAppletResource();
70 Result UnregisterCoreAppletResource();
71 Result RegisterAppletResourceUserId(u64 aruid, bool bool_value);
72 void UnregisterAppletResourceUserId(u64 aruid);
73
74 Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid);
75 void FreeAppletResourceId(u64 aruid);
76
77 void EnableInput(u64 aruid, bool is_enabled);
78 void EnableSixAxisSensor(u64 aruid, bool is_enabled);
79 void EnablePadInput(u64 aruid, bool is_enabled);
80 void EnableTouchScreen(u64 aruid, bool is_enabled);
81
82 void UpdateControllers(std::chrono::nanoseconds ns_late);
83 void UpdateNpad(std::chrono::nanoseconds ns_late);
84 void UpdateMouseKeyboard(std::chrono::nanoseconds ns_late);
85 void UpdateMotion(std::chrono::nanoseconds ns_late);
86
87private:
88 Result CreateAppletResourceImpl(u64 aruid);
89 void InitializeHidCommonSampler();
90 void InitializeTouchScreenSampler();
91 void InitializeConsoleSixAxisSampler();
92 void InitializeAHidSampler();
93
94 bool is_initialized{false};
95
96 mutable std::recursive_mutex shared_mutex;
97 std::shared_ptr<AppletResource> applet_resource = nullptr;
98
99 std::shared_ptr<CaptureButton> capture_button = nullptr;
100 std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr;
101 std::shared_ptr<DebugMouse> debug_mouse = nullptr;
102 std::shared_ptr<DebugPad> debug_pad = nullptr;
103 std::shared_ptr<Digitizer> digitizer = nullptr;
104 std::shared_ptr<Gesture> gesture = nullptr;
105 std::shared_ptr<HomeButton> home_button = nullptr;
106 std::shared_ptr<Keyboard> keyboard = nullptr;
107 std::shared_ptr<Mouse> mouse = nullptr;
108 std::shared_ptr<NPad> npad = nullptr;
109 std::shared_ptr<Palma> palma = nullptr;
110 std::shared_ptr<SevenSixAxis> seven_six_axis = nullptr;
111 std::shared_ptr<SixAxis> six_axis = nullptr;
112 std::shared_ptr<SleepButton> sleep_button = nullptr;
113 std::shared_ptr<TouchScreen> touch_screen = nullptr;
114 std::shared_ptr<UniquePad> unique_pad = nullptr;
115
116 // TODO: Create these resources
117 // std::shared_ptr<AudioControl> audio_control = nullptr;
118 // std::shared_ptr<ButtonConfig> button_config = nullptr;
119 // std::shared_ptr<Config> config = nullptr;
120 // std::shared_ptr<Connection> connection = nullptr;
121 // std::shared_ptr<CustomConfig> custom_config = nullptr;
122 // std::shared_ptr<Digitizer> digitizer = nullptr;
123 // std::shared_ptr<Hdls> hdls = nullptr;
124 // std::shared_ptr<PlayReport> play_report = nullptr;
125 // std::shared_ptr<Rail> rail = nullptr;
126
127 Core::System& system;
128 KernelHelpers::ServiceContext service_context;
129};
130
131class IAppletResource final : public ServiceFramework<IAppletResource> {
132public:
133 explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource,
134 u64 applet_resource_user_id);
135 ~IAppletResource() override;
136
137private:
138 void GetSharedMemoryHandle(HLERequestContext& ctx);
139
140 std::shared_ptr<Core::Timing::EventType> npad_update_event;
141 std::shared_ptr<Core::Timing::EventType> default_update_event;
142 std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
143 std::shared_ptr<Core::Timing::EventType> motion_update_event;
144
145 u64 aruid;
146 std::shared_ptr<ResourceManager> resource_manager;
147};
148
149} // namespace Service::HID
diff --git a/src/core/hle/service/hid/ring_lifo.h b/src/core/hle/service/hid/ring_lifo.h
deleted file mode 100644
index 0816784e0..000000000
--- a/src/core/hle/service/hid/ring_lifo.h
+++ /dev/null
@@ -1,53 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "common/common_types.h"
9
10namespace Service::HID {
11
12template <typename State>
13struct AtomicStorage {
14 s64 sampling_number;
15 State state;
16};
17
18template <typename State, std::size_t max_buffer_size>
19struct Lifo {
20 s64 timestamp{};
21 s64 total_buffer_count = static_cast<s64>(max_buffer_size);
22 s64 buffer_tail{};
23 s64 buffer_count{};
24 std::array<AtomicStorage<State>, max_buffer_size> entries{};
25
26 const AtomicStorage<State>& ReadCurrentEntry() const {
27 return entries[buffer_tail];
28 }
29
30 const AtomicStorage<State>& ReadPreviousEntry() const {
31 return entries[GetPreviousEntryIndex()];
32 }
33
34 std::size_t GetPreviousEntryIndex() const {
35 return static_cast<size_t>((buffer_tail + max_buffer_size - 1) % max_buffer_size);
36 }
37
38 std::size_t GetNextEntryIndex() const {
39 return static_cast<size_t>((buffer_tail + 1) % max_buffer_size);
40 }
41
42 void WriteNextEntry(const State& new_state) {
43 if (buffer_count < static_cast<s64>(max_buffer_size) - 1) {
44 buffer_count++;
45 }
46 buffer_tail = GetNextEntryIndex();
47 const auto& previous_entry = ReadPreviousEntry();
48 entries[buffer_tail].sampling_number = previous_entry.sampling_number + 1;
49 entries[buffer_tail].state = new_state;
50 }
51};
52
53} // namespace Service::HID
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index f97e5b44c..b37fb6da3 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -22,9 +22,6 @@
22#include "common/string_util.h" 22#include "common/string_util.h"
23#include "common/tiny_mt.h" 23#include "common/tiny_mt.h"
24#include "core/core.h" 24#include "core/core.h"
25#include "core/hid/emulated_controller.h"
26#include "core/hid/hid_core.h"
27#include "core/hid/hid_types.h"
28#include "core/hle/kernel/k_event.h" 25#include "core/hle/kernel/k_event.h"
29#include "core/hle/service/ipc_helpers.h" 26#include "core/hle/service/ipc_helpers.h"
30#include "core/hle/service/mii/mii_manager.h" 27#include "core/hle/service/mii/mii_manager.h"
@@ -33,6 +30,9 @@
33#include "core/hle/service/nfc/mifare_result.h" 30#include "core/hle/service/nfc/mifare_result.h"
34#include "core/hle/service/nfc/nfc_result.h" 31#include "core/hle/service/nfc/nfc_result.h"
35#include "core/hle/service/time/time_manager.h" 32#include "core/hle/service/time/time_manager.h"
33#include "hid_core/frontend/emulated_controller.h"
34#include "hid_core/hid_core.h"
35#include "hid_core/hid_types.h"
36 36
37namespace Service::NFC { 37namespace Service::NFC {
38NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, 38NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
index ad534177d..44f651b87 100644
--- a/src/core/hle/service/nfc/common/device_manager.cpp
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -5,15 +5,15 @@
5 5
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hid/hid_types.h"
9#include "core/hle/kernel/k_event.h" 8#include "core/hle/kernel/k_event.h"
10#include "core/hle/service/hid/hid_util.h"
11#include "core/hle/service/ipc_helpers.h" 9#include "core/hle/service/ipc_helpers.h"
12#include "core/hle/service/nfc/common/device.h" 10#include "core/hle/service/nfc/common/device.h"
13#include "core/hle/service/nfc/common/device_manager.h" 11#include "core/hle/service/nfc/common/device_manager.h"
14#include "core/hle/service/nfc/nfc_result.h" 12#include "core/hle/service/nfc/nfc_result.h"
15#include "core/hle/service/time/clock_types.h" 13#include "core/hle/service/time/clock_types.h"
16#include "core/hle/service/time/time_manager.h" 14#include "core/hle/service/time/time_manager.h"
15#include "hid_core/hid_types.h"
16#include "hid_core/hid_util.h"
17 17
18namespace Service::NFC { 18namespace Service::NFC {
19 19
diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h
index c9f038e32..f02bdccf5 100644
--- a/src/core/hle/service/nfc/common/device_manager.h
+++ b/src/core/hle/service/nfc/common/device_manager.h
@@ -8,13 +8,13 @@
8#include <optional> 8#include <optional>
9#include <span> 9#include <span>
10 10
11#include "core/hid/hid_types.h"
12#include "core/hle/service/kernel_helpers.h" 11#include "core/hle/service/kernel_helpers.h"
13#include "core/hle/service/nfc/mifare_types.h" 12#include "core/hle/service/nfc/mifare_types.h"
14#include "core/hle/service/nfc/nfc_types.h" 13#include "core/hle/service/nfc/nfc_types.h"
15#include "core/hle/service/nfp/nfp_types.h" 14#include "core/hle/service/nfp/nfp_types.h"
16#include "core/hle/service/service.h" 15#include "core/hle/service/service.h"
17#include "core/hle/service/time/clock_types.h" 16#include "core/hle/service/time/clock_types.h"
17#include "hid_core/hid_types.h"
18 18
19namespace Service::NFC { 19namespace Service::NFC {
20class NfcDevice; 20class NfcDevice;
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
index 179c7ba2c..a71cf74b8 100644
--- a/src/core/hle/service/nfc/nfc_interface.cpp
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -3,7 +3,6 @@
3 3
4#include "common/logging/log.h" 4#include "common/logging/log.h"
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hid/hid_types.h"
7#include "core/hle/kernel/k_event.h" 6#include "core/hle/kernel/k_event.h"
8#include "core/hle/service/ipc_helpers.h" 7#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/nfc/common/device.h" 8#include "core/hle/service/nfc/common/device.h"
@@ -15,6 +14,7 @@
15#include "core/hle/service/nfc/nfc_types.h" 14#include "core/hle/service/nfc/nfc_types.h"
16#include "core/hle/service/nfp/nfp_result.h" 15#include "core/hle/service/nfp/nfp_result.h"
17#include "core/hle/service/time/clock_types.h" 16#include "core/hle/service/time/clock_types.h"
17#include "hid_core/hid_types.h"
18 18
19namespace Service::NFC { 19namespace Service::NFC {
20 20
diff --git a/src/core/hle/service/nfp/nfp_interface.cpp b/src/core/hle/service/nfp/nfp_interface.cpp
index 34ef9d82d..5ba6d1742 100644
--- a/src/core/hle/service/nfp/nfp_interface.cpp
+++ b/src/core/hle/service/nfp/nfp_interface.cpp
@@ -3,7 +3,6 @@
3 3
4#include "common/logging/log.h" 4#include "common/logging/log.h"
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hid/hid_types.h"
7#include "core/hle/kernel/k_event.h" 6#include "core/hle/kernel/k_event.h"
8#include "core/hle/service/ipc_helpers.h" 7#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/nfc/common/device.h" 8#include "core/hle/service/nfc/common/device.h"
@@ -12,6 +11,7 @@
12#include "core/hle/service/nfp/nfp_interface.h" 11#include "core/hle/service/nfp/nfp_interface.h"
13#include "core/hle/service/nfp/nfp_result.h" 12#include "core/hle/service/nfp/nfp_result.h"
14#include "core/hle/service/nfp/nfp_types.h" 13#include "core/hle/service/nfp/nfp_types.h"
14#include "hid_core/hid_types.h"
15 15
16namespace Service::NFP { 16namespace Service::NFP {
17 17
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index 7bc5b5ae5..96fa7fa3a 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -9,12 +9,12 @@
9#include "core/core_timing.h" 9#include "core/core_timing.h"
10#include "core/hle/kernel/k_page_table.h" 10#include "core/hle/kernel/k_page_table.h"
11#include "core/hle/kernel/k_process.h" 11#include "core/hle/kernel/k_process.h"
12#include "core/hle/service/hid/controllers/npad.h"
13#include "core/hle/service/hid/hid_server.h" 12#include "core/hle/service/hid/hid_server.h"
14#include "core/hle/service/hid/resource_manager.h"
15#include "core/hle/service/sm/sm.h" 13#include "core/hle/service/sm/sm.h"
16#include "core/memory.h" 14#include "core/memory.h"
17#include "core/memory/cheat_engine.h" 15#include "core/memory/cheat_engine.h"
16#include "hid_core/resource_manager.h"
17#include "hid_core/resources/npad/npad.h"
18 18
19namespace Core::Memory { 19namespace Core::Memory {
20namespace { 20namespace {