summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/service/hid/hid.cpp5
-rw-r--r--src/core/hle/service/hid/hid_debug_server.cpp196
-rw-r--r--src/core/hle/service/hid/hid_debug_server.h15
-rw-r--r--src/core/hle/service/hid/hid_server.cpp24
-rw-r--r--src/core/hle/service/hid/hid_system_server.cpp64
-rw-r--r--src/core/hle/service/hid/hid_system_server.h3
-rw-r--r--src/core/hle/service/set/setting_formats/system_settings.h4
-rw-r--r--src/core/hle/service/set/system_settings_server.cpp37
-rw-r--r--src/core/hle/service/set/system_settings_server.h4
-rw-r--r--src/frontend_common/config.cpp8
-rw-r--r--src/hid_core/CMakeLists.txt7
-rw-r--r--src/hid_core/hid_result.h8
-rw-r--r--src/hid_core/hid_types.h28
-rw-r--r--src/hid_core/resource_manager.cpp61
-rw-r--r--src/hid_core/resource_manager.h89
-rw-r--r--src/hid_core/resources/applet_resource.cpp6
-rw-r--r--src/hid_core/resources/applet_resource.h8
-rw-r--r--src/hid_core/resources/npad/npad.cpp3
-rw-r--r--src/hid_core/resources/npad/npad.h4
-rw-r--r--src/hid_core/resources/npad/npad_resource.cpp6
-rw-r--r--src/hid_core/resources/touch_screen/gesture.cpp367
-rw-r--r--src/hid_core/resources/touch_screen/gesture.h87
-rw-r--r--src/hid_core/resources/touch_screen/gesture_handler.cpp260
-rw-r--r--src/hid_core/resources/touch_screen/gesture_handler.h55
-rw-r--r--src/hid_core/resources/touch_screen/gesture_types.h77
-rw-r--r--src/hid_core/resources/touch_screen/touch_screen.cpp209
-rw-r--r--src/hid_core/resources/touch_screen/touch_screen.h71
-rw-r--r--src/hid_core/resources/touch_screen/touch_screen_driver.cpp114
-rw-r--r--src/hid_core/resources/touch_screen/touch_screen_driver.h47
-rw-r--r--src/hid_core/resources/touch_screen/touch_screen_resource.cpp579
-rw-r--r--src/hid_core/resources/touch_screen/touch_screen_resource.h126
-rw-r--r--src/hid_core/resources/touch_screen/touch_types.h61
32 files changed, 1894 insertions, 739 deletions
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 5b28be577..b60fb9139 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -18,9 +18,10 @@ namespace Service::HID {
18 18
19void LoopProcess(Core::System& system) { 19void LoopProcess(Core::System& system) {
20 auto server_manager = std::make_unique<ServerManager>(system); 20 auto server_manager = std::make_unique<ServerManager>(system);
21 std::shared_ptr<ResourceManager> resource_manager = std::make_shared<ResourceManager>(system);
22 std::shared_ptr<HidFirmwareSettings> firmware_settings = 21 std::shared_ptr<HidFirmwareSettings> firmware_settings =
23 std::make_shared<HidFirmwareSettings>(system); 22 std::make_shared<HidFirmwareSettings>(system);
23 std::shared_ptr<ResourceManager> resource_manager =
24 std::make_shared<ResourceManager>(system, firmware_settings);
24 25
25 // TODO: Remove this hack when am is emulated properly. 26 // TODO: Remove this hack when am is emulated properly.
26 resource_manager->Initialize(); 27 resource_manager->Initialize();
@@ -31,7 +32,7 @@ void LoopProcess(Core::System& system) {
31 server_manager->RegisterNamedService( 32 server_manager->RegisterNamedService(
32 "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); 33 "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings));
33 server_manager->RegisterNamedService( 34 server_manager->RegisterNamedService(
34 "hid:dbg", std::make_shared<IHidDebugServer>(system, resource_manager)); 35 "hid:dbg", std::make_shared<IHidDebugServer>(system, resource_manager, firmware_settings));
35 server_manager->RegisterNamedService( 36 server_manager->RegisterNamedService(
36 "hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager, firmware_settings)); 37 "hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager, firmware_settings));
37 38
diff --git a/src/core/hle/service/hid/hid_debug_server.cpp b/src/core/hle/service/hid/hid_debug_server.cpp
index f2a767d37..610af34dd 100644
--- a/src/core/hle/service/hid/hid_debug_server.cpp
+++ b/src/core/hle/service/hid/hid_debug_server.cpp
@@ -1,27 +1,37 @@
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 <algorithm>
5
4#include "core/hle/service/hid/hid_debug_server.h" 6#include "core/hle/service/hid/hid_debug_server.h"
5#include "core/hle/service/ipc_helpers.h" 7#include "core/hle/service/ipc_helpers.h"
8#include "hid_core/hid_types.h"
6#include "hid_core/resource_manager.h" 9#include "hid_core/resource_manager.h"
10#include "hid_core/resources/hid_firmware_settings.h"
11
12#include "hid_core/resources/touch_screen/gesture.h"
13#include "hid_core/resources/touch_screen/touch_screen.h"
14#include "hid_core/resources/touch_screen/touch_types.h"
7 15
8namespace Service::HID { 16namespace Service::HID {
9 17
10IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource) 18IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
11 : ServiceFramework{system_, "hid:dbg"}, resource_manager{resource} { 19 std::shared_ptr<HidFirmwareSettings> settings)
20 : ServiceFramework{system_, "hid:dbg"}, resource_manager{resource}, firmware_settings{
21 settings} {
12 // clang-format off 22 // clang-format off
13 static const FunctionInfo functions[] = { 23 static const FunctionInfo functions[] = {
14 {0, nullptr, "DeactivateDebugPad"}, 24 {0, nullptr, "DeactivateDebugPad"},
15 {1, nullptr, "SetDebugPadAutoPilotState"}, 25 {1, nullptr, "SetDebugPadAutoPilotState"},
16 {2, nullptr, "UnsetDebugPadAutoPilotState"}, 26 {2, nullptr, "UnsetDebugPadAutoPilotState"},
17 {10, nullptr, "DeactivateTouchScreen"}, 27 {10, &IHidDebugServer::DeactivateTouchScreen, "DeactivateTouchScreen"},
18 {11, nullptr, "SetTouchScreenAutoPilotState"}, 28 {11, &IHidDebugServer::SetTouchScreenAutoPilotState, "SetTouchScreenAutoPilotState"},
19 {12, nullptr, "UnsetTouchScreenAutoPilotState"}, 29 {12, &IHidDebugServer::UnsetTouchScreenAutoPilotState, "UnsetTouchScreenAutoPilotState"},
20 {13, nullptr, "GetTouchScreenConfiguration"}, 30 {13, &IHidDebugServer::GetTouchScreenConfiguration, "GetTouchScreenConfiguration"},
21 {14, nullptr, "ProcessTouchScreenAutoTune"}, 31 {14, &IHidDebugServer::ProcessTouchScreenAutoTune, "ProcessTouchScreenAutoTune"},
22 {15, nullptr, "ForceStopTouchScreenManagement"}, 32 {15, &IHidDebugServer::ForceStopTouchScreenManagement, "ForceStopTouchScreenManagement"},
23 {16, nullptr, "ForceRestartTouchScreenManagement"}, 33 {16, &IHidDebugServer::ForceRestartTouchScreenManagement, "ForceRestartTouchScreenManagement"},
24 {17, nullptr, "IsTouchScreenManaged"}, 34 {17, &IHidDebugServer::IsTouchScreenManaged, "IsTouchScreenManaged"},
25 {20, nullptr, "DeactivateMouse"}, 35 {20, nullptr, "DeactivateMouse"},
26 {21, nullptr, "SetMouseAutoPilotState"}, 36 {21, nullptr, "SetMouseAutoPilotState"},
27 {22, nullptr, "UnsetMouseAutoPilotState"}, 37 {22, nullptr, "UnsetMouseAutoPilotState"},
@@ -37,7 +47,7 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
37 {60, nullptr, "ClearNpadSystemCommonPolicy"}, 47 {60, nullptr, "ClearNpadSystemCommonPolicy"},
38 {61, nullptr, "DeactivateNpad"}, 48 {61, nullptr, "DeactivateNpad"},
39 {62, nullptr, "ForceDisconnectNpad"}, 49 {62, nullptr, "ForceDisconnectNpad"},
40 {91, nullptr, "DeactivateGesture"}, 50 {91, &IHidDebugServer::DeactivateGesture, "DeactivateGesture"},
41 {110, nullptr, "DeactivateHomeButton"}, 51 {110, nullptr, "DeactivateHomeButton"},
42 {111, nullptr, "SetHomeButtonAutoPilotState"}, 52 {111, nullptr, "SetHomeButtonAutoPilotState"},
43 {112, nullptr, "UnsetHomeButtonAutoPilotState"}, 53 {112, nullptr, "UnsetHomeButtonAutoPilotState"},
@@ -150,6 +160,170 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
150} 160}
151 161
152IHidDebugServer::~IHidDebugServer() = default; 162IHidDebugServer::~IHidDebugServer() = default;
163void IHidDebugServer::DeactivateTouchScreen(HLERequestContext& ctx) {
164 LOG_INFO(Service_HID, "called");
165
166 Result result = ResultSuccess;
167
168 if (!firmware_settings->IsDeviceManaged()) {
169 result = GetResourceManager()->GetTouchScreen()->Deactivate();
170 }
171
172 IPC::ResponseBuilder rb{ctx, 2};
173 rb.Push(result);
174}
175
176void IHidDebugServer::SetTouchScreenAutoPilotState(HLERequestContext& ctx) {
177 AutoPilotState auto_pilot{};
178 auto_pilot.count = ctx.GetReadBufferNumElements<TouchState>();
179 const auto buffer = ctx.ReadBuffer();
180
181 auto_pilot.count = std::min(auto_pilot.count, static_cast<u64>(auto_pilot.state.size()));
182 memcpy(auto_pilot.state.data(), buffer.data(), auto_pilot.count * sizeof(TouchState));
183
184 LOG_INFO(Service_HID, "called, auto_pilot_count={}", auto_pilot.count);
185
186 const Result result =
187 GetResourceManager()->GetTouchScreen()->SetTouchScreenAutoPilotState(auto_pilot);
188
189 IPC::ResponseBuilder rb{ctx, 2};
190 rb.Push(result);
191}
192
193void IHidDebugServer::UnsetTouchScreenAutoPilotState(HLERequestContext& ctx) {
194 LOG_INFO(Service_HID, "called");
195
196 const Result result = GetResourceManager()->GetTouchScreen()->UnsetTouchScreenAutoPilotState();
197
198 IPC::ResponseBuilder rb{ctx, 2};
199 rb.Push(result);
200}
201
202void IHidDebugServer::GetTouchScreenConfiguration(HLERequestContext& ctx) {
203 IPC::RequestParser rp{ctx};
204 const auto applet_resource_user_id{rp.Pop<u64>()};
205
206 LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
207
208 Core::HID::TouchScreenConfigurationForNx touchscreen_config{};
209 const Result result = GetResourceManager()->GetTouchScreen()->GetTouchScreenConfiguration(
210 touchscreen_config, applet_resource_user_id);
211
212 if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
213 touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
214 touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
215 }
216
217 IPC::ResponseBuilder rb{ctx, 6};
218 rb.Push(result);
219 rb.PushRaw(touchscreen_config);
220}
221
222void IHidDebugServer::ProcessTouchScreenAutoTune(HLERequestContext& ctx) {
223 LOG_INFO(Service_HID, "called");
224
225 Result result = GetResourceManager()->GetTouchScreen()->ProcessTouchScreenAutoTune();
226
227 IPC::ResponseBuilder rb{ctx, 2};
228 rb.Push(result);
229}
230
231void IHidDebugServer::ForceStopTouchScreenManagement(HLERequestContext& ctx) {
232 LOG_INFO(Service_HID, "called");
233
234 if (!firmware_settings->IsDeviceManaged()) {
235 IPC::ResponseBuilder rb{ctx, 2};
236 rb.Push(ResultSuccess);
237 return;
238 }
239
240 Result result = ResultSuccess;
241 bool is_touch_active{};
242 bool is_gesture_active{};
243 auto touch_screen = GetResourceManager()->GetTouchScreen();
244 auto gesture = GetResourceManager()->GetGesture();
245
246 if (firmware_settings->IsTouchI2cManaged()) {
247 result = touch_screen->IsActive(is_touch_active);
248 if (result.IsSuccess()) {
249 result = gesture->IsActive(is_gesture_active);
250 }
251 if (result.IsSuccess() && is_touch_active) {
252 result = touch_screen->Deactivate();
253 }
254 if (result.IsSuccess() && is_gesture_active) {
255 result = gesture->Deactivate();
256 }
257 }
258
259 IPC::ResponseBuilder rb{ctx, 2};
260 rb.Push(result);
261}
262
263void IHidDebugServer::ForceRestartTouchScreenManagement(HLERequestContext& ctx) {
264 IPC::RequestParser rp{ctx};
265 struct Parameters {
266 u32 basic_gesture_id;
267 INSERT_PADDING_WORDS_NOINIT(1);
268 u64 applet_resource_user_id;
269 };
270 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
271
272 const auto parameters{rp.PopRaw<Parameters>()};
273
274 LOG_INFO(Service_HID, "called, basic_gesture_id={}, applet_resource_user_id={}",
275 parameters.basic_gesture_id, parameters.applet_resource_user_id);
276
277 Result result = ResultSuccess;
278 auto touch_screen = GetResourceManager()->GetTouchScreen();
279 auto gesture = GetResourceManager()->GetGesture();
280
281 if (firmware_settings->IsDeviceManaged() && firmware_settings->IsTouchI2cManaged()) {
282 result = gesture->Activate();
283 if (result.IsSuccess()) {
284 result =
285 gesture->Activate(parameters.applet_resource_user_id, parameters.basic_gesture_id);
286 }
287 if (result.IsSuccess()) {
288 result = touch_screen->Activate();
289 }
290 if (result.IsSuccess()) {
291 result = touch_screen->Activate(parameters.applet_resource_user_id);
292 }
293 }
294
295 IPC::ResponseBuilder rb{ctx, 2};
296 rb.Push(result);
297}
298
299void IHidDebugServer::IsTouchScreenManaged(HLERequestContext& ctx) {
300 LOG_INFO(Service_HID, "called");
301
302 bool is_touch_active{};
303 bool is_gesture_active{};
304
305 Result result = GetResourceManager()->GetTouchScreen()->IsActive(is_touch_active);
306 if (result.IsSuccess()) {
307 result = GetResourceManager()->GetGesture()->IsActive(is_gesture_active);
308 }
309
310 IPC::ResponseBuilder rb{ctx, 3};
311 rb.Push(result);
312 rb.Push(is_touch_active | is_gesture_active);
313}
314
315void IHidDebugServer::DeactivateGesture(HLERequestContext& ctx) {
316 LOG_INFO(Service_HID, "called");
317
318 Result result = ResultSuccess;
319
320 if (!firmware_settings->IsDeviceManaged()) {
321 result = GetResourceManager()->GetGesture()->Deactivate();
322 }
323
324 IPC::ResponseBuilder rb{ctx, 2};
325 rb.Push(result);
326}
153 327
154std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() { 328std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() {
155 resource_manager->Initialize(); 329 resource_manager->Initialize();
diff --git a/src/core/hle/service/hid/hid_debug_server.h b/src/core/hle/service/hid/hid_debug_server.h
index 406db2211..7d5b082b3 100644
--- a/src/core/hle/service/hid/hid_debug_server.h
+++ b/src/core/hle/service/hid/hid_debug_server.h
@@ -11,16 +11,29 @@ class System;
11 11
12namespace Service::HID { 12namespace Service::HID {
13class ResourceManager; 13class ResourceManager;
14class HidFirmwareSettings;
14 15
15class IHidDebugServer final : public ServiceFramework<IHidDebugServer> { 16class IHidDebugServer final : public ServiceFramework<IHidDebugServer> {
16public: 17public:
17 explicit IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource); 18 explicit IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
19 std::shared_ptr<HidFirmwareSettings> settings);
18 ~IHidDebugServer() override; 20 ~IHidDebugServer() override;
19 21
20private: 22private:
23 void DeactivateTouchScreen(HLERequestContext& ctx);
24 void SetTouchScreenAutoPilotState(HLERequestContext& ctx);
25 void UnsetTouchScreenAutoPilotState(HLERequestContext& ctx);
26 void GetTouchScreenConfiguration(HLERequestContext& ctx);
27 void ProcessTouchScreenAutoTune(HLERequestContext& ctx);
28 void ForceStopTouchScreenManagement(HLERequestContext& ctx);
29 void ForceRestartTouchScreenManagement(HLERequestContext& ctx);
30 void IsTouchScreenManaged(HLERequestContext& ctx);
31 void DeactivateGesture(HLERequestContext& ctx);
32
21 std::shared_ptr<ResourceManager> GetResourceManager(); 33 std::shared_ptr<ResourceManager> GetResourceManager();
22 34
23 std::shared_ptr<ResourceManager> resource_manager; 35 std::shared_ptr<ResourceManager> resource_manager;
36 std::shared_ptr<HidFirmwareSettings> firmware_settings;
24}; 37};
25 38
26} // namespace Service::HID 39} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp
index 938b93451..3603d8ccf 100644
--- a/src/core/hle/service/hid/hid_server.cpp
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -990,8 +990,7 @@ void IHidServer::ActivateGesture(HLERequestContext& ctx) {
990 } 990 }
991 991
992 if (result.IsSuccess()) { 992 if (result.IsSuccess()) {
993 // TODO: Use gesture id here 993 result = gesture->Activate(parameters.applet_resource_user_id, parameters.basic_gesture_id);
994 result = gesture->Activate(parameters.applet_resource_user_id);
995 } 994 }
996 995
997 IPC::ResponseBuilder rb{ctx, 2}; 996 IPC::ResponseBuilder rb{ctx, 2};
@@ -2470,14 +2469,22 @@ void IHidServer::GetNpadCommunicationMode(HLERequestContext& ctx) {
2470 2469
2471void IHidServer::SetTouchScreenConfiguration(HLERequestContext& ctx) { 2470void IHidServer::SetTouchScreenConfiguration(HLERequestContext& ctx) {
2472 IPC::RequestParser rp{ctx}; 2471 IPC::RequestParser rp{ctx};
2473 const auto touchscreen_mode{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()}; 2472 auto touchscreen_config{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()};
2474 const auto applet_resource_user_id{rp.Pop<u64>()}; 2473 const auto applet_resource_user_id{rp.Pop<u64>()};
2475 2474
2476 LOG_WARNING(Service_HID, "(STUBBED) called, touchscreen_mode={}, applet_resource_user_id={}", 2475 LOG_INFO(Service_HID, "called, touchscreen_config={}, applet_resource_user_id={}",
2477 touchscreen_mode.mode, applet_resource_user_id); 2476 touchscreen_config.mode, applet_resource_user_id);
2477
2478 if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
2479 touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
2480 touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
2481 }
2482
2483 const Result result = GetResourceManager()->GetTouchScreen()->SetTouchScreenConfiguration(
2484 touchscreen_config, applet_resource_user_id);
2478 2485
2479 IPC::ResponseBuilder rb{ctx, 2}; 2486 IPC::ResponseBuilder rb{ctx, 2};
2480 rb.Push(ResultSuccess); 2487 rb.Push(result);
2481} 2488}
2482 2489
2483void IHidServer::IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx) { 2490void IHidServer::IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx) {
@@ -2505,11 +2512,12 @@ void IHidServer::SetTouchScreenResolution(HLERequestContext& ctx) {
2505 const auto height{rp.Pop<u32>()}; 2512 const auto height{rp.Pop<u32>()};
2506 const auto applet_resource_user_id{rp.Pop<u64>()}; 2513 const auto applet_resource_user_id{rp.Pop<u64>()};
2507 2514
2508 GetResourceManager()->GetTouchScreen()->SetTouchscreenDimensions(width, height);
2509
2510 LOG_INFO(Service_HID, "called, width={}, height={}, applet_resource_user_id={}", width, height, 2515 LOG_INFO(Service_HID, "called, width={}, height={}, applet_resource_user_id={}", width, height,
2511 applet_resource_user_id); 2516 applet_resource_user_id);
2512 2517
2518 GetResourceManager()->GetTouchScreen()->SetTouchScreenResolution(width, height,
2519 applet_resource_user_id);
2520
2513 IPC::ResponseBuilder rb{ctx, 2}; 2521 IPC::ResponseBuilder rb{ctx, 2};
2514 rb.Push(ResultSuccess); 2522 rb.Push(ResultSuccess);
2515} 2523}
diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp
index d1ec42edc..22471e9e2 100644
--- a/src/core/hle/service/hid/hid_system_server.cpp
+++ b/src/core/hle/service/hid/hid_system_server.cpp
@@ -155,9 +155,9 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
155 {1133, nullptr, "StartUsbFirmwareUpdate"}, 155 {1133, nullptr, "StartUsbFirmwareUpdate"},
156 {1134, nullptr, "GetUsbFirmwareUpdateState"}, 156 {1134, nullptr, "GetUsbFirmwareUpdateState"},
157 {1135, &IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory, "InitializeUsbFirmwareUpdateWithoutMemory"}, 157 {1135, &IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory, "InitializeUsbFirmwareUpdateWithoutMemory"},
158 {1150, nullptr, "SetTouchScreenMagnification"}, 158 {1150, &IHidSystemServer::SetTouchScreenMagnification, "SetTouchScreenMagnification"},
159 {1151, nullptr, "GetTouchScreenFirmwareVersion"}, 159 {1151, &IHidSystemServer::GetTouchScreenFirmwareVersion, "GetTouchScreenFirmwareVersion"},
160 {1152, nullptr, "SetTouchScreenDefaultConfiguration"}, 160 {1152, &IHidSystemServer::SetTouchScreenDefaultConfiguration, "SetTouchScreenDefaultConfiguration"},
161 {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"}, 161 {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},
162 {1154, nullptr, "IsFirmwareAvailableForNotification"}, 162 {1154, nullptr, "IsFirmwareAvailableForNotification"},
163 {1155, &IHidSystemServer::SetForceHandheldStyleVibration, "SetForceHandheldStyleVibration"}, 163 {1155, &IHidSystemServer::SetForceHandheldStyleVibration, "SetForceHandheldStyleVibration"},
@@ -845,12 +845,60 @@ void IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContex
845 rb.Push(ResultSuccess); 845 rb.Push(ResultSuccess);
846} 846}
847 847
848void IHidSystemServer::SetTouchScreenMagnification(HLERequestContext& ctx) {
849 IPC::RequestParser rp{ctx};
850 const auto point1x{rp.Pop<f32>()};
851 const auto point1y{rp.Pop<f32>()};
852 const auto point2x{rp.Pop<f32>()};
853 const auto point2y{rp.Pop<f32>()};
854
855 LOG_INFO(Service_HID, "called, point1=-({},{}), point2=({},{})", point1x, point1y, point2x,
856 point2y);
857
858 const Result result = GetResourceManager()->GetTouchScreen()->SetTouchScreenMagnification(
859 point1x, point1y, point2x, point2y);
860
861 IPC::ResponseBuilder rb{ctx, 2};
862 rb.Push(result);
863}
864
865void IHidSystemServer::GetTouchScreenFirmwareVersion(HLERequestContext& ctx) {
866 LOG_INFO(Service_HID, "called");
867
868 Core::HID::FirmwareVersion firmware{};
869 const auto result = GetResourceManager()->GetTouchScreenFirmwareVersion(firmware);
870
871 IPC::ResponseBuilder rb{ctx, 6};
872 rb.Push(result);
873 rb.PushRaw(firmware);
874}
875
876void IHidSystemServer::SetTouchScreenDefaultConfiguration(HLERequestContext& ctx) {
877 IPC::RequestParser rp{ctx};
878 auto touchscreen_config{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()};
879
880 LOG_INFO(Service_HID, "called, touchscreen_config={}", touchscreen_config.mode);
881
882 if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
883 touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
884 touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
885 }
886
887 const Result result =
888 GetResourceManager()->GetTouchScreen()->SetTouchScreenDefaultConfiguration(
889 touchscreen_config);
890
891 IPC::ResponseBuilder rb{ctx, 2};
892 rb.Push(result);
893}
894
848void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx) { 895void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx) {
849 LOG_WARNING(Service_HID, "(STUBBED) called"); 896 LOG_INFO(Service_HID, "called");
850 897
851 Core::HID::TouchScreenConfigurationForNx touchscreen_config{ 898 Core::HID::TouchScreenConfigurationForNx touchscreen_config{};
852 .mode = Core::HID::TouchScreenModeForNx::Finger, 899 const Result result =
853 }; 900 GetResourceManager()->GetTouchScreen()->GetTouchScreenDefaultConfiguration(
901 touchscreen_config);
854 902
855 if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 && 903 if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
856 touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) { 904 touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
@@ -858,7 +906,7 @@ void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx
858 } 906 }
859 907
860 IPC::ResponseBuilder rb{ctx, 6}; 908 IPC::ResponseBuilder rb{ctx, 6};
861 rb.Push(ResultSuccess); 909 rb.Push(result);
862 rb.PushRaw(touchscreen_config); 910 rb.PushRaw(touchscreen_config);
863} 911}
864 912
diff --git a/src/core/hle/service/hid/hid_system_server.h b/src/core/hle/service/hid/hid_system_server.h
index 4ab4d3931..738313e08 100644
--- a/src/core/hle/service/hid/hid_system_server.h
+++ b/src/core/hle/service/hid/hid_system_server.h
@@ -71,6 +71,9 @@ private:
71 void FinalizeUsbFirmwareUpdate(HLERequestContext& ctx); 71 void FinalizeUsbFirmwareUpdate(HLERequestContext& ctx);
72 void CheckUsbFirmwareUpdateRequired(HLERequestContext& ctx); 72 void CheckUsbFirmwareUpdateRequired(HLERequestContext& ctx);
73 void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx); 73 void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx);
74 void SetTouchScreenMagnification(HLERequestContext& ctx);
75 void GetTouchScreenFirmwareVersion(HLERequestContext& ctx);
76 void SetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
74 void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx); 77 void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
75 void SetForceHandheldStyleVibration(HLERequestContext& ctx); 78 void SetForceHandheldStyleVibration(HLERequestContext& ctx);
76 void IsUsingCustomButtonConfig(HLERequestContext& ctx); 79 void IsUsingCustomButtonConfig(HLERequestContext& ctx);
diff --git a/src/core/hle/service/set/setting_formats/system_settings.h b/src/core/hle/service/set/setting_formats/system_settings.h
index ebc373da5..40230182a 100644
--- a/src/core/hle/service/set/setting_formats/system_settings.h
+++ b/src/core/hle/service/set/setting_formats/system_settings.h
@@ -12,6 +12,7 @@
12#include "common/vector_math.h" 12#include "common/vector_math.h"
13#include "core/hle/service/set/setting_formats/private_settings.h" 13#include "core/hle/service/set/setting_formats/private_settings.h"
14#include "core/hle/service/set/settings_types.h" 14#include "core/hle/service/set/settings_types.h"
15#include "hid_core/resources/touch_screen/touch_types.h"
15 16
16namespace Service::Set { 17namespace Service::Set {
17 18
@@ -257,8 +258,7 @@ struct SystemSettings {
257 std::array<u8, 0x10> analog_stick_user_calibration_left; 258 std::array<u8, 0x10> analog_stick_user_calibration_left;
258 std::array<u8, 0x10> analog_stick_user_calibration_right; 259 std::array<u8, 0x10> analog_stick_user_calibration_right;
259 260
260 // nn::settings::system::TouchScreenMode 261 TouchScreenMode touch_screen_mode;
261 s32 touch_screen_mode;
262 INSERT_PADDING_BYTES(0x14); // Reserved 262 INSERT_PADDING_BYTES(0x14); // Reserved
263 263
264 TvSettings tv_settings; 264 TvSettings tv_settings;
diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp
index d3d0fb112..7ef4a0ded 100644
--- a/src/core/hle/service/set/system_settings_server.cpp
+++ b/src/core/hle/service/set/system_settings_server.cpp
@@ -275,8 +275,8 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
275 {184, nullptr, "SetPlatformRegion"}, 275 {184, nullptr, "SetPlatformRegion"},
276 {185, &ISystemSettingsServer::GetHomeMenuSchemeModel, "GetHomeMenuSchemeModel"}, 276 {185, &ISystemSettingsServer::GetHomeMenuSchemeModel, "GetHomeMenuSchemeModel"},
277 {186, nullptr, "GetMemoryUsageRateFlag"}, 277 {186, nullptr, "GetMemoryUsageRateFlag"},
278 {187, nullptr, "GetTouchScreenMode"}, 278 {187, &ISystemSettingsServer::GetTouchScreenMode, "GetTouchScreenMode"},
279 {188, nullptr, "SetTouchScreenMode"}, 279 {188, &ISystemSettingsServer::SetTouchScreenMode, "SetTouchScreenMode"},
280 {189, nullptr, "GetButtonConfigSettingsFull"}, 280 {189, nullptr, "GetButtonConfigSettingsFull"},
281 {190, nullptr, "SetButtonConfigSettingsFull"}, 281 {190, nullptr, "SetButtonConfigSettingsFull"},
282 {191, nullptr, "GetButtonConfigSettingsEmbedded"}, 282 {191, nullptr, "GetButtonConfigSettingsEmbedded"},
@@ -1395,6 +1395,28 @@ void ISystemSettingsServer::GetHomeMenuSchemeModel(HLERequestContext& ctx) {
1395 rb.Push(0); 1395 rb.Push(0);
1396} 1396}
1397 1397
1398void ISystemSettingsServer::GetTouchScreenMode(HLERequestContext& ctx) {
1399 TouchScreenMode touch_screen_mode{};
1400 auto res = GetTouchScreenMode(touch_screen_mode);
1401
1402 LOG_INFO(Service_SET, "called, touch_screen_mode={}", touch_screen_mode);
1403
1404 IPC::ResponseBuilder rb{ctx, 3};
1405 rb.Push(res);
1406 rb.PushEnum(touch_screen_mode);
1407}
1408
1409void ISystemSettingsServer::SetTouchScreenMode(HLERequestContext& ctx) {
1410 IPC::RequestParser rp{ctx};
1411 const auto touch_screen_mode = rp.PopEnum<TouchScreenMode>();
1412 auto res = SetTouchScreenMode(touch_screen_mode);
1413
1414 LOG_INFO(Service_SET, "called, touch_screen_mode={}", touch_screen_mode);
1415
1416 IPC::ResponseBuilder rb{ctx, 2};
1417 rb.Push(res);
1418}
1419
1398void ISystemSettingsServer::GetFieldTestingFlag(HLERequestContext& ctx) { 1420void ISystemSettingsServer::GetFieldTestingFlag(HLERequestContext& ctx) {
1399 LOG_INFO(Service_SET, "called, field_testing_flag={}", m_system_settings.field_testing_flag); 1421 LOG_INFO(Service_SET, "called, field_testing_flag={}", m_system_settings.field_testing_flag);
1400 1422
@@ -1670,4 +1692,15 @@ Result ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime(
1670 R_SUCCEED(); 1692 R_SUCCEED();
1671} 1693}
1672 1694
1695Result ISystemSettingsServer::GetTouchScreenMode(TouchScreenMode& touch_screen_mode) const {
1696 touch_screen_mode = m_system_settings.touch_screen_mode;
1697 R_SUCCEED();
1698}
1699
1700Result ISystemSettingsServer::SetTouchScreenMode(TouchScreenMode touch_screen_mode) {
1701 m_system_settings.touch_screen_mode = touch_screen_mode;
1702 SetSaveNeeded();
1703 R_SUCCEED();
1704}
1705
1673} // namespace Service::Set 1706} // namespace Service::Set
diff --git a/src/core/hle/service/set/system_settings_server.h b/src/core/hle/service/set/system_settings_server.h
index 1982b9723..9a3b36f0c 100644
--- a/src/core/hle/service/set/system_settings_server.h
+++ b/src/core/hle/service/set/system_settings_server.h
@@ -74,6 +74,8 @@ public:
74 Service::PSC::Time::SteadyClockTimePoint& out_time_point) const; 74 Service::PSC::Time::SteadyClockTimePoint& out_time_point) const;
75 Result SetUserSystemClockAutomaticCorrectionUpdatedTime( 75 Result SetUserSystemClockAutomaticCorrectionUpdatedTime(
76 const Service::PSC::Time::SteadyClockTimePoint& time_point); 76 const Service::PSC::Time::SteadyClockTimePoint& time_point);
77 Result GetTouchScreenMode(TouchScreenMode& touch_screen_mode) const;
78 Result SetTouchScreenMode(TouchScreenMode touch_screen_mode);
77 79
78private: 80private:
79 void SetLanguageCode(HLERequestContext& ctx); 81 void SetLanguageCode(HLERequestContext& ctx);
@@ -154,6 +156,8 @@ private:
154 void GetChineseTraditionalInputMethod(HLERequestContext& ctx); 156 void GetChineseTraditionalInputMethod(HLERequestContext& ctx);
155 void GetHomeMenuScheme(HLERequestContext& ctx); 157 void GetHomeMenuScheme(HLERequestContext& ctx);
156 void GetHomeMenuSchemeModel(HLERequestContext& ctx); 158 void GetHomeMenuSchemeModel(HLERequestContext& ctx);
159 void GetTouchScreenMode(HLERequestContext& ctx);
160 void SetTouchScreenMode(HLERequestContext& ctx);
157 void GetFieldTestingFlag(HLERequestContext& ctx); 161 void GetFieldTestingFlag(HLERequestContext& ctx);
158 void GetPanelCrcMode(HLERequestContext& ctx); 162 void GetPanelCrcMode(HLERequestContext& ctx);
159 void SetPanelCrcMode(HLERequestContext& ctx); 163 void SetPanelCrcMode(HLERequestContext& ctx);
diff --git a/src/frontend_common/config.cpp b/src/frontend_common/config.cpp
index 905f35118..d34624d28 100644
--- a/src/frontend_common/config.cpp
+++ b/src/frontend_common/config.cpp
@@ -190,9 +190,9 @@ void Config::ReadTouchscreenValues() {
190 Settings::values.touchscreen.rotation_angle = 190 Settings::values.touchscreen.rotation_angle =
191 static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_angle"), 0)); 191 static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_angle"), 0));
192 Settings::values.touchscreen.diameter_x = 192 Settings::values.touchscreen.diameter_x =
193 static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_x"), 15)); 193 static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_x"), 90));
194 Settings::values.touchscreen.diameter_y = 194 Settings::values.touchscreen.diameter_y =
195 static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_y"), 15)); 195 static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_y"), 90));
196} 196}
197 197
198void Config::ReadAudioValues() { 198void Config::ReadAudioValues() {
@@ -478,9 +478,9 @@ void Config::SaveTouchscreenValues() {
478 WriteIntegerSetting(std::string("touchscreen_angle"), touchscreen.rotation_angle, 478 WriteIntegerSetting(std::string("touchscreen_angle"), touchscreen.rotation_angle,
479 std::make_optional(static_cast<u32>(0))); 479 std::make_optional(static_cast<u32>(0)));
480 WriteIntegerSetting(std::string("touchscreen_diameter_x"), touchscreen.diameter_x, 480 WriteIntegerSetting(std::string("touchscreen_diameter_x"), touchscreen.diameter_x,
481 std::make_optional(static_cast<u32>(15))); 481 std::make_optional(static_cast<u32>(90)));
482 WriteIntegerSetting(std::string("touchscreen_diameter_y"), touchscreen.diameter_y, 482 WriteIntegerSetting(std::string("touchscreen_diameter_y"), touchscreen.diameter_y,
483 std::make_optional(static_cast<u32>(15))); 483 std::make_optional(static_cast<u32>(90)));
484} 484}
485 485
486void Config::SaveMotionTouchValues() { 486void Config::SaveMotionTouchValues() {
diff --git a/src/hid_core/CMakeLists.txt b/src/hid_core/CMakeLists.txt
index 64cd6e726..2699e1599 100644
--- a/src/hid_core/CMakeLists.txt
+++ b/src/hid_core/CMakeLists.txt
@@ -99,9 +99,14 @@ add_library(hid_core STATIC
99 resources/system_buttons/system_button_types.h 99 resources/system_buttons/system_button_types.h
100 resources/touch_screen/gesture.cpp 100 resources/touch_screen/gesture.cpp
101 resources/touch_screen/gesture.h 101 resources/touch_screen/gesture.h
102 resources/touch_screen/gesture_types.h 102 resources/touch_screen/gesture_handler.cpp
103 resources/touch_screen/gesture_handler.h
103 resources/touch_screen/touch_screen.cpp 104 resources/touch_screen/touch_screen.cpp
104 resources/touch_screen/touch_screen.h 105 resources/touch_screen/touch_screen.h
106 resources/touch_screen/touch_screen_driver.cpp
107 resources/touch_screen/touch_screen_driver.h
108 resources/touch_screen/touch_screen_resource.cpp
109 resources/touch_screen/touch_screen_resource.h
105 resources/touch_screen/touch_types.h 110 resources/touch_screen/touch_types.h
106 resources/unique_pad/unique_pad.cpp 111 resources/unique_pad/unique_pad.cpp
107 resources/unique_pad/unique_pad.h 112 resources/unique_pad/unique_pad.h
diff --git a/src/hid_core/hid_result.h b/src/hid_core/hid_result.h
index df9b28c9a..c8dd07bfe 100644
--- a/src/hid_core/hid_result.h
+++ b/src/hid_core/hid_result.h
@@ -8,6 +8,10 @@
8namespace Service::HID { 8namespace Service::HID {
9 9
10constexpr Result PalmaResultSuccess{ErrorModule::HID, 0}; 10constexpr Result PalmaResultSuccess{ErrorModule::HID, 0};
11
12constexpr Result ResultTouchNotInitialized{ErrorModule::HID, 41};
13constexpr Result ResultTouchOverflow{ErrorModule::HID, 42};
14
11constexpr Result NpadInvalidHandle{ErrorModule::HID, 100}; 15constexpr Result NpadInvalidHandle{ErrorModule::HID, 100};
12constexpr Result NpadDeviceIndexOutOfRange{ErrorModule::HID, 107}; 16constexpr Result NpadDeviceIndexOutOfRange{ErrorModule::HID, 107};
13 17
@@ -23,6 +27,10 @@ constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423};
23constexpr Result ResultNfcIsNotReady{ErrorModule::HID, 461}; 27constexpr Result ResultNfcIsNotReady{ErrorModule::HID, 461};
24constexpr Result ResultNfcXcdHandleIsNotInitialized{ErrorModule::HID, 464}; 28constexpr Result ResultNfcXcdHandleIsNotInitialized{ErrorModule::HID, 464};
25constexpr Result ResultIrSensorIsNotReady{ErrorModule::HID, 501}; 29constexpr Result ResultIrSensorIsNotReady{ErrorModule::HID, 501};
30
31constexpr Result ResultGestureOverflow{ErrorModule::HID, 522};
32constexpr Result ResultGestureNotInitialized{ErrorModule::HID, 523};
33
26constexpr Result ResultMcuIsNotReady{ErrorModule::HID, 541}; 34constexpr Result ResultMcuIsNotReady{ErrorModule::HID, 541};
27 35
28constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601}; 36constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601};
diff --git a/src/hid_core/hid_types.h b/src/hid_core/hid_types.h
index ffb5f1926..1b2fc6295 100644
--- a/src/hid_core/hid_types.h
+++ b/src/hid_core/hid_types.h
@@ -299,12 +299,6 @@ enum class GyroscopeZeroDriftMode : u32 {
299 Tight = 2, 299 Tight = 2,
300}; 300};
301 301
302// This is nn::settings::system::TouchScreenMode
303enum class TouchScreenMode : u32 {
304 Stylus = 0,
305 Standard = 1,
306};
307
308// This is nn::hid::TouchScreenModeForNx 302// This is nn::hid::TouchScreenModeForNx
309enum class TouchScreenModeForNx : u8 { 303enum class TouchScreenModeForNx : u8 {
310 UseSystemSetting, 304 UseSystemSetting,
@@ -354,18 +348,6 @@ struct TouchAttribute {
354}; 348};
355static_assert(sizeof(TouchAttribute) == 0x4, "TouchAttribute is an invalid size"); 349static_assert(sizeof(TouchAttribute) == 0x4, "TouchAttribute is an invalid size");
356 350
357// This is nn::hid::TouchState
358struct TouchState {
359 u64 delta_time{};
360 TouchAttribute attribute{};
361 u32 finger{};
362 Common::Point<u32> position{};
363 u32 diameter_x{};
364 u32 diameter_y{};
365 u32 rotation_angle{};
366};
367static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
368
369struct TouchFinger { 351struct TouchFinger {
370 u64 last_touch{}; 352 u64 last_touch{};
371 Common::Point<float> position{}; 353 Common::Point<float> position{};
@@ -756,4 +738,14 @@ struct UniquePadId {
756}; 738};
757static_assert(sizeof(UniquePadId) == 0x8, "UniquePadId is an invalid size"); 739static_assert(sizeof(UniquePadId) == 0x8, "UniquePadId is an invalid size");
758 740
741// This is nn::hid::system::FirmwareVersion
742struct FirmwareVersion {
743 u8 major;
744 u8 minor;
745 u8 micro;
746 u8 revision;
747 std::array<char, 0xc> device_identifier;
748};
749static_assert(sizeof(FirmwareVersion) == 0x10, "FirmwareVersion is an invalid size");
750
759} // namespace Core::HID 751} // namespace Core::HID
diff --git a/src/hid_core/resource_manager.cpp b/src/hid_core/resource_manager.cpp
index e78665d31..68ce2c7ae 100644
--- a/src/hid_core/resource_manager.cpp
+++ b/src/hid_core/resource_manager.cpp
@@ -15,6 +15,7 @@
15#include "hid_core/resources/applet_resource.h" 15#include "hid_core/resources/applet_resource.h"
16#include "hid_core/resources/debug_pad/debug_pad.h" 16#include "hid_core/resources/debug_pad/debug_pad.h"
17#include "hid_core/resources/digitizer/digitizer.h" 17#include "hid_core/resources/digitizer/digitizer.h"
18#include "hid_core/resources/hid_firmware_settings.h"
18#include "hid_core/resources/keyboard/keyboard.h" 19#include "hid_core/resources/keyboard/keyboard.h"
19#include "hid_core/resources/mouse/debug_mouse.h" 20#include "hid_core/resources/mouse/debug_mouse.h"
20#include "hid_core/resources/mouse/mouse.h" 21#include "hid_core/resources/mouse/mouse.h"
@@ -29,6 +30,8 @@
29#include "hid_core/resources/system_buttons/sleep_button.h" 30#include "hid_core/resources/system_buttons/sleep_button.h"
30#include "hid_core/resources/touch_screen/gesture.h" 31#include "hid_core/resources/touch_screen/gesture.h"
31#include "hid_core/resources/touch_screen/touch_screen.h" 32#include "hid_core/resources/touch_screen/touch_screen.h"
33#include "hid_core/resources/touch_screen/touch_screen_driver.h"
34#include "hid_core/resources/touch_screen/touch_screen_resource.h"
32#include "hid_core/resources/unique_pad/unique_pad.h" 35#include "hid_core/resources/unique_pad/unique_pad.h"
33#include "hid_core/resources/vibration/gc_vibration_device.h" 36#include "hid_core/resources/vibration/gc_vibration_device.h"
34#include "hid_core/resources/vibration/n64_vibration_device.h" 37#include "hid_core/resources/vibration/n64_vibration_device.h"
@@ -45,12 +48,16 @@ constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; //
45constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) 48constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
46constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) 49constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
47 50
48ResourceManager::ResourceManager(Core::System& system_) 51ResourceManager::ResourceManager(Core::System& system_,
49 : system{system_}, service_context{system_, "hid"} { 52 std::shared_ptr<HidFirmwareSettings> settings)
53 : firmware_settings{settings}, system{system_}, service_context{system_, "hid"} {
50 applet_resource = std::make_shared<AppletResource>(system); 54 applet_resource = std::make_shared<AppletResource>(system);
51} 55}
52 56
53ResourceManager::~ResourceManager() = default; 57ResourceManager::~ResourceManager() {
58 system.CoreTiming().UnscheduleEvent(touch_update_event);
59 input_event->Finalize();
60};
54 61
55void ResourceManager::Initialize() { 62void ResourceManager::Initialize() {
56 if (is_initialized) { 63 if (is_initialized) {
@@ -59,7 +66,9 @@ void ResourceManager::Initialize() {
59 66
60 system.HIDCore().ReloadInputDevices(); 67 system.HIDCore().ReloadInputDevices();
61 68
62 handheld_config = std::make_shared<HandheldConfig>(); 69 input_event = service_context.CreateEvent("ResourceManager:InputEvent");
70
71 InitializeHandheldConfig();
63 InitializeHidCommonSampler(); 72 InitializeHidCommonSampler();
64 InitializeTouchScreenSampler(); 73 InitializeTouchScreenSampler();
65 InitializeConsoleSixAxisSampler(); 74 InitializeConsoleSixAxisSampler();
@@ -154,6 +163,7 @@ Result ResourceManager::CreateAppletResource(u64 aruid) {
154 npad->Activate(); 163 npad->Activate();
155 six_axis->Activate(); 164 six_axis->Activate();
156 touch_screen->Activate(); 165 touch_screen->Activate();
166 gesture->Activate();
157 167
158 return GetNpad()->ActivateNpadResource(aruid); 168 return GetNpad()->ActivateNpadResource(aruid);
159} 169}
@@ -163,6 +173,17 @@ Result ResourceManager::CreateAppletResourceImpl(u64 aruid) {
163 return applet_resource->CreateAppletResource(aruid); 173 return applet_resource->CreateAppletResource(aruid);
164} 174}
165 175
176void ResourceManager::InitializeHandheldConfig() {
177 handheld_config = std::make_shared<HandheldConfig>();
178 handheld_config->is_handheld_hid_enabled = true;
179 handheld_config->is_joycon_rail_enabled = true;
180 handheld_config->is_force_handheld_style_vibration = false;
181 handheld_config->is_force_handheld = false;
182 if (firmware_settings->IsHandheldForced()) {
183 handheld_config->is_joycon_rail_enabled = false;
184 }
185}
186
166void ResourceManager::InitializeHidCommonSampler() { 187void ResourceManager::InitializeHidCommonSampler() {
167 debug_pad = std::make_shared<DebugPad>(system.HIDCore()); 188 debug_pad = std::make_shared<DebugPad>(system.HIDCore());
168 mouse = std::make_shared<Mouse>(system.HIDCore()); 189 mouse = std::make_shared<Mouse>(system.HIDCore());
@@ -170,7 +191,6 @@ void ResourceManager::InitializeHidCommonSampler() {
170 keyboard = std::make_shared<Keyboard>(system.HIDCore()); 191 keyboard = std::make_shared<Keyboard>(system.HIDCore());
171 unique_pad = std::make_shared<UniquePad>(system.HIDCore()); 192 unique_pad = std::make_shared<UniquePad>(system.HIDCore());
172 npad = std::make_shared<NPad>(system.HIDCore(), service_context); 193 npad = std::make_shared<NPad>(system.HIDCore(), service_context);
173 gesture = std::make_shared<Gesture>(system.HIDCore());
174 home_button = std::make_shared<HomeButton>(system.HIDCore()); 194 home_button = std::make_shared<HomeButton>(system.HIDCore());
175 sleep_button = std::make_shared<SleepButton>(system.HIDCore()); 195 sleep_button = std::make_shared<SleepButton>(system.HIDCore());
176 capture_button = std::make_shared<CaptureButton>(system.HIDCore()); 196 capture_button = std::make_shared<CaptureButton>(system.HIDCore());
@@ -185,7 +205,8 @@ void ResourceManager::InitializeHidCommonSampler() {
185 205
186 const auto settings = 206 const auto settings =
187 system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); 207 system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
188 npad->SetNpadExternals(applet_resource, &shared_mutex, handheld_config, settings); 208 npad->SetNpadExternals(applet_resource, &shared_mutex, handheld_config, input_event,
209 &input_mutex, settings);
189 210
190 six_axis->SetAppletResource(applet_resource, &shared_mutex); 211 six_axis->SetAppletResource(applet_resource, &shared_mutex);
191 mouse->SetAppletResource(applet_resource, &shared_mutex); 212 mouse->SetAppletResource(applet_resource, &shared_mutex);
@@ -196,11 +217,25 @@ void ResourceManager::InitializeHidCommonSampler() {
196} 217}
197 218
198void ResourceManager::InitializeTouchScreenSampler() { 219void ResourceManager::InitializeTouchScreenSampler() {
199 gesture = std::make_shared<Gesture>(system.HIDCore()); 220 // This is nn.hid.TouchScreenSampler
200 touch_screen = std::make_shared<TouchScreen>(system.HIDCore()); 221 touch_resource = std::make_shared<TouchResource>(system);
222 touch_driver = std::make_shared<TouchDriver>(system.HIDCore());
223 touch_screen = std::make_shared<TouchScreen>(touch_resource);
224 gesture = std::make_shared<Gesture>(touch_resource);
225
226 touch_update_event = Core::Timing::CreateEvent(
227 "HID::TouchUpdateCallback",
228 [this](s64 time,
229 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
230 touch_resource->OnTouchUpdate(time);
231 return std::nullopt;
232 });
201 233
202 touch_screen->SetAppletResource(applet_resource, &shared_mutex); 234 touch_resource->SetTouchDriver(touch_driver);
203 gesture->SetAppletResource(applet_resource, &shared_mutex); 235 touch_resource->SetAppletResource(applet_resource, &shared_mutex);
236 touch_resource->SetInputEvent(input_event, &input_mutex);
237 touch_resource->SetHandheldConfig(handheld_config);
238 touch_resource->SetTimerEvent(touch_update_event);
204} 239}
205 240
206void ResourceManager::InitializeConsoleSixAxisSampler() { 241void ResourceManager::InitializeConsoleSixAxisSampler() {
@@ -388,13 +423,15 @@ Result ResourceManager::SendVibrationValue(u64 aruid,
388 return result; 423 return result;
389} 424}
390 425
426Result ResourceManager::GetTouchScreenFirmwareVersion(Core::HID::FirmwareVersion& firmware) const {
427 return ResultSuccess;
428}
429
391void ResourceManager::UpdateControllers(std::chrono::nanoseconds ns_late) { 430void ResourceManager::UpdateControllers(std::chrono::nanoseconds ns_late) {
392 auto& core_timing = system.CoreTiming(); 431 auto& core_timing = system.CoreTiming();
393 debug_pad->OnUpdate(core_timing); 432 debug_pad->OnUpdate(core_timing);
394 digitizer->OnUpdate(core_timing); 433 digitizer->OnUpdate(core_timing);
395 unique_pad->OnUpdate(core_timing); 434 unique_pad->OnUpdate(core_timing);
396 gesture->OnUpdate(core_timing);
397 touch_screen->OnUpdate(core_timing);
398 palma->OnUpdate(core_timing); 435 palma->OnUpdate(core_timing);
399 home_button->OnUpdate(core_timing); 436 home_button->OnUpdate(core_timing);
400 sleep_button->OnUpdate(core_timing); 437 sleep_button->OnUpdate(core_timing);
diff --git a/src/hid_core/resource_manager.h b/src/hid_core/resource_manager.h
index 128e00125..0bfe09511 100644
--- a/src/hid_core/resource_manager.h
+++ b/src/hid_core/resource_manager.h
@@ -11,6 +11,7 @@ class System;
11} 11}
12 12
13namespace Core::HID { 13namespace Core::HID {
14struct FirmwareVersion;
14struct VibrationDeviceHandle; 15struct VibrationDeviceHandle;
15struct VibrationValue; 16struct VibrationValue;
16struct VibrationDeviceInfo; 17struct VibrationDeviceInfo;
@@ -21,8 +22,9 @@ struct EventType;
21} 22}
22 23
23namespace Kernel { 24namespace Kernel {
25class KEvent;
24class KSharedMemory; 26class KSharedMemory;
25} 27} // namespace Kernel
26 28
27namespace Service::HID { 29namespace Service::HID {
28class AppletResource; 30class AppletResource;
@@ -33,6 +35,7 @@ class DebugMouse;
33class DebugPad; 35class DebugPad;
34class Digitizer; 36class Digitizer;
35class Gesture; 37class Gesture;
38class HidFirmwareSettings;
36class HomeButton; 39class HomeButton;
37class Keyboard; 40class Keyboard;
38class Mouse; 41class Mouse;
@@ -42,6 +45,8 @@ class SevenSixAxis;
42class SixAxis; 45class SixAxis;
43class SleepButton; 46class SleepButton;
44class TouchScreen; 47class TouchScreen;
48class TouchDriver;
49class TouchResource;
45class UniquePad; 50class UniquePad;
46class NpadVibrationBase; 51class NpadVibrationBase;
47class NpadN64VibrationDevice; 52class NpadN64VibrationDevice;
@@ -52,7 +57,7 @@ struct HandheldConfig;
52class ResourceManager { 57class ResourceManager {
53 58
54public: 59public:
55 explicit ResourceManager(Core::System& system_); 60 explicit ResourceManager(Core::System& system_, std::shared_ptr<HidFirmwareSettings> settings);
56 ~ResourceManager(); 61 ~ResourceManager();
57 62
58 void Initialize(); 63 void Initialize();
@@ -102,6 +107,8 @@ public:
102 Result SendVibrationValue(u64 aruid, const Core::HID::VibrationDeviceHandle& handle, 107 Result SendVibrationValue(u64 aruid, const Core::HID::VibrationDeviceHandle& handle,
103 const Core::HID::VibrationValue& value); 108 const Core::HID::VibrationValue& value);
104 109
110 Result GetTouchScreenFirmwareVersion(Core::HID::FirmwareVersion& firmware) const;
111
105 void UpdateControllers(std::chrono::nanoseconds ns_late); 112 void UpdateControllers(std::chrono::nanoseconds ns_late);
106 void UpdateNpad(std::chrono::nanoseconds ns_late); 113 void UpdateNpad(std::chrono::nanoseconds ns_late);
107 void UpdateMouseKeyboard(std::chrono::nanoseconds ns_late); 114 void UpdateMouseKeyboard(std::chrono::nanoseconds ns_late);
@@ -109,6 +116,7 @@ public:
109 116
110private: 117private:
111 Result CreateAppletResourceImpl(u64 aruid); 118 Result CreateAppletResourceImpl(u64 aruid);
119 void InitializeHandheldConfig();
112 void InitializeHidCommonSampler(); 120 void InitializeHidCommonSampler();
113 void InitializeTouchScreenSampler(); 121 void InitializeTouchScreenSampler();
114 void InitializeConsoleSixAxisSampler(); 122 void InitializeConsoleSixAxisSampler();
@@ -117,37 +125,46 @@ private:
117 bool is_initialized{false}; 125 bool is_initialized{false};
118 126
119 mutable std::recursive_mutex shared_mutex; 127 mutable std::recursive_mutex shared_mutex;
120 std::shared_ptr<AppletResource> applet_resource = nullptr; 128 std::shared_ptr<AppletResource> applet_resource{nullptr};
121 129
122 std::shared_ptr<CaptureButton> capture_button = nullptr; 130 mutable std::mutex input_mutex;
123 std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr; 131 Kernel::KEvent* input_event{nullptr};
124 std::shared_ptr<DebugMouse> debug_mouse = nullptr; 132
125 std::shared_ptr<DebugPad> debug_pad = nullptr; 133 std::shared_ptr<HandheldConfig> handheld_config{nullptr};
126 std::shared_ptr<Digitizer> digitizer = nullptr; 134 std::shared_ptr<HidFirmwareSettings> firmware_settings{nullptr};
127 std::shared_ptr<Gesture> gesture = nullptr; 135
128 std::shared_ptr<HomeButton> home_button = nullptr; 136 std::shared_ptr<CaptureButton> capture_button{nullptr};
129 std::shared_ptr<Keyboard> keyboard = nullptr; 137 std::shared_ptr<ConsoleSixAxis> console_six_axis{nullptr};
130 std::shared_ptr<Mouse> mouse = nullptr; 138 std::shared_ptr<DebugMouse> debug_mouse{nullptr};
131 std::shared_ptr<NPad> npad = nullptr; 139 std::shared_ptr<DebugPad> debug_pad{nullptr};
132 std::shared_ptr<Palma> palma = nullptr; 140 std::shared_ptr<Digitizer> digitizer{nullptr};
133 std::shared_ptr<SevenSixAxis> seven_six_axis = nullptr; 141 std::shared_ptr<HomeButton> home_button{nullptr};
134 std::shared_ptr<SixAxis> six_axis = nullptr; 142 std::shared_ptr<Keyboard> keyboard{nullptr};
135 std::shared_ptr<SleepButton> sleep_button = nullptr; 143 std::shared_ptr<Mouse> mouse{nullptr};
136 std::shared_ptr<TouchScreen> touch_screen = nullptr; 144 std::shared_ptr<NPad> npad{nullptr};
137 std::shared_ptr<UniquePad> unique_pad = nullptr; 145 std::shared_ptr<Palma> palma{nullptr};
138 146 std::shared_ptr<SevenSixAxis> seven_six_axis{nullptr};
139 std::shared_ptr<HandheldConfig> handheld_config = nullptr; 147 std::shared_ptr<SixAxis> six_axis{nullptr};
148 std::shared_ptr<SleepButton> sleep_button{nullptr};
149 std::shared_ptr<UniquePad> unique_pad{nullptr};
140 150
141 // TODO: Create these resources 151 // TODO: Create these resources
142 // std::shared_ptr<AudioControl> audio_control = nullptr; 152 // std::shared_ptr<AudioControl> audio_control{nullptr};
143 // std::shared_ptr<ButtonConfig> button_config = nullptr; 153 // std::shared_ptr<ButtonConfig> button_config{nullptr};
144 // std::shared_ptr<Config> config = nullptr; 154 // std::shared_ptr<Config> config{nullptr};
145 // std::shared_ptr<Connection> connection = nullptr; 155 // std::shared_ptr<Connection> connection{nullptr};
146 // std::shared_ptr<CustomConfig> custom_config = nullptr; 156 // std::shared_ptr<CustomConfig> custom_config{nullptr};
147 // std::shared_ptr<Digitizer> digitizer = nullptr; 157 // std::shared_ptr<Digitizer> digitizer{nullptr};
148 // std::shared_ptr<Hdls> hdls = nullptr; 158 // std::shared_ptr<Hdls> hdls{nullptr};
149 // std::shared_ptr<PlayReport> play_report = nullptr; 159 // std::shared_ptr<PlayReport> play_report{nullptr};
150 // std::shared_ptr<Rail> rail = nullptr; 160 // std::shared_ptr<Rail> rail{nullptr};
161
162 // Touch Resources
163 std::shared_ptr<Gesture> gesture{nullptr};
164 std::shared_ptr<TouchScreen> touch_screen{nullptr};
165 std::shared_ptr<TouchResource> touch_resource{nullptr};
166 std::shared_ptr<TouchDriver> touch_driver{nullptr};
167 std::shared_ptr<Core::Timing::EventType> touch_update_event{nullptr};
151 168
152 Core::System& system; 169 Core::System& system;
153 KernelHelpers::ServiceContext service_context; 170 KernelHelpers::ServiceContext service_context;
@@ -162,12 +179,12 @@ public:
162private: 179private:
163 void GetSharedMemoryHandle(HLERequestContext& ctx); 180 void GetSharedMemoryHandle(HLERequestContext& ctx);
164 181
165 std::shared_ptr<Core::Timing::EventType> npad_update_event; 182 std::shared_ptr<Core::Timing::EventType> npad_update_event{nullptr};
166 std::shared_ptr<Core::Timing::EventType> default_update_event; 183 std::shared_ptr<Core::Timing::EventType> default_update_event{nullptr};
167 std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event; 184 std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event{nullptr};
168 std::shared_ptr<Core::Timing::EventType> motion_update_event; 185 std::shared_ptr<Core::Timing::EventType> motion_update_event{nullptr};
169 186
170 u64 aruid; 187 u64 aruid{};
171 std::shared_ptr<ResourceManager> resource_manager; 188 std::shared_ptr<ResourceManager> resource_manager;
172}; 189};
173 190
diff --git a/src/hid_core/resources/applet_resource.cpp b/src/hid_core/resources/applet_resource.cpp
index db4134037..243beb1c7 100644
--- a/src/hid_core/resources/applet_resource.cpp
+++ b/src/hid_core/resources/applet_resource.cpp
@@ -118,6 +118,12 @@ void AppletResource::UnregisterAppletResourceUserId(u64 aruid) {
118 data[index].aruid = 0; 118 data[index].aruid = 0;
119 119
120 registration_list.flag[index] = RegistrationStatus::PendingDelete; 120 registration_list.flag[index] = RegistrationStatus::PendingDelete;
121
122 for (std::size_t i = 0; i < AruidIndexMax; i++) {
123 if (registration_list.flag[i] == RegistrationStatus::Initialized) {
124 active_aruid = registration_list.aruid[i];
125 }
126 }
121} 127}
122 128
123void AppletResource::FreeAppletResourceId(u64 aruid) { 129void AppletResource::FreeAppletResourceId(u64 aruid) {
diff --git a/src/hid_core/resources/applet_resource.h b/src/hid_core/resources/applet_resource.h
index e9710d306..4a5416fb2 100644
--- a/src/hid_core/resources/applet_resource.h
+++ b/src/hid_core/resources/applet_resource.h
@@ -13,11 +13,12 @@
13 13
14namespace Core { 14namespace Core {
15class System; 15class System;
16} 16} // namespace Core
17 17
18namespace Kernel { 18namespace Kernel {
19class KEvent;
19class KSharedMemory; 20class KSharedMemory;
20} 21} // namespace Kernel
21 22
22namespace Service::HID { 23namespace Service::HID {
23struct SharedMemoryFormat; 24struct SharedMemoryFormat;
@@ -73,7 +74,8 @@ struct AppletResourceHolder {
73 std::recursive_mutex* shared_mutex{nullptr}; 74 std::recursive_mutex* shared_mutex{nullptr};
74 NPadResource* shared_npad_resource{nullptr}; 75 NPadResource* shared_npad_resource{nullptr};
75 std::shared_ptr<HandheldConfig> handheld_config{nullptr}; 76 std::shared_ptr<HandheldConfig> handheld_config{nullptr};
76 long* handle_1; 77 Kernel::KEvent* input_event{nullptr};
78 std::mutex* input_mutex{nullptr};
77}; 79};
78 80
79class AppletResource { 81class AppletResource {
diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp
index 2823be348..1a58eff4a 100644
--- a/src/hid_core/resources/npad/npad.cpp
+++ b/src/hid_core/resources/npad/npad.cpp
@@ -1070,11 +1070,14 @@ void NPad::UnregisterAppletResourceUserId(u64 aruid) {
1070void NPad::SetNpadExternals(std::shared_ptr<AppletResource> resource, 1070void NPad::SetNpadExternals(std::shared_ptr<AppletResource> resource,
1071 std::recursive_mutex* shared_mutex, 1071 std::recursive_mutex* shared_mutex,
1072 std::shared_ptr<HandheldConfig> handheld_config, 1072 std::shared_ptr<HandheldConfig> handheld_config,
1073 Kernel::KEvent* input_event, std::mutex* input_mutex,
1073 std::shared_ptr<Service::Set::ISystemSettingsServer> settings) { 1074 std::shared_ptr<Service::Set::ISystemSettingsServer> settings) {
1074 applet_resource_holder.applet_resource = resource; 1075 applet_resource_holder.applet_resource = resource;
1075 applet_resource_holder.shared_mutex = shared_mutex; 1076 applet_resource_holder.shared_mutex = shared_mutex;
1076 applet_resource_holder.shared_npad_resource = &npad_resource; 1077 applet_resource_holder.shared_npad_resource = &npad_resource;
1077 applet_resource_holder.handheld_config = handheld_config; 1078 applet_resource_holder.handheld_config = handheld_config;
1079 applet_resource_holder.input_event = input_event;
1080 applet_resource_holder.input_mutex = input_mutex;
1078 1081
1079 vibration_handler.SetSettingsService(settings); 1082 vibration_handler.SetSettingsService(settings);
1080 1083
diff --git a/src/hid_core/resources/npad/npad.h b/src/hid_core/resources/npad/npad.h
index 3b1a69e7f..4e26ed2e8 100644
--- a/src/hid_core/resources/npad/npad.h
+++ b/src/hid_core/resources/npad/npad.h
@@ -131,6 +131,7 @@ public:
131 void SetNpadExternals(std::shared_ptr<AppletResource> resource, 131 void SetNpadExternals(std::shared_ptr<AppletResource> resource,
132 std::recursive_mutex* shared_mutex, 132 std::recursive_mutex* shared_mutex,
133 std::shared_ptr<HandheldConfig> handheld_config, 133 std::shared_ptr<HandheldConfig> handheld_config,
134 Kernel::KEvent* input_event, std::mutex* input_mutex,
134 std::shared_ptr<Service::Set::ISystemSettingsServer> settings); 135 std::shared_ptr<Service::Set::ISystemSettingsServer> settings);
135 136
136 AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id); 137 AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);
@@ -204,9 +205,6 @@ private:
204 std::array<AbstractPad, MaxSupportedNpadIdTypes> abstracted_pads; 205 std::array<AbstractPad, MaxSupportedNpadIdTypes> abstracted_pads;
205 NpadVibration vibration_handler{}; 206 NpadVibration vibration_handler{};
206 207
207 Kernel::KEvent* input_event{nullptr};
208 std::mutex* input_mutex{nullptr};
209
210 std::atomic<u64> press_state{}; 208 std::atomic<u64> press_state{};
211 std::array<std::array<NpadControllerData, MaxSupportedNpadIdTypes>, AruidIndexMax> 209 std::array<std::array<NpadControllerData, MaxSupportedNpadIdTypes>, AruidIndexMax>
212 controller_data{}; 210 controller_data{};
diff --git a/src/hid_core/resources/npad/npad_resource.cpp b/src/hid_core/resources/npad/npad_resource.cpp
index ea9fc14ed..8dd86b58e 100644
--- a/src/hid_core/resources/npad/npad_resource.cpp
+++ b/src/hid_core/resources/npad/npad_resource.cpp
@@ -72,6 +72,12 @@ void NPadResource::UnregisterAppletResourceUserId(u64 aruid) {
72 state[aruid_index] = {}; 72 state[aruid_index] = {};
73 registration_list.flag[aruid_index] = RegistrationStatus::PendingDelete; 73 registration_list.flag[aruid_index] = RegistrationStatus::PendingDelete;
74 } 74 }
75
76 for (std::size_t i = 0; i < AruidIndexMax; i++) {
77 if (registration_list.flag[i] == RegistrationStatus::Initialized) {
78 active_data_aruid = registration_list.aruid[i];
79 }
80 }
75} 81}
76 82
77void NPadResource::DestroyStyleSetUpdateEvents(u64 aruid) { 83void NPadResource::DestroyStyleSetUpdateEvents(u64 aruid) {
diff --git a/src/hid_core/resources/touch_screen/gesture.cpp b/src/hid_core/resources/touch_screen/gesture.cpp
index 0ecc0941f..eaa0cc7d0 100644
--- a/src/hid_core/resources/touch_screen/gesture.cpp
+++ b/src/hid_core/resources/touch_screen/gesture.cpp
@@ -1,366 +1,53 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#include "common/math_util.h"
5#include "common/settings.h"
6#include "core/frontend/emu_window.h"
7#include "hid_core/frontend/emulated_console.h"
8#include "hid_core/hid_core.h"
9#include "hid_core/resources/applet_resource.h"
10#include "hid_core/resources/shared_memory_format.h"
11#include "hid_core/resources/touch_screen/gesture.h" 4#include "hid_core/resources/touch_screen/gesture.h"
5#include "hid_core/resources/touch_screen/touch_screen_resource.h"
12 6
13namespace Service::HID { 7namespace 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 8
21constexpr f32 Square(s32 num) { 9Gesture::Gesture(std::shared_ptr<TouchResource> resource) : touch_resource{resource} {}
22 return static_cast<f32>(num * num);
23}
24 10
25Gesture::Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) {
26 console = hid_core.GetEmulatedConsole();
27}
28Gesture::~Gesture() = default; 11Gesture::~Gesture() = default;
29 12
30void Gesture::OnInit() { 13Result Gesture::Activate() {
31 std::scoped_lock shared_lock{*shared_mutex}; 14 std::scoped_lock lock{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 15
170 // Promote to pan type if touch moved 16 // TODO: Result result = CreateThread();
171 for (size_t id = 0; id < MAX_POINTS; id++) { 17 Result result = ResultSuccess;
172 if (gesture.points[id] != last_gesture.points[id]) { 18 if (result.IsError()) {
173 type = GestureType::Pan; 19 return result;
174 break;
175 }
176 } 20 }
177 21
178 // Number of fingers changed cancel the last event and clear data 22 result = touch_resource->ActivateGesture();
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 23
194 // Promote to press type 24 if (result.IsError()) {
195 if (last_entry.type == GestureType::Touch) { 25 // TODO: StopThread();
196 type = GestureType::Press;
197 } 26 }
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 27
204 if (last_gesture_props.active_points != 0) { 28 return result;
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} 29}
234 30
235void Gesture::SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, 31Result Gesture::Activate(u64 aruid, u32 basic_gesture_id) {
236 GestureType& type, GestureAttribute& attributes) { 32 std::scoped_lock lock{mutex};
237 type = GestureType::Tap; 33 return touch_resource->ActivateGesture(aruid, basic_gesture_id);
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} 34}
247 35
248void Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, 36Result Gesture::Deactivate() {
249 GestureType& type, f32 time_difference) { 37 std::scoped_lock lock{mutex};
250 const auto& last_entry = GetLastGestureEntry(); 38 const auto result = touch_resource->DeactivateGesture();
251 39
252 next_state.delta = gesture.mid_point - last_entry.pos; 40 if (result.IsError()) {
253 next_state.vel_x = static_cast<f32>(next_state.delta.x) / time_difference; 41 return result;
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 } 42 }
263 43
264 const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) / 44 // TODO: return StopThread();
265 (1 + (gesture.angle * last_gesture_props.angle))); 45 return ResultSuccess;
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} 46}
273 47
274void Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, 48Result Gesture::IsActive(bool& out_is_active) const {
275 GestureType& type, f32 time_difference) { 49 out_is_active = touch_resource->IsGestureActive();
276 const auto& last_entry = GetLastGestureEntry(); 50 return ResultSuccess;
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} 51}
365 52
366} // namespace Service::HID 53} // namespace Service::HID
diff --git a/src/hid_core/resources/touch_screen/gesture.h b/src/hid_core/resources/touch_screen/gesture.h
index 32e9a8690..d92912bb6 100644
--- a/src/hid_core/resources/touch_screen/gesture.h
+++ b/src/hid_core/resources/touch_screen/gesture.h
@@ -1,87 +1,32 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#pragma once 4#pragma once
5 5
6#include <array> 6#include <mutex>
7 7
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "hid_core/resources/controller_base.h" 9#include "core/hle/result.h"
10#include "hid_core/resources/touch_screen/touch_types.h"
11
12namespace Core::HID {
13class EmulatedConsole;
14}
15 10
16namespace Service::HID { 11namespace Service::HID {
17struct GestureSharedMemoryFormat; 12class TouchResource;
18 13
19class Gesture final : public ControllerBase { 14/// Handles gesture request from HID interfaces
15class Gesture {
20public: 16public:
21 explicit Gesture(Core::HID::HIDCore& hid_core_); 17 Gesture(std::shared_ptr<TouchResource> resource);
22 ~Gesture() override; 18 ~Gesture();
23 19
24 // Called when the controller is initialized 20 Result Activate();
25 void OnInit() override; 21 Result Activate(u64 aruid, u32 basic_gesture_id);
26 22
27 // When the controller is released 23 Result Deactivate();
28 void OnRelease() override;
29 24
30 // When the controller is requesting an update for the shared memory 25 Result IsActive(bool& out_is_active) const;
31 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
32 26
33private: 27private:
34 // Reads input from all available input engines 28 mutable std::mutex mutex;
35 void ReadTouchInput(); 29 std::shared_ptr<TouchResource> touch_resource;
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}; 30};
31
87} // namespace Service::HID 32} // namespace Service::HID
diff --git a/src/hid_core/resources/touch_screen/gesture_handler.cpp b/src/hid_core/resources/touch_screen/gesture_handler.cpp
new file mode 100644
index 000000000..4fcaf6ecf
--- /dev/null
+++ b/src/hid_core/resources/touch_screen/gesture_handler.cpp
@@ -0,0 +1,260 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/math_util.h"
5#include "hid_core/resources/touch_screen/gesture_handler.h"
6
7namespace Service::HID {
8
9constexpr f32 Square(s32 num) {
10 return static_cast<f32>(num * num);
11}
12
13GestureHandler::GestureHandler() {}
14
15GestureHandler::~GestureHandler() {}
16
17void GestureHandler::SetTouchState(std::span<TouchState> touch_state, u32 count, s64 timestamp) {
18 gesture = {};
19 gesture.active_points = std::min(MaxPoints, static_cast<std::size_t>(count));
20
21 for (size_t id = 0; id < gesture.active_points; ++id) {
22 const auto& [active_x, active_y] = touch_state[id].position;
23 gesture.points[id] = {
24 .x = static_cast<s32>(active_x),
25 .y = static_cast<s32>(active_y),
26 };
27
28 gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points);
29 gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points);
30 }
31
32 for (size_t id = 0; id < gesture.active_points; ++id) {
33 const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) +
34 Square(gesture.mid_point.y - gesture.points[id].y));
35 gesture.average_distance += distance / static_cast<f32>(gesture.active_points);
36 }
37
38 gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y),
39 static_cast<f32>(gesture.mid_point.x - gesture.points[0].x));
40
41 gesture.detection_count = last_gesture.detection_count;
42
43 if (last_update_timestamp > timestamp) {
44 timestamp = last_tap_timestamp;
45 }
46
47 time_difference = static_cast<f32>(timestamp - last_update_timestamp) / (1000 * 1000 * 1000);
48}
49
50bool GestureHandler::NeedsUpdate() {
51 if (force_update) {
52 force_update = false;
53 return true;
54 }
55
56 // Update if coordinates change
57 for (size_t id = 0; id < MaxPoints; id++) {
58 if (gesture.points[id] != last_gesture.points[id]) {
59 return true;
60 }
61 }
62
63 // Update on press and hold event after 0.5 seconds
64 if (last_gesture_state.type == GestureType::Touch && last_gesture_state.point_count == 1 &&
65 time_difference > PressDelay) {
66 return enable_press_and_tap;
67 }
68
69 return false;
70}
71
72void GestureHandler::UpdateGestureState(GestureState& next_state, s64 timestamp) {
73 last_update_timestamp = timestamp;
74
75 GestureType type = GestureType::Idle;
76 GestureAttribute attributes{};
77
78 // Reset next state to default
79 next_state.sampling_number = last_gesture_state.sampling_number + 1;
80 next_state.delta = {};
81 next_state.vel_x = 0;
82 next_state.vel_y = 0;
83 next_state.direction = GestureDirection::None;
84 next_state.rotation_angle = 0;
85 next_state.scale = 0;
86
87 if (gesture.active_points > 0) {
88 if (last_gesture.active_points == 0) {
89 NewGesture(type, attributes);
90 } else {
91 UpdateExistingGesture(next_state, type);
92 }
93 } else {
94 EndGesture(next_state, type, attributes);
95 }
96
97 // Apply attributes
98 next_state.detection_count = gesture.detection_count;
99 next_state.type = type;
100 next_state.attributes = attributes;
101 next_state.pos = gesture.mid_point;
102 next_state.point_count = static_cast<s32>(gesture.active_points);
103 next_state.points = gesture.points;
104 last_gesture = gesture;
105 last_gesture_state = next_state;
106}
107
108void GestureHandler::NewGesture(GestureType& type, GestureAttribute& attributes) {
109 gesture.detection_count++;
110 type = GestureType::Touch;
111
112 // New touch after cancel is not considered new
113 if (last_gesture_state.type != GestureType::Cancel) {
114 attributes.is_new_touch.Assign(1);
115 enable_press_and_tap = true;
116 }
117}
118
119void GestureHandler::UpdateExistingGesture(GestureState& next_state, GestureType& type) {
120 // Promote to pan type if touch moved
121 for (size_t id = 0; id < MaxPoints; id++) {
122 if (gesture.points[id] != last_gesture.points[id]) {
123 type = GestureType::Pan;
124 break;
125 }
126 }
127
128 // Number of fingers changed cancel the last event and clear data
129 if (gesture.active_points != last_gesture.active_points) {
130 type = GestureType::Cancel;
131 enable_press_and_tap = false;
132 gesture.active_points = 0;
133 gesture.mid_point = {};
134 gesture.points.fill({});
135 return;
136 }
137
138 // Calculate extra parameters of panning
139 if (type == GestureType::Pan) {
140 UpdatePanEvent(next_state, type);
141 return;
142 }
143
144 // Promote to press type
145 if (last_gesture_state.type == GestureType::Touch) {
146 type = GestureType::Press;
147 }
148}
149
150void GestureHandler::EndGesture(GestureState& next_state, GestureType& type,
151 GestureAttribute& attributes) {
152 if (last_gesture.active_points != 0) {
153 switch (last_gesture_state.type) {
154 case GestureType::Touch:
155 if (enable_press_and_tap) {
156 SetTapEvent(type, attributes);
157 return;
158 }
159 type = GestureType::Cancel;
160 force_update = true;
161 break;
162 case GestureType::Press:
163 case GestureType::Tap:
164 case GestureType::Swipe:
165 case GestureType::Pinch:
166 case GestureType::Rotate:
167 type = GestureType::Complete;
168 force_update = true;
169 break;
170 case GestureType::Pan:
171 EndPanEvent(next_state, type);
172 break;
173 default:
174 break;
175 }
176 return;
177 }
178 if (last_gesture_state.type == GestureType::Complete ||
179 last_gesture_state.type == GestureType::Cancel) {
180 gesture.detection_count++;
181 }
182}
183
184void GestureHandler::SetTapEvent(GestureType& type, GestureAttribute& attributes) {
185 type = GestureType::Tap;
186 gesture = last_gesture;
187 force_update = true;
188 f32 tap_time_difference =
189 static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000);
190 last_tap_timestamp = last_update_timestamp;
191 if (tap_time_difference < DoubleTapDelay) {
192 attributes.is_double_tap.Assign(1);
193 }
194}
195
196void GestureHandler::UpdatePanEvent(GestureState& next_state, GestureType& type) {
197 next_state.delta = gesture.mid_point - last_gesture_state.pos;
198 next_state.vel_x = static_cast<f32>(next_state.delta.x) / time_difference;
199 next_state.vel_y = static_cast<f32>(next_state.delta.y) / time_difference;
200 last_pan_time_difference = time_difference;
201
202 // Promote to pinch type
203 if (std::abs(gesture.average_distance - last_gesture.average_distance) > PinchThreshold) {
204 type = GestureType::Pinch;
205 next_state.scale = gesture.average_distance / last_gesture.average_distance;
206 }
207
208 const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture.angle) /
209 (1 + (gesture.angle * last_gesture.angle)));
210 // Promote to rotate type
211 if (std::abs(angle_between_two_lines) > AngleThreshold) {
212 type = GestureType::Rotate;
213 next_state.scale = 0;
214 next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI;
215 }
216}
217
218void GestureHandler::EndPanEvent(GestureState& next_state, GestureType& type) {
219 next_state.vel_x =
220 static_cast<f32>(last_gesture_state.delta.x) / (last_pan_time_difference + time_difference);
221 next_state.vel_y =
222 static_cast<f32>(last_gesture_state.delta.y) / (last_pan_time_difference + time_difference);
223 const f32 curr_vel =
224 std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y));
225
226 // Set swipe event with parameters
227 if (curr_vel > SwipeThreshold) {
228 SetSwipeEvent(next_state, type);
229 return;
230 }
231
232 // End panning without swipe
233 type = GestureType::Complete;
234 next_state.vel_x = 0;
235 next_state.vel_y = 0;
236 force_update = true;
237}
238
239void GestureHandler::SetSwipeEvent(GestureState& next_state, GestureType& type) {
240 type = GestureType::Swipe;
241 gesture = last_gesture;
242 force_update = true;
243 next_state.delta = last_gesture_state.delta;
244
245 if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) {
246 if (next_state.delta.x > 0) {
247 next_state.direction = GestureDirection::Right;
248 return;
249 }
250 next_state.direction = GestureDirection::Left;
251 return;
252 }
253 if (next_state.delta.y > 0) {
254 next_state.direction = GestureDirection::Down;
255 return;
256 }
257 next_state.direction = GestureDirection::Up;
258}
259
260} // namespace Service::HID
diff --git a/src/hid_core/resources/touch_screen/gesture_handler.h b/src/hid_core/resources/touch_screen/gesture_handler.h
new file mode 100644
index 000000000..fda2040c9
--- /dev/null
+++ b/src/hid_core/resources/touch_screen/gesture_handler.h
@@ -0,0 +1,55 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <span>
7
8#include "hid_core/resources/touch_screen/touch_types.h"
9
10namespace Service::HID {
11
12class GestureHandler {
13public:
14 GestureHandler();
15 ~GestureHandler();
16
17 void SetTouchState(std::span<TouchState> touch_state, u32 count, s64 timestamp);
18
19 bool NeedsUpdate();
20 void UpdateGestureState(GestureState& next_state, s64 timestamp);
21
22private:
23 // Initializes new gesture
24 void NewGesture(GestureType& type, GestureAttribute& attributes);
25
26 // Updates existing gesture state
27 void UpdateExistingGesture(GestureState& next_state, GestureType& type);
28
29 // Terminates exiting gesture
30 void EndGesture(GestureState& next_state, GestureType& type, GestureAttribute& attributes);
31
32 // Set current event to a tap event
33 void SetTapEvent(GestureType& type, GestureAttribute& attributes);
34
35 // Calculates and set the extra parameters related to a pan event
36 void UpdatePanEvent(GestureState& next_state, GestureType& type);
37
38 // Terminates the pan event
39 void EndPanEvent(GestureState& next_state, GestureType& type);
40
41 // Set current event to a swipe event
42 void SetSwipeEvent(GestureState& next_state, GestureType& type);
43
44 GestureProperties gesture{};
45 GestureProperties last_gesture{};
46 GestureState last_gesture_state{};
47 s64 last_update_timestamp{};
48 s64 last_tap_timestamp{};
49 f32 last_pan_time_difference{};
50 f32 time_difference{};
51 bool force_update{true};
52 bool enable_press_and_tap{false};
53};
54
55} // namespace Service::HID
diff --git a/src/hid_core/resources/touch_screen/gesture_types.h b/src/hid_core/resources/touch_screen/gesture_types.h
deleted file mode 100644
index b4f034cd3..000000000
--- a/src/hid_core/resources/touch_screen/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/hid_core/resources/touch_screen/touch_screen.cpp b/src/hid_core/resources/touch_screen/touch_screen.cpp
index 48d956c51..35efb1786 100644
--- a/src/hid_core/resources/touch_screen/touch_screen.cpp
+++ b/src/hid_core/resources/touch_screen/touch_screen.cpp
@@ -1,132 +1,119 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#include <algorithm> 4#include "hid_core/hid_types.h"
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 "hid_core/frontend/emulated_console.h"
10#include "hid_core/hid_core.h"
11#include "hid_core/resources/applet_resource.h"
12#include "hid_core/resources/shared_memory_format.h"
13#include "hid_core/resources/touch_screen/touch_screen.h" 5#include "hid_core/resources/touch_screen/touch_screen.h"
6#include "hid_core/resources/touch_screen/touch_screen_resource.h"
14 7
15namespace Service::HID { 8namespace Service::HID {
16 9
17TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_) 10TouchScreen::TouchScreen(std::shared_ptr<TouchResource> resource) : touch_resource{resource} {}
18 : ControllerBase{hid_core_}, touchscreen_width(Layout::ScreenUndocked::Width),
19 touchscreen_height(Layout::ScreenUndocked::Height) {
20 console = hid_core.GetEmulatedConsole();
21}
22 11
23TouchScreen::~TouchScreen() = default; 12TouchScreen::~TouchScreen() = default;
24 13
25void TouchScreen::OnInit() {} 14Result TouchScreen::Activate() {
15 std::scoped_lock lock{mutex};
26 16
27void TouchScreen::OnRelease() {} 17 // TODO: Result result = CreateThread();
28 18 Result result = ResultSuccess;
29void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 19 if (result.IsError()) {
30 const u64 aruid = applet_resource->GetActiveAruid(); 20 return result;
31 auto* data = applet_resource->GetAruidData(aruid); 21 }
32 22
33 if (data == nullptr || !data->flag.is_assigned) { 23 result = touch_resource->ActivateTouch();
34 return; 24 if (result.IsError()) {
25 // TODO: StopThread();
35 } 26 }
36 27
37 TouchScreenSharedMemoryFormat& shared_memory = data->shared_memory_format->touch_screen; 28 return result;
38 shared_memory.touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count(); 29}
39 30
40 if (!IsControllerActivated()) { 31Result TouchScreen::Activate(u64 aruid) {
41 shared_memory.touch_screen_lifo.buffer_count = 0; 32 std::scoped_lock lock{mutex};
42 shared_memory.touch_screen_lifo.buffer_tail = 0; 33 return touch_resource->ActivateTouch(aruid);
43 return; 34}
44 }
45 35
46 const auto touch_status = console->GetTouch(); 36Result TouchScreen::Deactivate() {
47 for (std::size_t id = 0; id < MAX_FINGERS; id++) { 37 std::scoped_lock lock{mutex};
48 const auto& current_touch = touch_status[id]; 38 const auto result = touch_resource->DeactivateTouch();
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 39
85 std::array<Core::HID::TouchFinger, MAX_FINGERS> active_fingers; 40 if (result.IsError()) {
86 const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), 41 return result;
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 } 42 }
123 43
124 shared_memory.touch_screen_lifo.WriteNextEntry(next_state); 44 // TODO: return StopThread();
45 return ResultSuccess;
46}
47
48Result TouchScreen::IsActive(bool& out_is_active) const {
49 out_is_active = touch_resource->IsTouchActive();
50 return ResultSuccess;
51}
52
53Result TouchScreen::SetTouchScreenAutoPilotState(const AutoPilotState& auto_pilot_state) {
54 std::scoped_lock lock{mutex};
55 return touch_resource->SetTouchScreenAutoPilotState(auto_pilot_state);
56}
57
58Result TouchScreen::UnsetTouchScreenAutoPilotState() {
59 std::scoped_lock lock{mutex};
60 return touch_resource->UnsetTouchScreenAutoPilotState();
61}
62
63Result TouchScreen::RequestNextTouchInput() {
64 std::scoped_lock lock{mutex};
65 return touch_resource->RequestNextTouchInput();
66}
67
68Result TouchScreen::RequestNextDummyInput() {
69 std::scoped_lock lock{mutex};
70 return touch_resource->RequestNextDummyInput();
71}
72
73Result TouchScreen::ProcessTouchScreenAutoTune() {
74 std::scoped_lock lock{mutex};
75 return touch_resource->ProcessTouchScreenAutoTune();
76}
77
78Result TouchScreen::SetTouchScreenMagnification(f32 point1_x, f32 point1_y, f32 point2_x,
79 f32 point2_y) {
80 std::scoped_lock lock{mutex};
81 touch_resource->SetTouchScreenMagnification(point1_x, point1_y, point2_x, point2_y);
82 return ResultSuccess;
83}
84
85Result TouchScreen::SetTouchScreenResolution(u32 width, u32 height, u64 aruid) {
86 std::scoped_lock lock{mutex};
87 return touch_resource->SetTouchScreenResolution(width, height, aruid);
88}
89
90Result TouchScreen::SetTouchScreenConfiguration(
91 const Core::HID::TouchScreenConfigurationForNx& mode, u64 aruid) {
92 std::scoped_lock lock{mutex};
93 return touch_resource->SetTouchScreenConfiguration(mode, aruid);
94}
95
96Result TouchScreen::GetTouchScreenConfiguration(Core::HID::TouchScreenConfigurationForNx& out_mode,
97 u64 aruid) const {
98 std::scoped_lock lock{mutex};
99 return touch_resource->GetTouchScreenConfiguration(out_mode, aruid);
100}
101
102Result TouchScreen::SetTouchScreenDefaultConfiguration(
103 const Core::HID::TouchScreenConfigurationForNx& mode) {
104 std::scoped_lock lock{mutex};
105 return touch_resource->SetTouchScreenDefaultConfiguration(mode);
106}
107
108Result TouchScreen::GetTouchScreenDefaultConfiguration(
109 Core::HID::TouchScreenConfigurationForNx& out_mode) const {
110 std::scoped_lock lock{mutex};
111 return touch_resource->GetTouchScreenDefaultConfiguration(out_mode);
125} 112}
126 113
127void TouchScreen::SetTouchscreenDimensions(u32 width, u32 height) { 114void TouchScreen::OnTouchUpdate(u64 timestamp) {
128 touchscreen_width = width; 115 std::scoped_lock lock{mutex};
129 touchscreen_height = height; 116 touch_resource->OnTouchUpdate(timestamp);
130} 117}
131 118
132} // namespace Service::HID 119} // namespace Service::HID
diff --git a/src/hid_core/resources/touch_screen/touch_screen.h b/src/hid_core/resources/touch_screen/touch_screen.h
index 4b3824742..2fcb6247f 100644
--- a/src/hid_core/resources/touch_screen/touch_screen.h
+++ b/src/hid_core/resources/touch_screen/touch_screen.h
@@ -1,43 +1,64 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#pragma once 4#pragma once
5 5
6#include <array> 6#include <mutex>
7 7
8#include "hid_core/hid_types.h" 8#include "common/common_types.h"
9#include "hid_core/resources/controller_base.h" 9#include "core/hle/result.h"
10#include "hid_core/resources/touch_screen/touch_types.h"
11 10
12namespace Core::HID { 11namespace Core::HID {
13class EmulatedConsole; 12struct TouchScreenConfigurationForNx;
14} // namespace Core::HID 13}
14
15namespace Core::Timing {
16struct EventType;
17}
15 18
16namespace Service::HID { 19namespace Service::HID {
17struct TouchScreenSharedMemoryFormat; 20class TouchResource;
21struct AutoPilotState;
18 22
19class TouchScreen final : public ControllerBase { 23/// Handles touch request from HID interfaces
24class TouchScreen {
20public: 25public:
21 explicit TouchScreen(Core::HID::HIDCore& hid_core_); 26 TouchScreen(std::shared_ptr<TouchResource> resource);
22 ~TouchScreen() override; 27 ~TouchScreen();
23 28
24 // Called when the controller is initialized 29 Result Activate();
25 void OnInit() override; 30 Result Activate(u64 aruid);
26 31
27 // When the controller is released 32 Result Deactivate();
28 void OnRelease() override;
29 33
30 // When the controller is requesting an update for the shared memory 34 Result IsActive(bool& out_is_active) const;
31 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
32 35
33 void SetTouchscreenDimensions(u32 width, u32 height); 36 Result SetTouchScreenAutoPilotState(const AutoPilotState& auto_pilot_state);
37 Result UnsetTouchScreenAutoPilotState();
34 38
35private: 39 Result RequestNextTouchInput();
36 TouchScreenState next_state{}; 40 Result RequestNextDummyInput();
37 Core::HID::EmulatedConsole* console = nullptr; 41
42 Result ProcessTouchScreenAutoTune();
43
44 Result SetTouchScreenMagnification(f32 point1_x, f32 point1_y, f32 point2_x, f32 point2_y);
45 Result SetTouchScreenResolution(u32 width, u32 height, u64 aruid);
46
47 Result SetTouchScreenConfiguration(const Core::HID::TouchScreenConfigurationForNx& mode,
48 u64 aruid);
49 Result GetTouchScreenConfiguration(Core::HID::TouchScreenConfigurationForNx& out_mode,
50 u64 aruid) const;
38 51
39 std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{}; 52 Result SetTouchScreenDefaultConfiguration(const Core::HID::TouchScreenConfigurationForNx& mode);
40 u32 touchscreen_width; 53 Result GetTouchScreenDefaultConfiguration(
41 u32 touchscreen_height; 54 Core::HID::TouchScreenConfigurationForNx& out_mode) const;
55
56 void OnTouchUpdate(u64 timestamp);
57
58private:
59 mutable std::mutex mutex;
60 std::shared_ptr<TouchResource> touch_resource;
61 std::shared_ptr<Core::Timing::EventType> touch_update_event;
42}; 62};
63
43} // namespace Service::HID 64} // namespace Service::HID
diff --git a/src/hid_core/resources/touch_screen/touch_screen_driver.cpp b/src/hid_core/resources/touch_screen/touch_screen_driver.cpp
new file mode 100644
index 000000000..6a64c75b3
--- /dev/null
+++ b/src/hid_core/resources/touch_screen/touch_screen_driver.cpp
@@ -0,0 +1,114 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <algorithm>
5#include "common/settings.h"
6#include "core/frontend/emu_window.h"
7#include "hid_core/hid_core.h"
8#include "hid_core/resources/touch_screen/touch_screen_driver.h"
9
10namespace Service::HID {
11
12TouchDriver::TouchDriver(Core::HID::HIDCore& hid_core) {
13 console = hid_core.GetEmulatedConsole();
14}
15
16TouchDriver::~TouchDriver() = default;
17
18Result TouchDriver::StartTouchSensor() {
19 is_running = true;
20 return ResultSuccess;
21}
22
23Result TouchDriver::StopTouchSensor() {
24 is_running = false;
25 return ResultSuccess;
26}
27
28bool TouchDriver::IsRunning() const {
29 return is_running;
30}
31
32void TouchDriver::ProcessTouchScreenAutoTune() const {
33 // TODO
34}
35
36Result TouchDriver::WaitForDummyInput() {
37 touch_status = {};
38 return ResultSuccess;
39}
40
41Result TouchDriver::WaitForInput() {
42 touch_status = {};
43 const auto touch_input = console->GetTouch();
44 for (std::size_t id = 0; id < touch_status.states.size(); id++) {
45 const auto& current_touch = touch_input[id];
46 auto& finger = fingers[id];
47 finger.id = current_touch.id;
48
49 if (finger.attribute.start_touch) {
50 finger.attribute.raw = 0;
51 continue;
52 }
53
54 if (finger.attribute.end_touch) {
55 finger.attribute.raw = 0;
56 finger.pressed = false;
57 continue;
58 }
59
60 if (!finger.pressed && current_touch.pressed) {
61 finger.attribute.start_touch.Assign(1);
62 finger.pressed = true;
63 finger.position = current_touch.position;
64 continue;
65 }
66
67 if (finger.pressed && !current_touch.pressed) {
68 finger.attribute.raw = 0;
69 finger.attribute.end_touch.Assign(1);
70 continue;
71 }
72
73 // Only update position if touch is not on a special frame
74 finger.position = current_touch.position;
75 }
76
77 std::array<Core::HID::TouchFinger, MaxFingers> active_fingers;
78 const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),
79 [](const auto& finger) { return finger.pressed; });
80 const auto active_fingers_count =
81 static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
82
83 touch_status.entry_count = static_cast<s32>(active_fingers_count);
84 for (std::size_t id = 0; id < MaxFingers; ++id) {
85 auto& touch_entry = touch_status.states[id];
86 if (id < active_fingers_count) {
87 const auto& [active_x, active_y] = active_fingers[id].position;
88 touch_entry.position = {
89 .x = static_cast<u16>(active_x * TouchSensorWidth),
90 .y = static_cast<u16>(active_y * TouchSensorHeight),
91 };
92 touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
93 touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
94 touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
95 touch_entry.finger = active_fingers[id].id;
96 touch_entry.attribute.raw = active_fingers[id].attribute.raw;
97 }
98 }
99 return ResultSuccess;
100}
101
102void TouchDriver::GetNextTouchState(TouchScreenState& out_state) const {
103 out_state = touch_status;
104}
105
106void TouchDriver::SetTouchMode(Core::HID::TouchScreenModeForNx mode) {
107 touch_mode = mode;
108}
109
110Core::HID::TouchScreenModeForNx TouchDriver::GetTouchMode() const {
111 return touch_mode;
112}
113
114} // namespace Service::HID
diff --git a/src/hid_core/resources/touch_screen/touch_screen_driver.h b/src/hid_core/resources/touch_screen/touch_screen_driver.h
new file mode 100644
index 000000000..ca7e4970e
--- /dev/null
+++ b/src/hid_core/resources/touch_screen/touch_screen_driver.h
@@ -0,0 +1,47 @@
1// SPDX-FileCopyrightText: Copyright 2024 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/hle/result.h"
8#include "hid_core/frontend/emulated_console.h"
9#include "hid_core/hid_types.h"
10#include "hid_core/resources/touch_screen/touch_types.h"
11
12namespace Core::HID {
13class HIDCore;
14} // namespace Core::HID
15
16namespace Service::HID {
17
18/// This handles all request to Ftm3bd56(TouchPanel) hardware
19class TouchDriver {
20public:
21 explicit TouchDriver(Core::HID::HIDCore& hid_core);
22 ~TouchDriver();
23
24 Result StartTouchSensor();
25 Result StopTouchSensor();
26 bool IsRunning() const;
27
28 void ProcessTouchScreenAutoTune() const;
29
30 Result WaitForDummyInput();
31 Result WaitForInput();
32
33 void GetNextTouchState(TouchScreenState& out_state) const;
34
35 void SetTouchMode(Core::HID::TouchScreenModeForNx mode);
36 Core::HID::TouchScreenModeForNx GetTouchMode() const;
37
38private:
39 bool is_running{};
40 TouchScreenState touch_status{};
41 Core::HID::TouchFingerState fingers{};
42 Core::HID::TouchScreenModeForNx touch_mode{};
43
44 Core::HID::EmulatedConsole* console = nullptr;
45};
46
47} // namespace Service::HID
diff --git a/src/hid_core/resources/touch_screen/touch_screen_resource.cpp b/src/hid_core/resources/touch_screen/touch_screen_resource.cpp
new file mode 100644
index 000000000..56e8e8e51
--- /dev/null
+++ b/src/hid_core/resources/touch_screen/touch_screen_resource.cpp
@@ -0,0 +1,579 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/logging/log.h"
5#include "core/core_timing.h"
6#include "core/hle/kernel/k_event.h"
7#include "core/hle/kernel/k_shared_memory.h"
8#include "core/hle/service/set/system_settings_server.h"
9#include "core/hle/service/sm/sm.h"
10#include "hid_core/hid_result.h"
11#include "hid_core/resources/applet_resource.h"
12#include "hid_core/resources/shared_memory_format.h"
13#include "hid_core/resources/touch_screen/touch_screen_driver.h"
14#include "hid_core/resources/touch_screen/touch_screen_resource.h"
15
16namespace Service::HID {
17constexpr auto GestureUpdatePeriod = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz)
18
19TouchResource::TouchResource(Core::System& system_) : system{system_} {
20 m_set_sys = system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys");
21}
22
23TouchResource::~TouchResource() {
24 Finalize();
25};
26
27Result TouchResource::ActivateTouch() {
28 if (global_ref_counter == std::numeric_limits<s32>::max() - 1 ||
29 touch_ref_counter == std::numeric_limits<s32>::max() - 1) {
30 return ResultTouchOverflow;
31 }
32
33 if (global_ref_counter == 0) {
34 std::scoped_lock lock{*shared_mutex};
35
36 const auto result = touch_driver->StartTouchSensor();
37 if (result.IsError()) {
38 return result;
39 }
40
41 is_initalized = true;
42 system.CoreTiming().ScheduleLoopingEvent(GestureUpdatePeriod, GestureUpdatePeriod,
43 timer_event);
44 current_touch_state = {};
45 ReadTouchInput();
46 gesture_handler.SetTouchState(current_touch_state.states, current_touch_state.entry_count,
47 0);
48 }
49
50 Set::TouchScreenMode touch_mode{Set::TouchScreenMode::Standard};
51 m_set_sys->GetTouchScreenMode(touch_mode);
52 default_touch_screen_mode = static_cast<Core::HID::TouchScreenModeForNx>(touch_mode);
53
54 global_ref_counter++;
55 touch_ref_counter++;
56 return ResultSuccess;
57}
58
59Result TouchResource::ActivateTouch(u64 aruid) {
60 std::scoped_lock lock{*shared_mutex};
61
62 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
63 auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index);
64 TouchAruidData& touch_data = aruid_data[aruid_index];
65
66 if (!applet_data->flag.is_assigned) {
67 touch_data = {};
68 continue;
69 }
70
71 const u64 aruid_id = applet_data->aruid;
72 if (touch_data.aruid != aruid_id) {
73 touch_data = {};
74 touch_data.aruid = aruid_id;
75 }
76
77 if (aruid != aruid_id) {
78 continue;
79 }
80
81 auto& touch_shared = applet_data->shared_memory_format->touch_screen;
82
83 if (touch_shared.touch_screen_lifo.buffer_count == 0) {
84 StorePreviousTouchState(previous_touch_state, touch_data.finger_map,
85 current_touch_state,
86 applet_data->flag.enable_touchscreen.Value() != 0);
87 touch_shared.touch_screen_lifo.WriteNextEntry(previous_touch_state);
88 }
89 }
90 return ResultSuccess;
91}
92
93Result TouchResource::ActivateGesture() {
94 if (global_ref_counter == std::numeric_limits<s32>::max() - 1 ||
95 gesture_ref_counter == std::numeric_limits<s32>::max() - 1) {
96 return ResultGestureOverflow;
97 }
98
99 // Initialize first instance
100 if (global_ref_counter == 0) {
101 const auto result = touch_driver->StartTouchSensor();
102 if (result.IsError()) {
103 return result;
104 }
105
106 is_initalized = true;
107 system.CoreTiming().ScheduleLoopingEvent(GestureUpdatePeriod, GestureUpdatePeriod,
108 timer_event);
109 current_touch_state = {};
110 ReadTouchInput();
111 gesture_handler.SetTouchState(current_touch_state.states, current_touch_state.entry_count,
112 0);
113 }
114
115 global_ref_counter++;
116 gesture_ref_counter++;
117 return ResultSuccess;
118}
119
120Result TouchResource::ActivateGesture(u64 aruid, u32 basic_gesture_id) {
121 std::scoped_lock lock{*shared_mutex};
122
123 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
124 auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index);
125 TouchAruidData& touch_data = aruid_data[aruid_index];
126
127 if (!applet_data->flag.is_assigned) {
128 touch_data = {};
129 continue;
130 }
131
132 const u64 aruid_id = applet_data->aruid;
133 if (touch_data.aruid != aruid_id) {
134 touch_data = {};
135 touch_data.aruid = aruid_id;
136 }
137
138 if (aruid != aruid_id) {
139 continue;
140 }
141
142 auto& gesture_shared = applet_data->shared_memory_format->gesture;
143 if (touch_data.basic_gesture_id != basic_gesture_id) {
144 gesture_shared.gesture_lifo.buffer_count = 0;
145 }
146
147 if (gesture_shared.gesture_lifo.buffer_count == 0) {
148 touch_data.basic_gesture_id = basic_gesture_id;
149
150 gesture_shared.gesture_lifo.WriteNextEntry(gesture_state);
151 }
152 }
153
154 return ResultSuccess;
155}
156
157Result TouchResource::DeactivateTouch() {
158 if (touch_ref_counter == 0 || global_ref_counter == 0) {
159 return ResultTouchNotInitialized;
160 }
161
162 global_ref_counter--;
163 touch_ref_counter--;
164
165 if (touch_ref_counter + global_ref_counter != 0) {
166 return ResultSuccess;
167 }
168
169 return Finalize();
170}
171
172Result TouchResource::DeactivateGesture() {
173 if (gesture_ref_counter == 0 || global_ref_counter == 0) {
174 return ResultGestureNotInitialized;
175 }
176
177 global_ref_counter--;
178 gesture_ref_counter--;
179
180 if (touch_ref_counter + global_ref_counter != 0) {
181 return ResultSuccess;
182 }
183
184 return Finalize();
185}
186
187bool TouchResource::IsTouchActive() const {
188 return touch_ref_counter != 0;
189}
190
191bool TouchResource::IsGestureActive() const {
192 return gesture_ref_counter != 0;
193}
194
195void TouchResource::SetTouchDriver(std::shared_ptr<TouchDriver> driver) {
196 touch_driver = driver;
197}
198
199void TouchResource::SetAppletResource(std::shared_ptr<AppletResource> shared,
200 std::recursive_mutex* mutex) {
201 applet_resource = shared;
202 shared_mutex = mutex;
203}
204
205void TouchResource::SetInputEvent(Kernel::KEvent* event, std::mutex* mutex) {
206 input_event = event;
207 input_mutex = mutex;
208}
209
210void TouchResource::SetHandheldConfig(std::shared_ptr<HandheldConfig> config) {
211 handheld_config = config;
212}
213
214void TouchResource::SetTimerEvent(std::shared_ptr<Core::Timing::EventType> event) {
215 timer_event = event;
216}
217
218Result TouchResource::SetTouchScreenAutoPilotState(const AutoPilotState& auto_pilot_state) {
219 if (global_ref_counter == 0) {
220 return ResultTouchNotInitialized;
221 }
222
223 if (!is_auto_pilot_initialized) {
224 is_auto_pilot_initialized = true;
225 auto_pilot = {};
226 }
227
228 TouchScreenState state = {
229 .entry_count = static_cast<s32>(auto_pilot_state.count),
230 .states = auto_pilot_state.state,
231 };
232
233 SanitizeInput(state);
234
235 auto_pilot.count = state.entry_count;
236 auto_pilot.state = state.states;
237 return ResultSuccess;
238}
239
240Result TouchResource::UnsetTouchScreenAutoPilotState() {
241 if (global_ref_counter == 0) {
242 return ResultTouchNotInitialized;
243 }
244
245 is_auto_pilot_initialized = false;
246 auto_pilot = {};
247 return ResultSuccess;
248}
249
250Result TouchResource::RequestNextTouchInput() {
251 if (global_ref_counter == 0) {
252 return ResultTouchNotInitialized;
253 }
254
255 if (handheld_config->is_handheld_hid_enabled) {
256 const Result result = touch_driver->WaitForInput();
257 if (result.IsError()) {
258 return result;
259 }
260 }
261
262 is_initalized = true;
263 return ResultSuccess;
264}
265
266Result TouchResource::RequestNextDummyInput() {
267 if (global_ref_counter == 0) {
268 return ResultTouchNotInitialized;
269 }
270
271 if (handheld_config->is_handheld_hid_enabled) {
272 const Result result = touch_driver->WaitForDummyInput();
273 if (result.IsError()) {
274 return result;
275 }
276 }
277
278 is_initalized = false;
279 return ResultSuccess;
280}
281
282Result TouchResource::ProcessTouchScreenAutoTune() {
283 touch_driver->ProcessTouchScreenAutoTune();
284 return ResultSuccess;
285}
286
287void TouchResource::SetTouchScreenMagnification(f32 point1_x, f32 point1_y, f32 point2_x,
288 f32 point2_y) {
289 offset = {
290 .x = point1_x,
291 .y = point1_y,
292 };
293 magnification = {
294 .x = point2_x,
295 .y = point2_y,
296 };
297}
298
299Result TouchResource::SetTouchScreenResolution(u32 width, u32 height, u64 aruid) {
300 std::scoped_lock lock{*shared_mutex};
301
302 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
303 const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index);
304 TouchAruidData& data = aruid_data[aruid_index];
305
306 if (!applet_data->flag.is_assigned) {
307 continue;
308 }
309 if (aruid != data.aruid) {
310 continue;
311 }
312 data.resolution_width = static_cast<u16>(width);
313 data.resolution_height = static_cast<u16>(height);
314 }
315
316 return ResultSuccess;
317}
318
319Result TouchResource::SetTouchScreenConfiguration(
320 const Core::HID::TouchScreenConfigurationForNx& touch_configuration, u64 aruid) {
321 std::scoped_lock lock{*shared_mutex};
322
323 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
324 const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index);
325 TouchAruidData& data = aruid_data[aruid_index];
326
327 if (!applet_data->flag.is_assigned) {
328 continue;
329 }
330 if (aruid != data.aruid) {
331 continue;
332 }
333 data.finger_map.touch_mode = touch_configuration.mode;
334 }
335
336 return ResultSuccess;
337}
338
339Result TouchResource::GetTouchScreenConfiguration(
340 Core::HID::TouchScreenConfigurationForNx& out_touch_configuration, u64 aruid) const {
341 std::scoped_lock lock{*shared_mutex};
342
343 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
344 const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index);
345 const TouchAruidData& data = aruid_data[aruid_index];
346
347 if (!applet_data->flag.is_assigned) {
348 continue;
349 }
350 if (aruid != data.aruid) {
351 continue;
352 }
353 out_touch_configuration.mode = data.finger_map.touch_mode;
354 }
355
356 return ResultSuccess;
357}
358
359Result TouchResource::SetTouchScreenDefaultConfiguration(
360 const Core::HID::TouchScreenConfigurationForNx& touch_configuration) {
361 default_touch_screen_mode = touch_configuration.mode;
362 return ResultSuccess;
363}
364
365Result TouchResource::GetTouchScreenDefaultConfiguration(
366 Core::HID::TouchScreenConfigurationForNx& out_touch_configuration) const {
367 out_touch_configuration.mode = default_touch_screen_mode;
368 return ResultSuccess;
369}
370
371Result TouchResource::Finalize() {
372 is_auto_pilot_initialized = false;
373 auto_pilot = {};
374 system.CoreTiming().UnscheduleEvent(timer_event);
375
376 const auto result = touch_driver->StopTouchSensor();
377 if (result.IsError()) {
378 return result;
379 }
380
381 is_initalized = false;
382 return ResultSuccess;
383}
384
385void TouchResource::StorePreviousTouchState(TouchScreenState& out_previous_touch,
386 TouchFingerMap& out_finger_map,
387 const TouchScreenState& current_touch,
388 bool is_touch_enabled) const {
389 s32 finger_count{};
390
391 if (is_touch_enabled) {
392 finger_count = current_touch.entry_count;
393 if (finger_count < 1) {
394 out_finger_map.finger_count = 0;
395 out_finger_map.finger_ids = {};
396 out_previous_touch.sampling_number = current_touch.sampling_number;
397 out_previous_touch.entry_count = 0;
398 out_previous_touch.states = {};
399 return;
400 }
401 for (std::size_t i = 0; i < static_cast<u32>(finger_count); i++) {
402 out_finger_map.finger_ids[i] = current_touch.states[i].finger;
403 out_previous_touch.states[i] = current_touch.states[i];
404 }
405 out_finger_map.finger_count = finger_count;
406 return;
407 }
408
409 if (!is_touch_enabled && out_finger_map.finger_count > 0 && current_touch.entry_count > 0) {
410 // TODO
411 }
412
413 // Zero out unused entries
414 for (std::size_t i = finger_count; i < MaxFingers; i++) {
415 out_finger_map.finger_ids[i] = 0;
416 out_previous_touch.states[i] = {};
417 }
418
419 out_previous_touch.sampling_number = current_touch.sampling_number;
420 out_previous_touch.entry_count = finger_count;
421}
422
423void TouchResource::ReadTouchInput() {
424 previous_touch_state = current_touch_state;
425
426 if (!is_initalized || !handheld_config->is_handheld_hid_enabled || !touch_driver->IsRunning()) {
427 touch_driver->WaitForDummyInput();
428 } else {
429 touch_driver->WaitForInput();
430 }
431
432 touch_driver->GetNextTouchState(current_touch_state);
433 SanitizeInput(current_touch_state);
434 current_touch_state.sampling_number = sample_number;
435 sample_number++;
436
437 if (is_auto_pilot_initialized && current_touch_state.entry_count == 0) {
438 const std::size_t finger_count = static_cast<std::size_t>(auto_pilot.count);
439 current_touch_state.entry_count = static_cast<s32>(finger_count);
440 for (std::size_t i = 0; i < finger_count; i++) {
441 current_touch_state.states[i] = auto_pilot.state[i];
442 }
443
444 std::size_t index = 0;
445 for (std::size_t i = 0; i < finger_count; i++) {
446 if (auto_pilot.state[i].attribute.end_touch) {
447 continue;
448 }
449 auto_pilot.state[i].attribute.raw = 0;
450 auto_pilot.state[index] = auto_pilot.state[i];
451 index++;
452 }
453
454 auto_pilot.count = index;
455 for (std::size_t i = index; i < auto_pilot.state.size(); i++) {
456 auto_pilot.state[i] = {};
457 }
458 }
459
460 for (std::size_t i = 0; i < static_cast<std::size_t>(current_touch_state.entry_count); i++) {
461 auto& state = current_touch_state.states[i];
462 state.position.x = static_cast<u32>((magnification.y * static_cast<f32>(state.position.x)) +
463 (offset.x * static_cast<f32>(TouchSensorWidth)));
464 state.position.y = static_cast<u32>((magnification.y * static_cast<f32>(state.position.y)) +
465 (offset.x * static_cast<f32>(TouchSensorHeight)));
466 state.diameter_x = static_cast<u32>(magnification.x * static_cast<f32>(state.diameter_x));
467 state.diameter_y = static_cast<u32>(magnification.y * static_cast<f32>(state.diameter_y));
468 }
469
470 std::size_t index = 0;
471 for (std::size_t i = 0; i < static_cast<std::size_t>(current_touch_state.entry_count); i++) {
472 const auto& old_state = current_touch_state.states[i];
473 auto& state = current_touch_state.states[index];
474 if ((TouchSensorWidth <= old_state.position.x) ||
475 (TouchSensorHeight <= old_state.position.y)) {
476 continue;
477 }
478 state = old_state;
479 index++;
480 }
481 current_touch_state.entry_count = static_cast<s32>(index);
482
483 SanitizeInput(current_touch_state);
484
485 std::scoped_lock lock{*input_mutex};
486 if (current_touch_state.entry_count == previous_touch_state.entry_count) {
487 if (current_touch_state.entry_count < 1) {
488 return;
489 }
490 bool has_moved = false;
491 for (std::size_t i = 0; i < static_cast<std::size_t>(current_touch_state.entry_count);
492 i++) {
493 s32 delta_x = std::abs(static_cast<s32>(current_touch_state.states[i].position.x) -
494 static_cast<s32>(previous_touch_state.states[i].position.x));
495 s32 delta_y = std::abs(static_cast<s32>(current_touch_state.states[i].position.y) -
496 static_cast<s32>(previous_touch_state.states[i].position.y));
497 if (delta_x > 1 || delta_y > 1) {
498 has_moved = true;
499 }
500 }
501 if (!has_moved) {
502 return;
503 }
504 }
505
506 input_event->Signal();
507}
508
509void TouchResource::OnTouchUpdate(s64 timestamp) {
510 if (global_ref_counter == 0) {
511 return;
512 }
513
514 ReadTouchInput();
515 gesture_handler.SetTouchState(current_touch_state.states, current_touch_state.entry_count,
516 timestamp);
517
518 std::scoped_lock lock{*shared_mutex};
519
520 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
521 const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index);
522 TouchAruidData& data = aruid_data[aruid_index];
523
524 if (applet_data == nullptr || !applet_data->flag.is_assigned) {
525 data = {};
526 continue;
527 }
528
529 if (data.aruid != applet_data->aruid) {
530 data = {};
531 data.aruid = applet_data->aruid;
532 }
533
534 if (gesture_ref_counter != 0) {
535 if (!applet_data->flag.enable_touchscreen) {
536 gesture_state = {};
537 }
538 if (gesture_handler.NeedsUpdate()) {
539 gesture_handler.UpdateGestureState(gesture_state, timestamp);
540 auto& gesture_shared = applet_data->shared_memory_format->gesture;
541 gesture_shared.gesture_lifo.WriteNextEntry(gesture_state);
542 }
543 }
544
545 if (touch_ref_counter != 0) {
546 auto touch_mode = data.finger_map.touch_mode;
547 if (touch_mode == Core::HID::TouchScreenModeForNx::UseSystemSetting) {
548 touch_mode = default_touch_screen_mode;
549 }
550
551 if (applet_resource->GetActiveAruid() == applet_data->aruid &&
552 touch_mode != Core::HID::TouchScreenModeForNx::UseSystemSetting && is_initalized &&
553 handheld_config->is_handheld_hid_enabled && touch_driver->IsRunning()) {
554 touch_driver->SetTouchMode(touch_mode);
555 }
556
557 auto& touch_shared = applet_data->shared_memory_format->touch_screen;
558 StorePreviousTouchState(previous_touch_state, data.finger_map, current_touch_state,
559 applet_data->flag.enable_touchscreen.As<bool>());
560 touch_shared.touch_screen_lifo.WriteNextEntry(current_touch_state);
561 }
562 }
563}
564
565void TouchResource::SanitizeInput(TouchScreenState& state) const {
566 for (std::size_t i = 0; i < static_cast<std::size_t>(state.entry_count); i++) {
567 auto& entry = state.states[i];
568 entry.position.x =
569 std::clamp(entry.position.x, TouchBorders, TouchSensorWidth - TouchBorders - 1);
570 entry.position.y =
571 std::clamp(entry.position.y, TouchBorders, TouchSensorHeight - TouchBorders - 1);
572 entry.diameter_x = std::clamp(entry.diameter_x, 0u, TouchSensorWidth - MaxTouchDiameter);
573 entry.diameter_y = std::clamp(entry.diameter_y, 0u, TouchSensorHeight - MaxTouchDiameter);
574 entry.rotation_angle =
575 std::clamp(entry.rotation_angle, -MaxRotationAngle, MaxRotationAngle);
576 }
577}
578
579} // namespace Service::HID
diff --git a/src/hid_core/resources/touch_screen/touch_screen_resource.h b/src/hid_core/resources/touch_screen/touch_screen_resource.h
new file mode 100644
index 000000000..095cddd76
--- /dev/null
+++ b/src/hid_core/resources/touch_screen/touch_screen_resource.h
@@ -0,0 +1,126 @@
1// SPDX-FileCopyrightText: Copyright 2024 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/common_types.h"
10#include "common/point.h"
11#include "core/hle/result.h"
12#include "hid_core/hid_types.h"
13#include "hid_core/resources/touch_screen/gesture_handler.h"
14#include "hid_core/resources/touch_screen/touch_types.h"
15
16namespace Core {
17class System;
18}
19
20namespace Core::Timing {
21struct EventType;
22}
23
24namespace Kernel {
25class KEvent;
26} // namespace Kernel
27
28namespace Service::Set {
29class ISystemSettingsServer;
30}
31
32namespace Service::HID {
33class AppletResource;
34class TouchSharedMemoryManager;
35class TouchDriver;
36struct HandheldConfig;
37
38class TouchResource {
39public:
40 TouchResource(Core::System& system_);
41 ~TouchResource();
42
43 Result ActivateTouch();
44 Result ActivateTouch(u64 aruid);
45
46 Result ActivateGesture();
47 Result ActivateGesture(u64 aruid, u32 basic_gesture_id);
48
49 Result DeactivateTouch();
50 Result DeactivateGesture();
51
52 bool IsTouchActive() const;
53 bool IsGestureActive() const;
54
55 void SetTouchDriver(std::shared_ptr<TouchDriver> driver);
56 void SetAppletResource(std::shared_ptr<AppletResource> shared, std::recursive_mutex* mutex);
57 void SetInputEvent(Kernel::KEvent* event, std::mutex* mutex);
58 void SetHandheldConfig(std::shared_ptr<HandheldConfig> config);
59 void SetTimerEvent(std::shared_ptr<Core::Timing::EventType> event);
60
61 Result SetTouchScreenAutoPilotState(const AutoPilotState& auto_pilot_state);
62 Result UnsetTouchScreenAutoPilotState();
63
64 Result RequestNextTouchInput();
65 Result RequestNextDummyInput();
66
67 Result ProcessTouchScreenAutoTune();
68 void SetTouchScreenMagnification(f32 point1_x, f32 point1_y, f32 point2_x, f32 point2_y);
69 Result SetTouchScreenResolution(u32 width, u32 height, u64 aruid);
70
71 Result SetTouchScreenConfiguration(
72 const Core::HID::TouchScreenConfigurationForNx& touch_configuration, u64 aruid);
73 Result GetTouchScreenConfiguration(
74 Core::HID::TouchScreenConfigurationForNx& out_touch_configuration, u64 aruid) const;
75
76 Result SetTouchScreenDefaultConfiguration(
77 const Core::HID::TouchScreenConfigurationForNx& touch_configuration);
78 Result GetTouchScreenDefaultConfiguration(
79 Core::HID::TouchScreenConfigurationForNx& out_touch_configuration) const;
80
81 void OnTouchUpdate(s64 timestamp);
82
83private:
84 Result Finalize();
85
86 void StorePreviousTouchState(TouchScreenState& out_previous_touch,
87 TouchFingerMap& out_finger_map,
88 const TouchScreenState& current_touch,
89 bool is_touch_enabled) const;
90 void ReadTouchInput();
91
92 void SanitizeInput(TouchScreenState& state) const;
93
94 s32 global_ref_counter{};
95 s32 gesture_ref_counter{};
96 s32 touch_ref_counter{};
97 bool is_initalized{};
98 u64 sample_number{};
99
100 // External resources
101 std::shared_ptr<Core::Timing::EventType> timer_event{nullptr};
102 std::shared_ptr<TouchDriver> touch_driver{nullptr};
103 std::shared_ptr<AppletResource> applet_resource{nullptr};
104 std::recursive_mutex* shared_mutex{nullptr};
105 std::shared_ptr<HandheldConfig> handheld_config{nullptr};
106 Kernel::KEvent* input_event{nullptr};
107 std::mutex* input_mutex{nullptr};
108
109 // Internal state
110 TouchScreenState current_touch_state{};
111 TouchScreenState previous_touch_state{};
112 GestureState gesture_state{};
113 bool is_auto_pilot_initialized{};
114 AutoPilotState auto_pilot{};
115 GestureHandler gesture_handler{};
116 std::array<TouchAruidData, 0x20> aruid_data{};
117 Common::Point<f32> magnification{1.0f, 1.0f};
118 Common::Point<f32> offset{0.0f, 0.0f};
119 Core::HID::TouchScreenModeForNx default_touch_screen_mode{
120 Core::HID::TouchScreenModeForNx::Finger};
121
122 Core::System& system;
123 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
124};
125
126} // namespace Service::HID
diff --git a/src/hid_core/resources/touch_screen/touch_types.h b/src/hid_core/resources/touch_screen/touch_types.h
index 97ee847da..362088939 100644
--- a/src/hid_core/resources/touch_screen/touch_types.h
+++ b/src/hid_core/resources/touch_screen/touch_types.h
@@ -13,8 +13,20 @@
13#include "hid_core/hid_types.h" 13#include "hid_core/hid_types.h"
14 14
15namespace Service::HID { 15namespace Service::HID {
16static constexpr std::size_t MAX_FINGERS = 16; 16constexpr std::size_t MaxFingers = 16;
17static constexpr size_t MAX_POINTS = 4; 17constexpr std::size_t MaxPoints = 4;
18constexpr u32 TouchSensorWidth = 1280;
19constexpr u32 TouchSensorHeight = 720;
20constexpr s32 MaxRotationAngle = 270;
21constexpr u32 MaxTouchDiameter = 30;
22constexpr u32 TouchBorders = 15;
23
24// HW is around 700, value is set to 400 to make it easier to trigger with mouse
25constexpr f32 SwipeThreshold = 400.0f; // Threshold in pixels/s
26constexpr f32 AngleThreshold = 0.015f; // Threshold in radians
27constexpr f32 PinchThreshold = 0.5f; // Threshold in pixels
28constexpr f32 PressDelay = 0.5f; // Time in seconds
29constexpr f32 DoubleTapDelay = 0.35f; // Time in seconds
18 30
19// This is nn::hid::GestureType 31// This is nn::hid::GestureType
20enum class GestureType : u32 { 32enum class GestureType : u32 {
@@ -28,6 +40,7 @@ enum class GestureType : u32 {
28 Swipe, // Fast press movement and release of a single point 40 Swipe, // Fast press movement and release of a single point
29 Pinch, // All points moving away/closer to the midpoint 41 Pinch, // All points moving away/closer to the midpoint
30 Rotate, // All points rotating from the midpoint 42 Rotate, // All points rotating from the midpoint
43 GestureTypeMax = Rotate,
31}; 44};
32 45
33// This is nn::hid::GestureDirection 46// This is nn::hid::GestureDirection
@@ -69,7 +82,7 @@ struct GestureState {
69static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); 82static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
70 83
71struct GestureProperties { 84struct GestureProperties {
72 std::array<Common::Point<s32>, MAX_POINTS> points{}; 85 std::array<Common::Point<s32>, MaxPoints> points{};
73 std::size_t active_points{}; 86 std::size_t active_points{};
74 Common::Point<s32> mid_point{}; 87 Common::Point<s32> mid_point{};
75 s64 detection_count{}; 88 s64 detection_count{};
@@ -78,13 +91,53 @@ struct GestureProperties {
78 f32 angle{}; 91 f32 angle{};
79}; 92};
80 93
94// This is nn::hid::TouchState
95struct TouchState {
96 u64 delta_time{};
97 Core::HID::TouchAttribute attribute{};
98 u32 finger{};
99 Common::Point<u32> position{};
100 u32 diameter_x{};
101 u32 diameter_y{};
102 s32 rotation_angle{};
103};
104static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
105
81// This is nn::hid::TouchScreenState 106// This is nn::hid::TouchScreenState
82struct TouchScreenState { 107struct TouchScreenState {
83 s64 sampling_number{}; 108 s64 sampling_number{};
84 s32 entry_count{}; 109 s32 entry_count{};
85 INSERT_PADDING_BYTES(4); // Reserved 110 INSERT_PADDING_BYTES(4); // Reserved
86 std::array<Core::HID::TouchState, MAX_FINGERS> states{}; 111 std::array<TouchState, MaxFingers> states{};
87}; 112};
88static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); 113static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
89 114
115struct TouchFingerMap {
116 s32 finger_count{};
117 Core::HID::TouchScreenModeForNx touch_mode;
118 INSERT_PADDING_BYTES(3);
119 std::array<u32, MaxFingers> finger_ids{};
120};
121static_assert(sizeof(TouchFingerMap) == 0x48, "TouchFingerMap is an invalid size");
122
123struct TouchAruidData {
124 u64 aruid;
125 u32 basic_gesture_id;
126 u64 used_1;
127 u64 used_2;
128 u64 used_3;
129 u64 used_4;
130 GestureType gesture_type;
131 u16 resolution_width;
132 u16 resolution_height;
133 TouchFingerMap finger_map;
134};
135static_assert(sizeof(TouchAruidData) == 0x80, "TouchAruidData is an invalid size");
136
137struct AutoPilotState {
138 u64 count;
139 std::array<TouchState, 16> state;
140};
141static_assert(sizeof(AutoPilotState) == 0x288, "AutoPilotState is an invalid size");
142
90} // namespace Service::HID 143} // namespace Service::HID