From e21f96ffde30d66337bd119c04a13f1025be159c Mon Sep 17 00:00:00 2001
From: FrozenAra <macjordan02@googlemail.com>
Date: Mon, 27 Nov 2023 19:26:06 +0100
Subject: [PATCH] Fixed controller applet crashing when on FW17+

---
 .../hle/service/hid/controllers/touchscreen.cpp  | 12 +++++++++---
 .../hle/service/hid/controllers/touchscreen.h    |  4 ++++
 src/core/hle/service/hid/hid_server.cpp          | 16 ++++++++++++++++
 src/core/hle/service/hid/hid_server.h            |  1 +
 4 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index 3bcf0ee9f2..fcd9734143 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -16,7 +16,8 @@ namespace Service::HID {
 constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
 
 TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
-    : ControllerBase{hid_core_} {
+    : ControllerBase{hid_core_}, touchscreen_width(Layout::ScreenUndocked::Width),
+      touchscreen_height(Layout::ScreenUndocked::Height) {
     static_assert(SHARED_MEMORY_OFFSET + sizeof(TouchSharedMemory) < shared_memory_size,
                   "TouchSharedMemory is bigger than the shared memory");
     shared_memory = std::construct_at(
@@ -95,8 +96,8 @@ void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
         if (id < active_fingers_count) {
             const auto& [active_x, active_y] = active_fingers[id].position;
             touch_entry.position = {
-                .x = static_cast<u16>(active_x * Layout::ScreenUndocked::Width),
-                .y = static_cast<u16>(active_y * Layout::ScreenUndocked::Height),
+                .x = static_cast<u16>(active_x * static_cast<float>(touchscreen_width)),
+                .y = static_cast<u16>(active_y * static_cast<float>(touchscreen_height)),
             };
             touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
             touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
@@ -120,4 +121,9 @@ void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
     shared_memory->touch_screen_lifo.WriteNextEntry(next_state);
 }
 
+void TouchScreen::SetTouchscreenDimensions(u32 width, u32 height) {
+    touchscreen_width = width;
+    touchscreen_height = height;
+}
+
 } // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index cd342ce914..79f026a81d 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -28,6 +28,8 @@ public:
     // When the controller is requesting an update for the shared memory
     void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
 
+    void SetTouchscreenDimensions(u32 width, u32 height);
+
 private:
     static constexpr std::size_t MAX_FINGERS = 16;
 
@@ -53,5 +55,7 @@ private:
     Core::HID::EmulatedConsole* console = nullptr;
 
     std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{};
+    u32 touchscreen_width;
+    u32 touchscreen_height;
 };
 } // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp
index 583142e350..a7d1578d92 100644
--- a/src/core/hle/service/hid/hid_server.cpp
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -208,6 +208,7 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r
         {1001, &IHidServer::GetNpadCommunicationMode, "GetNpadCommunicationMode"},
         {1002, &IHidServer::SetTouchScreenConfiguration, "SetTouchScreenConfiguration"},
         {1003, &IHidServer::IsFirmwareUpdateNeededForNotification, "IsFirmwareUpdateNeededForNotification"},
+        {1004, &IHidServer::SetTouchScreenResolution, "SetTouchScreenResolution"},
         {2000, nullptr, "ActivateDigitizer"},
     };
     // clang-format on
@@ -2363,6 +2364,21 @@ void IHidServer::IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx) {
     rb.Push(false);
 }
 
+void IHidServer::SetTouchScreenResolution(HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto width{rp.Pop<u32>()};
+    const auto height{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    GetResourceManager()->GetTouchScreen()->SetTouchscreenDimensions(width, height);
+
+    LOG_INFO(Service_HID, "called, width={}, height={}, applet_resource_user_id={}", width, height,
+             applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(ResultSuccess);
+}
+
 std::shared_ptr<ResourceManager> IHidServer::GetResourceManager() {
     resource_manager->Initialize();
     return resource_manager;
diff --git a/src/core/hle/service/hid/hid_server.h b/src/core/hle/service/hid/hid_server.h
index eb2e8e7f4c..cc7c4ebdd1 100644
--- a/src/core/hle/service/hid/hid_server.h
+++ b/src/core/hle/service/hid/hid_server.h
@@ -141,6 +141,7 @@ private:
     void GetNpadCommunicationMode(HLERequestContext& ctx);
     void SetTouchScreenConfiguration(HLERequestContext& ctx);
     void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
+    void SetTouchScreenResolution(HLERequestContext& ctx);
 
     std::shared_ptr<ResourceManager> resource_manager;
     std::shared_ptr<HidFirmwareSettings> firmware_settings;