diff options
30 files changed, 1882 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 {  void LoopProcess(Core::System& system) {      auto server_manager = std::make_unique<ServerManager>(system); -    std::shared_ptr<ResourceManager> resource_manager = std::make_shared<ResourceManager>(system);      std::shared_ptr<HidFirmwareSettings> firmware_settings =          std::make_shared<HidFirmwareSettings>(system); +    std::shared_ptr<ResourceManager> resource_manager = +        std::make_shared<ResourceManager>(system, firmware_settings);      // TODO: Remove this hack when am is emulated properly.      resource_manager->Initialize(); @@ -31,7 +32,7 @@ void LoopProcess(Core::System& system) {      server_manager->RegisterNamedService(          "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings));      server_manager->RegisterNamedService( -        "hid:dbg", std::make_shared<IHidDebugServer>(system, resource_manager)); +        "hid:dbg", std::make_shared<IHidDebugServer>(system, resource_manager, firmware_settings));      server_manager->RegisterNamedService(          "hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager, firmware_settings)); 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 @@  // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project  // SPDX-License-Identifier: GPL-3.0-or-later +#include <algorithm> +  #include "core/hle/service/hid/hid_debug_server.h"  #include "core/hle/service/ipc_helpers.h" +#include "hid_core/hid_types.h"  #include "hid_core/resource_manager.h" +#include "hid_core/resources/hid_firmware_settings.h" + +#include "hid_core/resources/touch_screen/gesture.h" +#include "hid_core/resources/touch_screen/touch_screen.h" +#include "hid_core/resources/touch_screen/touch_types.h"  namespace Service::HID { -IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource) -    : ServiceFramework{system_, "hid:dbg"}, resource_manager{resource} { +IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource, +                                 std::shared_ptr<HidFirmwareSettings> settings) +    : ServiceFramework{system_, "hid:dbg"}, resource_manager{resource}, firmware_settings{ +                                                                            settings} {      // clang-format off      static const FunctionInfo functions[] = {          {0, nullptr, "DeactivateDebugPad"},          {1, nullptr, "SetDebugPadAutoPilotState"},          {2, nullptr, "UnsetDebugPadAutoPilotState"}, -        {10, nullptr, "DeactivateTouchScreen"}, -        {11, nullptr, "SetTouchScreenAutoPilotState"}, -        {12, nullptr, "UnsetTouchScreenAutoPilotState"}, -        {13, nullptr, "GetTouchScreenConfiguration"}, -        {14, nullptr, "ProcessTouchScreenAutoTune"}, -        {15, nullptr, "ForceStopTouchScreenManagement"}, -        {16, nullptr, "ForceRestartTouchScreenManagement"}, -        {17, nullptr, "IsTouchScreenManaged"}, +        {10, &IHidDebugServer::DeactivateTouchScreen, "DeactivateTouchScreen"}, +        {11, &IHidDebugServer::SetTouchScreenAutoPilotState, "SetTouchScreenAutoPilotState"}, +        {12, &IHidDebugServer::UnsetTouchScreenAutoPilotState, "UnsetTouchScreenAutoPilotState"}, +        {13, &IHidDebugServer::GetTouchScreenConfiguration, "GetTouchScreenConfiguration"}, +        {14, &IHidDebugServer::ProcessTouchScreenAutoTune, "ProcessTouchScreenAutoTune"}, +        {15, &IHidDebugServer::ForceStopTouchScreenManagement, "ForceStopTouchScreenManagement"}, +        {16, &IHidDebugServer::ForceRestartTouchScreenManagement, "ForceRestartTouchScreenManagement"}, +        {17, &IHidDebugServer::IsTouchScreenManaged, "IsTouchScreenManaged"},          {20, nullptr, "DeactivateMouse"},          {21, nullptr, "SetMouseAutoPilotState"},          {22, nullptr, "UnsetMouseAutoPilotState"}, @@ -37,7 +47,7 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource          {60, nullptr, "ClearNpadSystemCommonPolicy"},          {61, nullptr, "DeactivateNpad"},          {62, nullptr, "ForceDisconnectNpad"}, -        {91, nullptr, "DeactivateGesture"}, +        {91, &IHidDebugServer::DeactivateGesture, "DeactivateGesture"},          {110, nullptr, "DeactivateHomeButton"},          {111, nullptr, "SetHomeButtonAutoPilotState"},          {112, nullptr, "UnsetHomeButtonAutoPilotState"}, @@ -150,6 +160,170 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource  }  IHidDebugServer::~IHidDebugServer() = default; +void IHidDebugServer::DeactivateTouchScreen(HLERequestContext& ctx) { +    LOG_INFO(Service_HID, "called"); + +    Result result = ResultSuccess; + +    if (!firmware_settings->IsDeviceManaged()) { +        result = GetResourceManager()->GetTouchScreen()->Deactivate(); +    } + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(result); +} + +void IHidDebugServer::SetTouchScreenAutoPilotState(HLERequestContext& ctx) { +    AutoPilotState auto_pilot{}; +    auto_pilot.count = ctx.GetReadBufferNumElements<TouchState>(); +    const auto buffer = ctx.ReadBuffer(); + +    auto_pilot.count = std::min(auto_pilot.count, static_cast<u64>(auto_pilot.state.size())); +    memcpy(auto_pilot.state.data(), buffer.data(), auto_pilot.count * sizeof(TouchState)); + +    LOG_INFO(Service_HID, "called, auto_pilot_count={}", auto_pilot.count); + +    const Result result = +        GetResourceManager()->GetTouchScreen()->SetTouchScreenAutoPilotState(auto_pilot); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(result); +} + +void IHidDebugServer::UnsetTouchScreenAutoPilotState(HLERequestContext& ctx) { +    LOG_INFO(Service_HID, "called"); + +    const Result result = GetResourceManager()->GetTouchScreen()->UnsetTouchScreenAutoPilotState(); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(result); +} + +void IHidDebugServer::GetTouchScreenConfiguration(HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto applet_resource_user_id{rp.Pop<u64>()}; + +    LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + +    Core::HID::TouchScreenConfigurationForNx touchscreen_config{}; +    const Result result = GetResourceManager()->GetTouchScreen()->GetTouchScreenConfiguration( +        touchscreen_config, applet_resource_user_id); + +    if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 && +        touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) { +        touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting; +    } + +    IPC::ResponseBuilder rb{ctx, 6}; +    rb.Push(result); +    rb.PushRaw(touchscreen_config); +} + +void IHidDebugServer::ProcessTouchScreenAutoTune(HLERequestContext& ctx) { +    LOG_INFO(Service_HID, "called"); + +    Result result = GetResourceManager()->GetTouchScreen()->ProcessTouchScreenAutoTune(); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(result); +} + +void IHidDebugServer::ForceStopTouchScreenManagement(HLERequestContext& ctx) { +    LOG_INFO(Service_HID, "called"); + +    if (!firmware_settings->IsDeviceManaged()) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(ResultSuccess); +        return; +    } + +    Result result = ResultSuccess; +    bool is_touch_active{}; +    bool is_gesture_active{}; +    auto touch_screen = GetResourceManager()->GetTouchScreen(); +    auto gesture = GetResourceManager()->GetGesture(); + +    if (firmware_settings->IsTouchI2cManaged()) { +        result = touch_screen->IsActive(is_touch_active); +        if (result.IsSuccess()) { +            result = gesture->IsActive(is_gesture_active); +        } +        if (result.IsSuccess() && is_touch_active) { +            result = touch_screen->Deactivate(); +        } +        if (result.IsSuccess() && is_gesture_active) { +            result = gesture->Deactivate(); +        } +    } + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(result); +} + +void IHidDebugServer::ForceRestartTouchScreenManagement(HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    struct Parameters { +        u32 basic_gesture_id; +        INSERT_PADDING_WORDS_NOINIT(1); +        u64 applet_resource_user_id; +    }; +    static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); + +    const auto parameters{rp.PopRaw<Parameters>()}; + +    LOG_INFO(Service_HID, "called, basic_gesture_id={}, applet_resource_user_id={}", +             parameters.basic_gesture_id, parameters.applet_resource_user_id); + +    Result result = ResultSuccess; +    auto touch_screen = GetResourceManager()->GetTouchScreen(); +    auto gesture = GetResourceManager()->GetGesture(); + +    if (firmware_settings->IsDeviceManaged() && firmware_settings->IsTouchI2cManaged()) { +        result = gesture->Activate(); +        if (result.IsSuccess()) { +            result = +                gesture->Activate(parameters.applet_resource_user_id, parameters.basic_gesture_id); +        } +        if (result.IsSuccess()) { +            result = touch_screen->Activate(); +        } +        if (result.IsSuccess()) { +            result = touch_screen->Activate(parameters.applet_resource_user_id); +        } +    } + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(result); +} + +void IHidDebugServer::IsTouchScreenManaged(HLERequestContext& ctx) { +    LOG_INFO(Service_HID, "called"); + +    bool is_touch_active{}; +    bool is_gesture_active{}; + +    Result result = GetResourceManager()->GetTouchScreen()->IsActive(is_touch_active); +    if (result.IsSuccess()) { +        result = GetResourceManager()->GetGesture()->IsActive(is_gesture_active); +    } + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(result); +    rb.Push(is_touch_active | is_gesture_active); +} + +void IHidDebugServer::DeactivateGesture(HLERequestContext& ctx) { +    LOG_INFO(Service_HID, "called"); + +    Result result = ResultSuccess; + +    if (!firmware_settings->IsDeviceManaged()) { +        result = GetResourceManager()->GetGesture()->Deactivate(); +    } + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(result); +}  std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() {      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;  namespace Service::HID {  class ResourceManager; +class HidFirmwareSettings;  class IHidDebugServer final : public ServiceFramework<IHidDebugServer> {  public: -    explicit IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource); +    explicit IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource, +                             std::shared_ptr<HidFirmwareSettings> settings);      ~IHidDebugServer() override;  private: +    void DeactivateTouchScreen(HLERequestContext& ctx); +    void SetTouchScreenAutoPilotState(HLERequestContext& ctx); +    void UnsetTouchScreenAutoPilotState(HLERequestContext& ctx); +    void GetTouchScreenConfiguration(HLERequestContext& ctx); +    void ProcessTouchScreenAutoTune(HLERequestContext& ctx); +    void ForceStopTouchScreenManagement(HLERequestContext& ctx); +    void ForceRestartTouchScreenManagement(HLERequestContext& ctx); +    void IsTouchScreenManaged(HLERequestContext& ctx); +    void DeactivateGesture(HLERequestContext& ctx); +      std::shared_ptr<ResourceManager> GetResourceManager();      std::shared_ptr<ResourceManager> resource_manager; +    std::shared_ptr<HidFirmwareSettings> firmware_settings;  };  } // namespace Service::HID diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp index 09c47b5e3..9ffe027ff 100644 --- a/src/core/hle/service/hid/hid_server.cpp +++ b/src/core/hle/service/hid/hid_server.cpp @@ -989,8 +989,7 @@ void IHidServer::ActivateGesture(HLERequestContext& ctx) {      }      if (result.IsSuccess()) { -        // TODO: Use gesture id here -        result = gesture->Activate(parameters.applet_resource_user_id); +        result = gesture->Activate(parameters.applet_resource_user_id, parameters.basic_gesture_id);      }      IPC::ResponseBuilder rb{ctx, 2}; @@ -2449,14 +2448,22 @@ void IHidServer::GetNpadCommunicationMode(HLERequestContext& ctx) {  void IHidServer::SetTouchScreenConfiguration(HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    const auto touchscreen_mode{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()}; +    auto touchscreen_config{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()};      const auto applet_resource_user_id{rp.Pop<u64>()}; -    LOG_WARNING(Service_HID, "(STUBBED) called, touchscreen_mode={}, applet_resource_user_id={}", -                touchscreen_mode.mode, applet_resource_user_id); +    LOG_INFO(Service_HID, "called, touchscreen_config={}, applet_resource_user_id={}", +             touchscreen_config.mode, applet_resource_user_id); + +    if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 && +        touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) { +        touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting; +    } + +    const Result result = GetResourceManager()->GetTouchScreen()->SetTouchScreenConfiguration( +        touchscreen_config, applet_resource_user_id);      IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(ResultSuccess); +    rb.Push(result);  }  void IHidServer::IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx) { @@ -2484,11 +2491,12 @@ void IHidServer::SetTouchScreenResolution(HLERequestContext& ctx) {      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); +    GetResourceManager()->GetTouchScreen()->SetTouchScreenResolution(width, height, +                                                                     applet_resource_user_id); +      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(ResultSuccess);  } 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          {1133, nullptr, "StartUsbFirmwareUpdate"},          {1134, nullptr, "GetUsbFirmwareUpdateState"},          {1135, &IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory, "InitializeUsbFirmwareUpdateWithoutMemory"}, -        {1150, nullptr, "SetTouchScreenMagnification"}, -        {1151, nullptr, "GetTouchScreenFirmwareVersion"}, -        {1152, nullptr, "SetTouchScreenDefaultConfiguration"}, +        {1150, &IHidSystemServer::SetTouchScreenMagnification, "SetTouchScreenMagnification"}, +        {1151, &IHidSystemServer::GetTouchScreenFirmwareVersion, "GetTouchScreenFirmwareVersion"}, +        {1152, &IHidSystemServer::SetTouchScreenDefaultConfiguration, "SetTouchScreenDefaultConfiguration"},          {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},          {1154, nullptr, "IsFirmwareAvailableForNotification"},          {1155, &IHidSystemServer::SetForceHandheldStyleVibration, "SetForceHandheldStyleVibration"}, @@ -845,12 +845,60 @@ void IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContex      rb.Push(ResultSuccess);  } +void IHidSystemServer::SetTouchScreenMagnification(HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto point1x{rp.Pop<f32>()}; +    const auto point1y{rp.Pop<f32>()}; +    const auto point2x{rp.Pop<f32>()}; +    const auto point2y{rp.Pop<f32>()}; + +    LOG_INFO(Service_HID, "called, point1=-({},{}), point2=({},{})", point1x, point1y, point2x, +             point2y); + +    const Result result = GetResourceManager()->GetTouchScreen()->SetTouchScreenMagnification( +        point1x, point1y, point2x, point2y); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(result); +} + +void IHidSystemServer::GetTouchScreenFirmwareVersion(HLERequestContext& ctx) { +    LOG_INFO(Service_HID, "called"); + +    Core::HID::FirmwareVersion firmware{}; +    const auto result = GetResourceManager()->GetTouchScreenFirmwareVersion(firmware); + +    IPC::ResponseBuilder rb{ctx, 6}; +    rb.Push(result); +    rb.PushRaw(firmware); +} + +void IHidSystemServer::SetTouchScreenDefaultConfiguration(HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    auto touchscreen_config{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()}; + +    LOG_INFO(Service_HID, "called, touchscreen_config={}", touchscreen_config.mode); + +    if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 && +        touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) { +        touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting; +    } + +    const Result result = +        GetResourceManager()->GetTouchScreen()->SetTouchScreenDefaultConfiguration( +            touchscreen_config); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(result); +} +  void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx) { -    LOG_WARNING(Service_HID, "(STUBBED) called"); +    LOG_INFO(Service_HID, "called"); -    Core::HID::TouchScreenConfigurationForNx touchscreen_config{ -        .mode = Core::HID::TouchScreenModeForNx::Finger, -    }; +    Core::HID::TouchScreenConfigurationForNx touchscreen_config{}; +    const Result result = +        GetResourceManager()->GetTouchScreen()->GetTouchScreenDefaultConfiguration( +            touchscreen_config);      if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&          touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) { @@ -858,7 +906,7 @@ void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx      }      IPC::ResponseBuilder rb{ctx, 6}; -    rb.Push(ResultSuccess); +    rb.Push(result);      rb.PushRaw(touchscreen_config);  } 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:      void FinalizeUsbFirmwareUpdate(HLERequestContext& ctx);      void CheckUsbFirmwareUpdateRequired(HLERequestContext& ctx);      void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx); +    void SetTouchScreenMagnification(HLERequestContext& ctx); +    void GetTouchScreenFirmwareVersion(HLERequestContext& ctx); +    void SetTouchScreenDefaultConfiguration(HLERequestContext& ctx);      void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);      void SetForceHandheldStyleVibration(HLERequestContext& ctx);      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 @@  #include "common/vector_math.h"  #include "core/hle/service/set/setting_formats/private_settings.h"  #include "core/hle/service/set/settings_types.h" +#include "hid_core/resources/touch_screen/touch_types.h"  namespace Service::Set { @@ -257,8 +258,7 @@ struct SystemSettings {      std::array<u8, 0x10> analog_stick_user_calibration_left;      std::array<u8, 0x10> analog_stick_user_calibration_right; -    // nn::settings::system::TouchScreenMode -    s32 touch_screen_mode; +    TouchScreenMode touch_screen_mode;      INSERT_PADDING_BYTES(0x14); // Reserved      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 100cb2db4..c889aec47 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_)          {184, nullptr, "SetPlatformRegion"},          {185, &ISystemSettingsServer::GetHomeMenuSchemeModel, "GetHomeMenuSchemeModel"},          {186, nullptr, "GetMemoryUsageRateFlag"}, -        {187, nullptr, "GetTouchScreenMode"}, -        {188, nullptr, "SetTouchScreenMode"}, +        {187, &ISystemSettingsServer::GetTouchScreenMode, "GetTouchScreenMode"}, +        {188, &ISystemSettingsServer::SetTouchScreenMode, "SetTouchScreenMode"},          {189, nullptr, "GetButtonConfigSettingsFull"},          {190, nullptr, "SetButtonConfigSettingsFull"},          {191, nullptr, "GetButtonConfigSettingsEmbedded"}, @@ -1395,6 +1395,28 @@ void ISystemSettingsServer::GetHomeMenuSchemeModel(HLERequestContext& ctx) {      rb.Push(0);  } +void ISystemSettingsServer::GetTouchScreenMode(HLERequestContext& ctx) { +    TouchScreenMode touch_screen_mode{}; +    auto res = GetTouchScreenMode(touch_screen_mode); + +    LOG_INFO(Service_SET, "called, touch_screen_mode={}", touch_screen_mode); + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(res); +    rb.PushEnum(touch_screen_mode); +} + +void ISystemSettingsServer::SetTouchScreenMode(HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto touch_screen_mode = rp.PopEnum<TouchScreenMode>(); +    auto res = SetTouchScreenMode(touch_screen_mode); + +    LOG_INFO(Service_SET, "called, touch_screen_mode={}", touch_screen_mode); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(res); +} +  void ISystemSettingsServer::GetFieldTestingFlag(HLERequestContext& ctx) {      LOG_INFO(Service_SET, "called, field_testing_flag={}", m_system_settings.field_testing_flag); @@ -1670,4 +1692,15 @@ Result ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime(      R_SUCCEED();  } +Result ISystemSettingsServer::GetTouchScreenMode(TouchScreenMode& touch_screen_mode) const { +    touch_screen_mode = m_system_settings.touch_screen_mode; +    R_SUCCEED(); +} + +Result ISystemSettingsServer::SetTouchScreenMode(TouchScreenMode touch_screen_mode) { +    m_system_settings.touch_screen_mode = touch_screen_mode; +    SetSaveNeeded(); +    R_SUCCEED(); +} +  } // 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:          Service::PSC::Time::SteadyClockTimePoint& out_time_point) const;      Result SetUserSystemClockAutomaticCorrectionUpdatedTime(          const Service::PSC::Time::SteadyClockTimePoint& time_point); +    Result GetTouchScreenMode(TouchScreenMode& touch_screen_mode) const; +    Result SetTouchScreenMode(TouchScreenMode touch_screen_mode);  private:      void SetLanguageCode(HLERequestContext& ctx); @@ -154,6 +156,8 @@ private:      void GetChineseTraditionalInputMethod(HLERequestContext& ctx);      void GetHomeMenuScheme(HLERequestContext& ctx);      void GetHomeMenuSchemeModel(HLERequestContext& ctx); +    void GetTouchScreenMode(HLERequestContext& ctx); +    void SetTouchScreenMode(HLERequestContext& ctx);      void GetFieldTestingFlag(HLERequestContext& ctx);      void GetPanelCrcMode(HLERequestContext& ctx);      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() {      Settings::values.touchscreen.rotation_angle =          static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_angle"), 0));      Settings::values.touchscreen.diameter_x = -        static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_x"), 15)); +        static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_x"), 90));      Settings::values.touchscreen.diameter_y = -        static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_y"), 15)); +        static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_y"), 90));  }  void Config::ReadAudioValues() { @@ -478,9 +478,9 @@ void Config::SaveTouchscreenValues() {      WriteIntegerSetting(std::string("touchscreen_angle"), touchscreen.rotation_angle,                          std::make_optional(static_cast<u32>(0)));      WriteIntegerSetting(std::string("touchscreen_diameter_x"), touchscreen.diameter_x, -                        std::make_optional(static_cast<u32>(15))); +                        std::make_optional(static_cast<u32>(90)));      WriteIntegerSetting(std::string("touchscreen_diameter_y"), touchscreen.diameter_y, -                        std::make_optional(static_cast<u32>(15))); +                        std::make_optional(static_cast<u32>(90)));  }  void Config::SaveMotionTouchValues() { diff --git a/src/hid_core/CMakeLists.txt b/src/hid_core/CMakeLists.txt index aa85502b5..055954224 100644 --- a/src/hid_core/CMakeLists.txt +++ b/src/hid_core/CMakeLists.txt @@ -98,9 +98,14 @@ add_library(hid_core STATIC      resources/system_buttons/sleep_button.h      resources/touch_screen/gesture.cpp      resources/touch_screen/gesture.h -    resources/touch_screen/gesture_types.h +    resources/touch_screen/gesture_handler.cpp +    resources/touch_screen/gesture_handler.h      resources/touch_screen/touch_screen.cpp      resources/touch_screen/touch_screen.h +    resources/touch_screen/touch_screen_driver.cpp +    resources/touch_screen/touch_screen_driver.h +    resources/touch_screen/touch_screen_resource.cpp +    resources/touch_screen/touch_screen_resource.h      resources/touch_screen/touch_types.h      resources/unique_pad/unique_pad.cpp      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 @@  namespace Service::HID {  constexpr Result PalmaResultSuccess{ErrorModule::HID, 0}; + +constexpr Result ResultTouchNotInitialized{ErrorModule::HID, 41}; +constexpr Result ResultTouchOverflow{ErrorModule::HID, 42}; +  constexpr Result NpadInvalidHandle{ErrorModule::HID, 100};  constexpr Result NpadDeviceIndexOutOfRange{ErrorModule::HID, 107}; @@ -23,6 +27,10 @@ constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423};  constexpr Result ResultNfcIsNotReady{ErrorModule::HID, 461};  constexpr Result ResultNfcXcdHandleIsNotInitialized{ErrorModule::HID, 464};  constexpr Result ResultIrSensorIsNotReady{ErrorModule::HID, 501}; + +constexpr Result ResultGestureOverflow{ErrorModule::HID, 522}; +constexpr Result ResultGestureNotInitialized{ErrorModule::HID, 523}; +  constexpr Result ResultMcuIsNotReady{ErrorModule::HID, 541};  constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601}; diff --git a/src/hid_core/hid_types.h b/src/hid_core/hid_types.h index a01292a70..3cf12f6e5 100644 --- a/src/hid_core/hid_types.h +++ b/src/hid_core/hid_types.h @@ -299,12 +299,6 @@ enum class GyroscopeZeroDriftMode : u32 {      Tight = 2,  }; -// This is nn::settings::system::TouchScreenMode -enum class TouchScreenMode : u32 { -    Stylus = 0, -    Standard = 1, -}; -  // This is nn::hid::TouchScreenModeForNx  enum class TouchScreenModeForNx : u8 {      UseSystemSetting, @@ -354,18 +348,6 @@ struct TouchAttribute {  };  static_assert(sizeof(TouchAttribute) == 0x4, "TouchAttribute is an invalid size"); -// This is nn::hid::TouchState -struct TouchState { -    u64 delta_time{}; -    TouchAttribute attribute{}; -    u32 finger{}; -    Common::Point<u32> position{}; -    u32 diameter_x{}; -    u32 diameter_y{}; -    u32 rotation_angle{}; -}; -static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); -  struct TouchFinger {      u64 last_touch{};      Common::Point<float> position{}; @@ -743,4 +725,14 @@ struct UniquePadId {  };  static_assert(sizeof(UniquePadId) == 0x8, "UniquePadId is an invalid size"); +// This is nn::hid::system::FirmwareVersion +struct FirmwareVersion { +    u8 major; +    u8 minor; +    u8 micro; +    u8 revision; +    std::array<char, 0xc> device_identifier; +}; +static_assert(sizeof(FirmwareVersion) == 0x10, "FirmwareVersion is an invalid size"); +  } // 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 @@  #include "hid_core/resources/applet_resource.h"  #include "hid_core/resources/debug_pad/debug_pad.h"  #include "hid_core/resources/digitizer/digitizer.h" +#include "hid_core/resources/hid_firmware_settings.h"  #include "hid_core/resources/keyboard/keyboard.h"  #include "hid_core/resources/mouse/debug_mouse.h"  #include "hid_core/resources/mouse/mouse.h" @@ -29,6 +30,8 @@  #include "hid_core/resources/system_buttons/sleep_button.h"  #include "hid_core/resources/touch_screen/gesture.h"  #include "hid_core/resources/touch_screen/touch_screen.h" +#include "hid_core/resources/touch_screen/touch_screen_driver.h" +#include "hid_core/resources/touch_screen/touch_screen_resource.h"  #include "hid_core/resources/unique_pad/unique_pad.h"  #include "hid_core/resources/vibration/gc_vibration_device.h"  #include "hid_core/resources/vibration/n64_vibration_device.h" @@ -45,12 +48,16 @@ constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; //  constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)  constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000};         // (5ms, 200Hz) -ResourceManager::ResourceManager(Core::System& system_) -    : system{system_}, service_context{system_, "hid"} { +ResourceManager::ResourceManager(Core::System& system_, +                                 std::shared_ptr<HidFirmwareSettings> settings) +    : firmware_settings{settings}, system{system_}, service_context{system_, "hid"} {      applet_resource = std::make_shared<AppletResource>(system);  } -ResourceManager::~ResourceManager() = default; +ResourceManager::~ResourceManager() { +    system.CoreTiming().UnscheduleEvent(touch_update_event); +    input_event->Finalize(); +};  void ResourceManager::Initialize() {      if (is_initialized) { @@ -59,7 +66,9 @@ void ResourceManager::Initialize() {      system.HIDCore().ReloadInputDevices(); -    handheld_config = std::make_shared<HandheldConfig>(); +    input_event = service_context.CreateEvent("ResourceManager:InputEvent"); + +    InitializeHandheldConfig();      InitializeHidCommonSampler();      InitializeTouchScreenSampler();      InitializeConsoleSixAxisSampler(); @@ -154,6 +163,7 @@ Result ResourceManager::CreateAppletResource(u64 aruid) {      npad->Activate();      six_axis->Activate();      touch_screen->Activate(); +    gesture->Activate();      return GetNpad()->ActivateNpadResource(aruid);  } @@ -163,6 +173,17 @@ Result ResourceManager::CreateAppletResourceImpl(u64 aruid) {      return applet_resource->CreateAppletResource(aruid);  } +void ResourceManager::InitializeHandheldConfig() { +    handheld_config = std::make_shared<HandheldConfig>(); +    handheld_config->is_handheld_hid_enabled = true; +    handheld_config->is_joycon_rail_enabled = true; +    handheld_config->is_force_handheld_style_vibration = false; +    handheld_config->is_force_handheld = false; +    if (firmware_settings->IsHandheldForced()) { +        handheld_config->is_joycon_rail_enabled = false; +    } +} +  void ResourceManager::InitializeHidCommonSampler() {      debug_pad = std::make_shared<DebugPad>(system.HIDCore());      mouse = std::make_shared<Mouse>(system.HIDCore()); @@ -170,7 +191,6 @@ void ResourceManager::InitializeHidCommonSampler() {      keyboard = std::make_shared<Keyboard>(system.HIDCore());      unique_pad = std::make_shared<UniquePad>(system.HIDCore());      npad = std::make_shared<NPad>(system.HIDCore(), service_context); -    gesture = std::make_shared<Gesture>(system.HIDCore());      home_button = std::make_shared<HomeButton>(system.HIDCore());      sleep_button = std::make_shared<SleepButton>(system.HIDCore());      capture_button = std::make_shared<CaptureButton>(system.HIDCore()); @@ -185,7 +205,8 @@ void ResourceManager::InitializeHidCommonSampler() {      const auto settings =          system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); -    npad->SetNpadExternals(applet_resource, &shared_mutex, handheld_config, settings); +    npad->SetNpadExternals(applet_resource, &shared_mutex, handheld_config, input_event, +                           &input_mutex, settings);      six_axis->SetAppletResource(applet_resource, &shared_mutex);      mouse->SetAppletResource(applet_resource, &shared_mutex); @@ -196,11 +217,25 @@ void ResourceManager::InitializeHidCommonSampler() {  }  void ResourceManager::InitializeTouchScreenSampler() { -    gesture = std::make_shared<Gesture>(system.HIDCore()); -    touch_screen = std::make_shared<TouchScreen>(system.HIDCore()); +    // This is nn.hid.TouchScreenSampler +    touch_resource = std::make_shared<TouchResource>(system); +    touch_driver = std::make_shared<TouchDriver>(system.HIDCore()); +    touch_screen = std::make_shared<TouchScreen>(touch_resource); +    gesture = std::make_shared<Gesture>(touch_resource); + +    touch_update_event = Core::Timing::CreateEvent( +        "HID::TouchUpdateCallback", +        [this](s64 time, +               std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { +            touch_resource->OnTouchUpdate(time); +            return std::nullopt; +        }); -    touch_screen->SetAppletResource(applet_resource, &shared_mutex); -    gesture->SetAppletResource(applet_resource, &shared_mutex); +    touch_resource->SetTouchDriver(touch_driver); +    touch_resource->SetAppletResource(applet_resource, &shared_mutex); +    touch_resource->SetInputEvent(input_event, &input_mutex); +    touch_resource->SetHandheldConfig(handheld_config); +    touch_resource->SetTimerEvent(touch_update_event);  }  void ResourceManager::InitializeConsoleSixAxisSampler() { @@ -388,13 +423,15 @@ Result ResourceManager::SendVibrationValue(u64 aruid,      return result;  } +Result ResourceManager::GetTouchScreenFirmwareVersion(Core::HID::FirmwareVersion& firmware) const { +    return ResultSuccess; +} +  void ResourceManager::UpdateControllers(std::chrono::nanoseconds ns_late) {      auto& core_timing = system.CoreTiming();      debug_pad->OnUpdate(core_timing);      digitizer->OnUpdate(core_timing);      unique_pad->OnUpdate(core_timing); -    gesture->OnUpdate(core_timing); -    touch_screen->OnUpdate(core_timing);      palma->OnUpdate(core_timing);      home_button->OnUpdate(core_timing);      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;  }  namespace Core::HID { +struct FirmwareVersion;  struct VibrationDeviceHandle;  struct VibrationValue;  struct VibrationDeviceInfo; @@ -21,8 +22,9 @@ struct EventType;  }  namespace Kernel { +class KEvent;  class KSharedMemory; -} +} // namespace Kernel  namespace Service::HID {  class AppletResource; @@ -33,6 +35,7 @@ class DebugMouse;  class DebugPad;  class Digitizer;  class Gesture; +class HidFirmwareSettings;  class HomeButton;  class Keyboard;  class Mouse; @@ -42,6 +45,8 @@ class SevenSixAxis;  class SixAxis;  class SleepButton;  class TouchScreen; +class TouchDriver; +class TouchResource;  class UniquePad;  class NpadVibrationBase;  class NpadN64VibrationDevice; @@ -52,7 +57,7 @@ struct HandheldConfig;  class ResourceManager {  public: -    explicit ResourceManager(Core::System& system_); +    explicit ResourceManager(Core::System& system_, std::shared_ptr<HidFirmwareSettings> settings);      ~ResourceManager();      void Initialize(); @@ -102,6 +107,8 @@ public:      Result SendVibrationValue(u64 aruid, const Core::HID::VibrationDeviceHandle& handle,                                const Core::HID::VibrationValue& value); +    Result GetTouchScreenFirmwareVersion(Core::HID::FirmwareVersion& firmware) const; +      void UpdateControllers(std::chrono::nanoseconds ns_late);      void UpdateNpad(std::chrono::nanoseconds ns_late);      void UpdateMouseKeyboard(std::chrono::nanoseconds ns_late); @@ -109,6 +116,7 @@ public:  private:      Result CreateAppletResourceImpl(u64 aruid); +    void InitializeHandheldConfig();      void InitializeHidCommonSampler();      void InitializeTouchScreenSampler();      void InitializeConsoleSixAxisSampler(); @@ -117,37 +125,46 @@ private:      bool is_initialized{false};      mutable std::recursive_mutex shared_mutex; -    std::shared_ptr<AppletResource> applet_resource = nullptr; - -    std::shared_ptr<CaptureButton> capture_button = nullptr; -    std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr; -    std::shared_ptr<DebugMouse> debug_mouse = nullptr; -    std::shared_ptr<DebugPad> debug_pad = nullptr; -    std::shared_ptr<Digitizer> digitizer = nullptr; -    std::shared_ptr<Gesture> gesture = nullptr; -    std::shared_ptr<HomeButton> home_button = nullptr; -    std::shared_ptr<Keyboard> keyboard = nullptr; -    std::shared_ptr<Mouse> mouse = nullptr; -    std::shared_ptr<NPad> npad = nullptr; -    std::shared_ptr<Palma> palma = nullptr; -    std::shared_ptr<SevenSixAxis> seven_six_axis = nullptr; -    std::shared_ptr<SixAxis> six_axis = nullptr; -    std::shared_ptr<SleepButton> sleep_button = nullptr; -    std::shared_ptr<TouchScreen> touch_screen = nullptr; -    std::shared_ptr<UniquePad> unique_pad = nullptr; - -    std::shared_ptr<HandheldConfig> handheld_config = nullptr; +    std::shared_ptr<AppletResource> applet_resource{nullptr}; + +    mutable std::mutex input_mutex; +    Kernel::KEvent* input_event{nullptr}; + +    std::shared_ptr<HandheldConfig> handheld_config{nullptr}; +    std::shared_ptr<HidFirmwareSettings> firmware_settings{nullptr}; + +    std::shared_ptr<CaptureButton> capture_button{nullptr}; +    std::shared_ptr<ConsoleSixAxis> console_six_axis{nullptr}; +    std::shared_ptr<DebugMouse> debug_mouse{nullptr}; +    std::shared_ptr<DebugPad> debug_pad{nullptr}; +    std::shared_ptr<Digitizer> digitizer{nullptr}; +    std::shared_ptr<HomeButton> home_button{nullptr}; +    std::shared_ptr<Keyboard> keyboard{nullptr}; +    std::shared_ptr<Mouse> mouse{nullptr}; +    std::shared_ptr<NPad> npad{nullptr}; +    std::shared_ptr<Palma> palma{nullptr}; +    std::shared_ptr<SevenSixAxis> seven_six_axis{nullptr}; +    std::shared_ptr<SixAxis> six_axis{nullptr}; +    std::shared_ptr<SleepButton> sleep_button{nullptr}; +    std::shared_ptr<UniquePad> unique_pad{nullptr};      // TODO: Create these resources -    // std::shared_ptr<AudioControl> audio_control = nullptr; -    // std::shared_ptr<ButtonConfig> button_config = nullptr; -    // std::shared_ptr<Config> config = nullptr; -    // std::shared_ptr<Connection> connection = nullptr; -    // std::shared_ptr<CustomConfig> custom_config = nullptr; -    // std::shared_ptr<Digitizer> digitizer = nullptr; -    // std::shared_ptr<Hdls> hdls = nullptr; -    // std::shared_ptr<PlayReport> play_report = nullptr; -    // std::shared_ptr<Rail> rail = nullptr; +    // std::shared_ptr<AudioControl> audio_control{nullptr}; +    // std::shared_ptr<ButtonConfig> button_config{nullptr}; +    // std::shared_ptr<Config> config{nullptr}; +    // std::shared_ptr<Connection> connection{nullptr}; +    // std::shared_ptr<CustomConfig> custom_config{nullptr}; +    // std::shared_ptr<Digitizer> digitizer{nullptr}; +    // std::shared_ptr<Hdls> hdls{nullptr}; +    // std::shared_ptr<PlayReport> play_report{nullptr}; +    // std::shared_ptr<Rail> rail{nullptr}; + +    // Touch Resources +    std::shared_ptr<Gesture> gesture{nullptr}; +    std::shared_ptr<TouchScreen> touch_screen{nullptr}; +    std::shared_ptr<TouchResource> touch_resource{nullptr}; +    std::shared_ptr<TouchDriver> touch_driver{nullptr}; +    std::shared_ptr<Core::Timing::EventType> touch_update_event{nullptr};      Core::System& system;      KernelHelpers::ServiceContext service_context; @@ -162,12 +179,12 @@ public:  private:      void GetSharedMemoryHandle(HLERequestContext& ctx); -    std::shared_ptr<Core::Timing::EventType> npad_update_event; -    std::shared_ptr<Core::Timing::EventType> default_update_event; -    std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event; -    std::shared_ptr<Core::Timing::EventType> motion_update_event; +    std::shared_ptr<Core::Timing::EventType> npad_update_event{nullptr}; +    std::shared_ptr<Core::Timing::EventType> default_update_event{nullptr}; +    std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event{nullptr}; +    std::shared_ptr<Core::Timing::EventType> motion_update_event{nullptr}; -    u64 aruid; +    u64 aruid{};      std::shared_ptr<ResourceManager> resource_manager;  }; 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 @@  namespace Core {  class System; -} +} // namespace Core  namespace Kernel { +class KEvent;  class KSharedMemory; -} +} // namespace Kernel  namespace Service::HID {  struct SharedMemoryFormat; @@ -73,7 +74,8 @@ struct AppletResourceHolder {      std::recursive_mutex* shared_mutex{nullptr};      NPadResource* shared_npad_resource{nullptr};      std::shared_ptr<HandheldConfig> handheld_config{nullptr}; -    long* handle_1; +    Kernel::KEvent* input_event{nullptr}; +    std::mutex* input_mutex{nullptr};  };  class AppletResource { diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp index cde84b1bb..8ab26bc36 100644 --- a/src/hid_core/resources/npad/npad.cpp +++ b/src/hid_core/resources/npad/npad.cpp @@ -1081,11 +1081,14 @@ void NPad::UnregisterAppletResourceUserId(u64 aruid) {  void NPad::SetNpadExternals(std::shared_ptr<AppletResource> resource,                              std::recursive_mutex* shared_mutex,                              std::shared_ptr<HandheldConfig> handheld_config, +                            Kernel::KEvent* input_event, std::mutex* input_mutex,                              std::shared_ptr<Service::Set::ISystemSettingsServer> settings) {      applet_resource_holder.applet_resource = resource;      applet_resource_holder.shared_mutex = shared_mutex;      applet_resource_holder.shared_npad_resource = &npad_resource;      applet_resource_holder.handheld_config = handheld_config; +    applet_resource_holder.input_event = input_event; +    applet_resource_holder.input_mutex = input_mutex;      vibration_handler.SetSettingsService(settings); diff --git a/src/hid_core/resources/npad/npad.h b/src/hid_core/resources/npad/npad.h index 502cb9b55..e81cc3abe 100644 --- a/src/hid_core/resources/npad/npad.h +++ b/src/hid_core/resources/npad/npad.h @@ -133,6 +133,7 @@ public:      void SetNpadExternals(std::shared_ptr<AppletResource> resource,                            std::recursive_mutex* shared_mutex,                            std::shared_ptr<HandheldConfig> handheld_config, +                          Kernel::KEvent* input_event, std::mutex* input_mutex,                            std::shared_ptr<Service::Set::ISystemSettingsServer> settings);      AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id); @@ -206,9 +207,6 @@ private:      std::array<AbstractPad, MaxSupportedNpadIdTypes> abstracted_pads;      NpadVibration vibration_handler{}; -    Kernel::KEvent* input_event{nullptr}; -    std::mutex* input_mutex{nullptr}; -      std::atomic<u64> press_state{};      std::array<std::array<NpadControllerData, MaxSupportedNpadIdTypes>, AruidIndexMax>          controller_data{}; 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 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later -#include "common/math_util.h" -#include "common/settings.h" -#include "core/frontend/emu_window.h" -#include "hid_core/frontend/emulated_console.h" -#include "hid_core/hid_core.h" -#include "hid_core/resources/applet_resource.h" -#include "hid_core/resources/shared_memory_format.h"  #include "hid_core/resources/touch_screen/gesture.h" +#include "hid_core/resources/touch_screen/touch_screen_resource.h"  namespace Service::HID { -// HW is around 700, value is set to 400 to make it easier to trigger with mouse -constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s -constexpr f32 angle_threshold = 0.015f; // Threshold in radians -constexpr f32 pinch_threshold = 0.5f;   // Threshold in pixels -constexpr f32 press_delay = 0.5f;       // Time in seconds -constexpr f32 double_tap_delay = 0.35f; // Time in seconds -constexpr f32 Square(s32 num) { -    return static_cast<f32>(num * num); -} +Gesture::Gesture(std::shared_ptr<TouchResource> resource) : touch_resource{resource} {} -Gesture::Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) { -    console = hid_core.GetEmulatedConsole(); -}  Gesture::~Gesture() = default; -void Gesture::OnInit() { -    std::scoped_lock shared_lock{*shared_mutex}; -    const u64 aruid = applet_resource->GetActiveAruid(); -    auto* data = applet_resource->GetAruidData(aruid); - -    if (data == nullptr || !data->flag.is_assigned) { -        return; -    } - -    shared_memory = &data->shared_memory_format->gesture; -    shared_memory->gesture_lifo.buffer_count = 0; -    shared_memory->gesture_lifo.buffer_tail = 0; -    force_update = true; -} - -void Gesture::OnRelease() {} - -void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { -    std::scoped_lock shared_lock{*shared_mutex}; -    const u64 aruid = applet_resource->GetActiveAruid(); -    auto* data = applet_resource->GetAruidData(aruid); - -    if (data == nullptr || !data->flag.is_assigned) { -        return; -    } - -    shared_memory = &data->shared_memory_format->gesture; - -    if (!IsControllerActivated()) { -        shared_memory->gesture_lifo.buffer_count = 0; -        shared_memory->gesture_lifo.buffer_tail = 0; -        return; -    } - -    ReadTouchInput(); - -    GestureProperties gesture = GetGestureProperties(); -    f32 time_difference = -        static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) / -        (1000 * 1000 * 1000); - -    // Only update if necessary -    if (!ShouldUpdateGesture(gesture, time_difference)) { -        return; -    } - -    last_update_timestamp = shared_memory->gesture_lifo.timestamp; -    UpdateGestureSharedMemory(gesture, time_difference); -} - -void Gesture::ReadTouchInput() { -    if (!Settings::values.touchscreen.enabled) { -        fingers = {}; -        return; -    } - -    const auto touch_status = console->GetTouch(); -    for (std::size_t id = 0; id < fingers.size(); ++id) { -        fingers[id] = touch_status[id]; -    } -} - -bool Gesture::ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference) { -    const auto& last_entry = GetLastGestureEntry(); -    if (force_update) { -        force_update = false; -        return true; -    } - -    // Update if coordinates change -    for (size_t id = 0; id < MAX_POINTS; id++) { -        if (gesture.points[id] != last_gesture.points[id]) { -            return true; -        } -    } - -    // Update on press and hold event after 0.5 seconds -    if (last_entry.type == GestureType::Touch && last_entry.point_count == 1 && -        time_difference > press_delay) { -        return enable_press_and_tap; -    } - -    return false; -} - -void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference) { -    GestureType type = GestureType::Idle; -    GestureAttribute attributes{}; - -    const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state; - -    // Reset next state to default -    next_state.sampling_number = last_entry.sampling_number + 1; -    next_state.delta = {}; -    next_state.vel_x = 0; -    next_state.vel_y = 0; -    next_state.direction = GestureDirection::None; -    next_state.rotation_angle = 0; -    next_state.scale = 0; - -    if (gesture.active_points > 0) { -        if (last_gesture.active_points == 0) { -            NewGesture(gesture, type, attributes); -        } else { -            UpdateExistingGesture(gesture, type, time_difference); -        } -    } else { -        EndGesture(gesture, last_gesture, type, attributes, time_difference); -    } - -    // Apply attributes -    next_state.detection_count = gesture.detection_count; -    next_state.type = type; -    next_state.attributes = attributes; -    next_state.pos = gesture.mid_point; -    next_state.point_count = static_cast<s32>(gesture.active_points); -    next_state.points = gesture.points; -    last_gesture = gesture; - -    shared_memory->gesture_lifo.WriteNextEntry(next_state); -} - -void Gesture::NewGesture(GestureProperties& gesture, GestureType& type, -                         GestureAttribute& attributes) { -    const auto& last_entry = GetLastGestureEntry(); - -    gesture.detection_count++; -    type = GestureType::Touch; - -    // New touch after cancel is not considered new -    if (last_entry.type != GestureType::Cancel) { -        attributes.is_new_touch.Assign(1); -        enable_press_and_tap = true; -    } -} - -void Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type, -                                    f32 time_difference) { -    const auto& last_entry = GetLastGestureEntry(); +Result Gesture::Activate() { +    std::scoped_lock lock{mutex}; -    // Promote to pan type if touch moved -    for (size_t id = 0; id < MAX_POINTS; id++) { -        if (gesture.points[id] != last_gesture.points[id]) { -            type = GestureType::Pan; -            break; -        } +    // TODO: Result result = CreateThread(); +    Result result = ResultSuccess; +    if (result.IsError()) { +        return result;      } -    // Number of fingers changed cancel the last event and clear data -    if (gesture.active_points != last_gesture.active_points) { -        type = GestureType::Cancel; -        enable_press_and_tap = false; -        gesture.active_points = 0; -        gesture.mid_point = {}; -        gesture.points.fill({}); -        return; -    } - -    // Calculate extra parameters of panning -    if (type == GestureType::Pan) { -        UpdatePanEvent(gesture, last_gesture, type, time_difference); -        return; -    } +    result = touch_resource->ActivateGesture(); -    // Promote to press type -    if (last_entry.type == GestureType::Touch) { -        type = GestureType::Press; +    if (result.IsError()) { +        // TODO: StopThread();      } -} - -void Gesture::EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, -                         GestureType& type, GestureAttribute& attributes, f32 time_difference) { -    const auto& last_entry = GetLastGestureEntry(); -    if (last_gesture_props.active_points != 0) { -        switch (last_entry.type) { -        case GestureType::Touch: -            if (enable_press_and_tap) { -                SetTapEvent(gesture, last_gesture_props, type, attributes); -                return; -            } -            type = GestureType::Cancel; -            force_update = true; -            break; -        case GestureType::Press: -        case GestureType::Tap: -        case GestureType::Swipe: -        case GestureType::Pinch: -        case GestureType::Rotate: -            type = GestureType::Complete; -            force_update = true; -            break; -        case GestureType::Pan: -            EndPanEvent(gesture, last_gesture_props, type, time_difference); -            break; -        default: -            break; -        } -        return; -    } -    if (last_entry.type == GestureType::Complete || last_entry.type == GestureType::Cancel) { -        gesture.detection_count++; -    } +    return result;  } -void Gesture::SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, -                          GestureType& type, GestureAttribute& attributes) { -    type = GestureType::Tap; -    gesture = last_gesture_props; -    force_update = true; -    f32 tap_time_difference = -        static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000); -    last_tap_timestamp = last_update_timestamp; -    if (tap_time_difference < double_tap_delay) { -        attributes.is_double_tap.Assign(1); -    } +Result Gesture::Activate(u64 aruid, u32 basic_gesture_id) { +    std::scoped_lock lock{mutex}; +    return touch_resource->ActivateGesture(aruid, basic_gesture_id);  } -void Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, -                             GestureType& type, f32 time_difference) { -    const auto& last_entry = GetLastGestureEntry(); +Result Gesture::Deactivate() { +    std::scoped_lock lock{mutex}; +    const auto result = touch_resource->DeactivateGesture(); -    next_state.delta = gesture.mid_point - last_entry.pos; -    next_state.vel_x = static_cast<f32>(next_state.delta.x) / time_difference; -    next_state.vel_y = static_cast<f32>(next_state.delta.y) / time_difference; -    last_pan_time_difference = time_difference; - -    // Promote to pinch type -    if (std::abs(gesture.average_distance - last_gesture_props.average_distance) > -        pinch_threshold) { -        type = GestureType::Pinch; -        next_state.scale = gesture.average_distance / last_gesture_props.average_distance; +    if (result.IsError()) { +        return result;      } -    const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) / -                                                  (1 + (gesture.angle * last_gesture_props.angle))); -    // Promote to rotate type -    if (std::abs(angle_between_two_lines) > angle_threshold) { -        type = GestureType::Rotate; -        next_state.scale = 0; -        next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; -    } +    // TODO: return StopThread(); +    return ResultSuccess;  } -void Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, -                          GestureType& type, f32 time_difference) { -    const auto& last_entry = GetLastGestureEntry(); -    next_state.vel_x = -        static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference); -    next_state.vel_y = -        static_cast<f32>(last_entry.delta.y) / (last_pan_time_difference + time_difference); -    const f32 curr_vel = -        std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y)); - -    // Set swipe event with parameters -    if (curr_vel > swipe_threshold) { -        SetSwipeEvent(gesture, last_gesture_props, type); -        return; -    } - -    // End panning without swipe -    type = GestureType::Complete; -    next_state.vel_x = 0; -    next_state.vel_y = 0; -    force_update = true; -} - -void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, -                            GestureType& type) { -    const auto& last_entry = GetLastGestureEntry(); - -    type = GestureType::Swipe; -    gesture = last_gesture_props; -    force_update = true; -    next_state.delta = last_entry.delta; - -    if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) { -        if (next_state.delta.x > 0) { -            next_state.direction = GestureDirection::Right; -            return; -        } -        next_state.direction = GestureDirection::Left; -        return; -    } -    if (next_state.delta.y > 0) { -        next_state.direction = GestureDirection::Down; -        return; -    } -    next_state.direction = GestureDirection::Up; -} - -const GestureState& Gesture::GetLastGestureEntry() const { -    return shared_memory->gesture_lifo.ReadCurrentEntry().state; -} - -GestureProperties Gesture::GetGestureProperties() { -    GestureProperties gesture; -    std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers; -    const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), -                                       [](const auto& finger) { return finger.pressed; }); -    gesture.active_points = -        static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); - -    for (size_t id = 0; id < gesture.active_points; ++id) { -        const auto& [active_x, active_y] = active_fingers[id].position; -        gesture.points[id] = { -            .x = static_cast<s32>(active_x * Layout::ScreenUndocked::Width), -            .y = static_cast<s32>(active_y * Layout::ScreenUndocked::Height), -        }; - -        // Hack: There is no touch in docked but games still allow it -        if (Settings::IsDockedMode()) { -            gesture.points[id] = { -                .x = static_cast<s32>(active_x * Layout::ScreenDocked::Width), -                .y = static_cast<s32>(active_y * Layout::ScreenDocked::Height), -            }; -        } - -        gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points); -        gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points); -    } - -    for (size_t id = 0; id < gesture.active_points; ++id) { -        const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) + -                                       Square(gesture.mid_point.y - gesture.points[id].y)); -        gesture.average_distance += distance / static_cast<f32>(gesture.active_points); -    } - -    gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y), -                               static_cast<f32>(gesture.mid_point.x - gesture.points[0].x)); - -    gesture.detection_count = last_gesture.detection_count; - -    return gesture; +Result Gesture::IsActive(bool& out_is_active) const { +    out_is_active = touch_resource->IsGestureActive(); +    return ResultSuccess;  }  } // 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 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later  #pragma once -#include <array> +#include <mutex>  #include "common/common_types.h" -#include "hid_core/resources/controller_base.h" -#include "hid_core/resources/touch_screen/touch_types.h" - -namespace Core::HID { -class EmulatedConsole; -} +#include "core/hle/result.h"  namespace Service::HID { -struct GestureSharedMemoryFormat; +class TouchResource; -class Gesture final : public ControllerBase { +/// Handles gesture request from HID interfaces +class Gesture {  public: -    explicit Gesture(Core::HID::HIDCore& hid_core_); -    ~Gesture() override; +    Gesture(std::shared_ptr<TouchResource> resource); +    ~Gesture(); -    // Called when the controller is initialized -    void OnInit() override; +    Result Activate(); +    Result Activate(u64 aruid, u32 basic_gesture_id); -    // When the controller is released -    void OnRelease() override; +    Result Deactivate(); -    // When the controller is requesting an update for the shared memory -    void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; +    Result IsActive(bool& out_is_active) const;  private: -    // Reads input from all available input engines -    void ReadTouchInput(); - -    // Returns true if gesture state needs to be updated -    bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference); - -    // Updates the shared memory to the next state -    void UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference); - -    // Initializes new gesture -    void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes); - -    // Updates existing gesture state -    void UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference); - -    // Terminates exiting gesture -    void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, -                    GestureType& type, GestureAttribute& attributes, f32 time_difference); - -    // Set current event to a tap event -    void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, -                     GestureType& type, GestureAttribute& attributes); - -    // Calculates and set the extra parameters related to a pan event -    void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, -                        GestureType& type, f32 time_difference); - -    // Terminates the pan event -    void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, -                     GestureType& type, f32 time_difference); - -    // Set current event to a swipe event -    void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, -                       GestureType& type); - -    // Retrieves the last gesture entry, as indicated by shared memory indices. -    [[nodiscard]] const GestureState& GetLastGestureEntry() const; - -    // Returns the average distance, angle and middle point of the active fingers -    GestureProperties GetGestureProperties(); - -    GestureState next_state{}; -    GestureSharedMemoryFormat* shared_memory; -    Core::HID::EmulatedConsole* console = nullptr; - -    std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{}; -    GestureProperties last_gesture{}; -    s64 last_update_timestamp{}; -    s64 last_tap_timestamp{}; -    f32 last_pan_time_difference{}; -    bool force_update{false}; -    bool enable_press_and_tap{false}; +    mutable std::mutex mutex; +    std::shared_ptr<TouchResource> touch_resource;  }; +  } // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "common/math_util.h" +#include "hid_core/resources/touch_screen/gesture_handler.h" + +namespace Service::HID { + +constexpr f32 Square(s32 num) { +    return static_cast<f32>(num * num); +} + +GestureHandler::GestureHandler() {} + +GestureHandler::~GestureHandler() {} + +void GestureHandler::SetTouchState(std::span<TouchState> touch_state, u32 count, s64 timestamp) { +    gesture = {}; +    gesture.active_points = std::min(MaxPoints, static_cast<std::size_t>(count)); + +    for (size_t id = 0; id < gesture.active_points; ++id) { +        const auto& [active_x, active_y] = touch_state[id].position; +        gesture.points[id] = { +            .x = static_cast<s32>(active_x), +            .y = static_cast<s32>(active_y), +        }; + +        gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points); +        gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points); +    } + +    for (size_t id = 0; id < gesture.active_points; ++id) { +        const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) + +                                       Square(gesture.mid_point.y - gesture.points[id].y)); +        gesture.average_distance += distance / static_cast<f32>(gesture.active_points); +    } + +    gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y), +                               static_cast<f32>(gesture.mid_point.x - gesture.points[0].x)); + +    gesture.detection_count = last_gesture.detection_count; + +    if (last_update_timestamp > timestamp) { +        timestamp = last_tap_timestamp; +    } + +    time_difference = static_cast<f32>(timestamp - last_update_timestamp) / (1000 * 1000 * 1000); +} + +bool GestureHandler::NeedsUpdate() { +    if (force_update) { +        force_update = false; +        return true; +    } + +    // Update if coordinates change +    for (size_t id = 0; id < MaxPoints; id++) { +        if (gesture.points[id] != last_gesture.points[id]) { +            return true; +        } +    } + +    // Update on press and hold event after 0.5 seconds +    if (last_gesture_state.type == GestureType::Touch && last_gesture_state.point_count == 1 && +        time_difference > PressDelay) { +        return enable_press_and_tap; +    } + +    return false; +} + +void GestureHandler::UpdateGestureState(GestureState& next_state, s64 timestamp) { +    last_update_timestamp = timestamp; + +    GestureType type = GestureType::Idle; +    GestureAttribute attributes{}; + +    // Reset next state to default +    next_state.sampling_number = last_gesture_state.sampling_number + 1; +    next_state.delta = {}; +    next_state.vel_x = 0; +    next_state.vel_y = 0; +    next_state.direction = GestureDirection::None; +    next_state.rotation_angle = 0; +    next_state.scale = 0; + +    if (gesture.active_points > 0) { +        if (last_gesture.active_points == 0) { +            NewGesture(type, attributes); +        } else { +            UpdateExistingGesture(next_state, type); +        } +    } else { +        EndGesture(next_state, type, attributes); +    } + +    // Apply attributes +    next_state.detection_count = gesture.detection_count; +    next_state.type = type; +    next_state.attributes = attributes; +    next_state.pos = gesture.mid_point; +    next_state.point_count = static_cast<s32>(gesture.active_points); +    next_state.points = gesture.points; +    last_gesture = gesture; +    last_gesture_state = next_state; +} + +void GestureHandler::NewGesture(GestureType& type, GestureAttribute& attributes) { +    gesture.detection_count++; +    type = GestureType::Touch; + +    // New touch after cancel is not considered new +    if (last_gesture_state.type != GestureType::Cancel) { +        attributes.is_new_touch.Assign(1); +        enable_press_and_tap = true; +    } +} + +void GestureHandler::UpdateExistingGesture(GestureState& next_state, GestureType& type) { +    // Promote to pan type if touch moved +    for (size_t id = 0; id < MaxPoints; id++) { +        if (gesture.points[id] != last_gesture.points[id]) { +            type = GestureType::Pan; +            break; +        } +    } + +    // Number of fingers changed cancel the last event and clear data +    if (gesture.active_points != last_gesture.active_points) { +        type = GestureType::Cancel; +        enable_press_and_tap = false; +        gesture.active_points = 0; +        gesture.mid_point = {}; +        gesture.points.fill({}); +        return; +    } + +    // Calculate extra parameters of panning +    if (type == GestureType::Pan) { +        UpdatePanEvent(next_state, type); +        return; +    } + +    // Promote to press type +    if (last_gesture_state.type == GestureType::Touch) { +        type = GestureType::Press; +    } +} + +void GestureHandler::EndGesture(GestureState& next_state, GestureType& type, +                                GestureAttribute& attributes) { +    if (last_gesture.active_points != 0) { +        switch (last_gesture_state.type) { +        case GestureType::Touch: +            if (enable_press_and_tap) { +                SetTapEvent(type, attributes); +                return; +            } +            type = GestureType::Cancel; +            force_update = true; +            break; +        case GestureType::Press: +        case GestureType::Tap: +        case GestureType::Swipe: +        case GestureType::Pinch: +        case GestureType::Rotate: +            type = GestureType::Complete; +            force_update = true; +            break; +        case GestureType::Pan: +            EndPanEvent(next_state, type); +            break; +        default: +            break; +        } +        return; +    } +    if (last_gesture_state.type == GestureType::Complete || +        last_gesture_state.type == GestureType::Cancel) { +        gesture.detection_count++; +    } +} + +void GestureHandler::SetTapEvent(GestureType& type, GestureAttribute& attributes) { +    type = GestureType::Tap; +    gesture = last_gesture; +    force_update = true; +    f32 tap_time_difference = +        static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000); +    last_tap_timestamp = last_update_timestamp; +    if (tap_time_difference < DoubleTapDelay) { +        attributes.is_double_tap.Assign(1); +    } +} + +void GestureHandler::UpdatePanEvent(GestureState& next_state, GestureType& type) { +    next_state.delta = gesture.mid_point - last_gesture_state.pos; +    next_state.vel_x = static_cast<f32>(next_state.delta.x) / time_difference; +    next_state.vel_y = static_cast<f32>(next_state.delta.y) / time_difference; +    last_pan_time_difference = time_difference; + +    // Promote to pinch type +    if (std::abs(gesture.average_distance - last_gesture.average_distance) > PinchThreshold) { +        type = GestureType::Pinch; +        next_state.scale = gesture.average_distance / last_gesture.average_distance; +    } + +    const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture.angle) / +                                                  (1 + (gesture.angle * last_gesture.angle))); +    // Promote to rotate type +    if (std::abs(angle_between_two_lines) > AngleThreshold) { +        type = GestureType::Rotate; +        next_state.scale = 0; +        next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; +    } +} + +void GestureHandler::EndPanEvent(GestureState& next_state, GestureType& type) { +    next_state.vel_x = +        static_cast<f32>(last_gesture_state.delta.x) / (last_pan_time_difference + time_difference); +    next_state.vel_y = +        static_cast<f32>(last_gesture_state.delta.y) / (last_pan_time_difference + time_difference); +    const f32 curr_vel = +        std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y)); + +    // Set swipe event with parameters +    if (curr_vel > SwipeThreshold) { +        SetSwipeEvent(next_state, type); +        return; +    } + +    // End panning without swipe +    type = GestureType::Complete; +    next_state.vel_x = 0; +    next_state.vel_y = 0; +    force_update = true; +} + +void GestureHandler::SetSwipeEvent(GestureState& next_state, GestureType& type) { +    type = GestureType::Swipe; +    gesture = last_gesture; +    force_update = true; +    next_state.delta = last_gesture_state.delta; + +    if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) { +        if (next_state.delta.x > 0) { +            next_state.direction = GestureDirection::Right; +            return; +        } +        next_state.direction = GestureDirection::Left; +        return; +    } +    if (next_state.delta.y > 0) { +        next_state.direction = GestureDirection::Down; +        return; +    } +    next_state.direction = GestureDirection::Up; +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <span> + +#include "hid_core/resources/touch_screen/touch_types.h" + +namespace Service::HID { + +class GestureHandler { +public: +    GestureHandler(); +    ~GestureHandler(); + +    void SetTouchState(std::span<TouchState> touch_state, u32 count, s64 timestamp); + +    bool NeedsUpdate(); +    void UpdateGestureState(GestureState& next_state, s64 timestamp); + +private: +    // Initializes new gesture +    void NewGesture(GestureType& type, GestureAttribute& attributes); + +    // Updates existing gesture state +    void UpdateExistingGesture(GestureState& next_state, GestureType& type); + +    // Terminates exiting gesture +    void EndGesture(GestureState& next_state, GestureType& type, GestureAttribute& attributes); + +    // Set current event to a tap event +    void SetTapEvent(GestureType& type, GestureAttribute& attributes); + +    // Calculates and set the extra parameters related to a pan event +    void UpdatePanEvent(GestureState& next_state, GestureType& type); + +    // Terminates the pan event +    void EndPanEvent(GestureState& next_state, GestureType& type); + +    // Set current event to a swipe event +    void SetSwipeEvent(GestureState& next_state, GestureType& type); + +    GestureProperties gesture{}; +    GestureProperties last_gesture{}; +    GestureState last_gesture_state{}; +    s64 last_update_timestamp{}; +    s64 last_tap_timestamp{}; +    f32 last_pan_time_difference{}; +    f32 time_difference{}; +    bool force_update{true}; +    bool enable_press_and_tap{false}; +}; + +} // 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 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include <array> -#include "common/bit_field.h" -#include "common/common_types.h" -#include "common/point.h" - -namespace Service::HID { -static constexpr size_t MAX_FINGERS = 16; -static constexpr size_t MAX_POINTS = 4; - -// This is nn::hid::GestureType -enum class GestureType : u32 { -    Idle,     // Nothing touching the screen -    Complete, // Set at the end of a touch event -    Cancel,   // Set when the number of fingers change -    Touch,    // A finger just touched the screen -    Press,    // Set if last type is touch and the finger hasn't moved -    Tap,      // Fast press then release -    Pan,      // All points moving together across the screen -    Swipe,    // Fast press movement and release of a single point -    Pinch,    // All points moving away/closer to the midpoint -    Rotate,   // All points rotating from the midpoint -}; - -// This is nn::hid::GestureDirection -enum class GestureDirection : u32 { -    None, -    Left, -    Up, -    Right, -    Down, -}; - -// This is nn::hid::GestureAttribute -struct GestureAttribute { -    union { -        u32 raw{}; - -        BitField<4, 1, u32> is_new_touch; -        BitField<8, 1, u32> is_double_tap; -    }; -}; -static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size"); - -// This is nn::hid::GestureState -struct GestureState { -    s64 sampling_number{}; -    s64 detection_count{}; -    GestureType type{GestureType::Idle}; -    GestureDirection direction{GestureDirection::None}; -    Common::Point<s32> pos{}; -    Common::Point<s32> delta{}; -    f32 vel_x{}; -    f32 vel_y{}; -    GestureAttribute attributes{}; -    f32 scale{}; -    f32 rotation_angle{}; -    s32 point_count{}; -    std::array<Common::Point<s32>, 4> points{}; -}; -static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); - -struct GestureProperties { -    std::array<Common::Point<s32>, MAX_POINTS> points{}; -    std::size_t active_points{}; -    Common::Point<s32> mid_point{}; -    s64 detection_count{}; -    u64 delta_time{}; -    f32 average_distance{}; -    f32 angle{}; -}; - -} // 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 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <algorithm> -#include "common/common_types.h" -#include "common/settings.h" -#include "core/core_timing.h" -#include "core/frontend/emu_window.h" -#include "hid_core/frontend/emulated_console.h" -#include "hid_core/hid_core.h" -#include "hid_core/resources/applet_resource.h" -#include "hid_core/resources/shared_memory_format.h" +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "hid_core/hid_types.h"  #include "hid_core/resources/touch_screen/touch_screen.h" +#include "hid_core/resources/touch_screen/touch_screen_resource.h"  namespace Service::HID { -TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_) -    : ControllerBase{hid_core_}, touchscreen_width(Layout::ScreenUndocked::Width), -      touchscreen_height(Layout::ScreenUndocked::Height) { -    console = hid_core.GetEmulatedConsole(); -} +TouchScreen::TouchScreen(std::shared_ptr<TouchResource> resource) : touch_resource{resource} {}  TouchScreen::~TouchScreen() = default; -void TouchScreen::OnInit() {} +Result TouchScreen::Activate() { +    std::scoped_lock lock{mutex}; -void TouchScreen::OnRelease() {} - -void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { -    const u64 aruid = applet_resource->GetActiveAruid(); -    auto* data = applet_resource->GetAruidData(aruid); +    // TODO: Result result = CreateThread(); +    Result result = ResultSuccess; +    if (result.IsError()) { +        return result; +    } -    if (data == nullptr || !data->flag.is_assigned) { -        return; +    result = touch_resource->ActivateTouch(); +    if (result.IsError()) { +        // TODO: StopThread();      } -    TouchScreenSharedMemoryFormat& shared_memory = data->shared_memory_format->touch_screen; -    shared_memory.touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count(); +    return result; +} -    if (!IsControllerActivated()) { -        shared_memory.touch_screen_lifo.buffer_count = 0; -        shared_memory.touch_screen_lifo.buffer_tail = 0; -        return; -    } +Result TouchScreen::Activate(u64 aruid) { +    std::scoped_lock lock{mutex}; +    return touch_resource->ActivateTouch(aruid); +} -    const auto touch_status = console->GetTouch(); -    for (std::size_t id = 0; id < MAX_FINGERS; id++) { -        const auto& current_touch = touch_status[id]; -        auto& finger = fingers[id]; -        finger.id = current_touch.id; - -        if (finger.attribute.start_touch) { -            finger.attribute.raw = 0; -            continue; -        } - -        if (finger.attribute.end_touch) { -            finger.attribute.raw = 0; -            finger.pressed = false; -            continue; -        } - -        if (!finger.pressed && current_touch.pressed) { -            // Ignore all touch fingers if disabled -            if (!Settings::values.touchscreen.enabled) { -                continue; -            } - -            finger.attribute.start_touch.Assign(1); -            finger.pressed = true; -            finger.position = current_touch.position; -            continue; -        } - -        if (finger.pressed && !current_touch.pressed) { -            finger.attribute.raw = 0; -            finger.attribute.end_touch.Assign(1); -            continue; -        } - -        // Only update position if touch is not on a special frame -        finger.position = current_touch.position; -    } +Result TouchScreen::Deactivate() { +    std::scoped_lock lock{mutex}; +    const auto result = touch_resource->DeactivateTouch(); -    std::array<Core::HID::TouchFinger, MAX_FINGERS> active_fingers; -    const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), -                                       [](const auto& finger) { return finger.pressed; }); -    const auto active_fingers_count = -        static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); - -    const u64 timestamp = static_cast<u64>(core_timing.GetGlobalTimeNs().count()); -    const auto& last_entry = shared_memory.touch_screen_lifo.ReadCurrentEntry().state; - -    next_state.sampling_number = last_entry.sampling_number + 1; -    next_state.entry_count = static_cast<s32>(active_fingers_count); - -    for (std::size_t id = 0; id < MAX_FINGERS; ++id) { -        auto& touch_entry = next_state.states[id]; -        if (id < active_fingers_count) { -            const auto& [active_x, active_y] = active_fingers[id].position; -            touch_entry.position = { -                .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; -            touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; -            touch_entry.delta_time = timestamp - active_fingers[id].last_touch; -            fingers[active_fingers[id].id].last_touch = timestamp; -            touch_entry.finger = active_fingers[id].id; -            touch_entry.attribute.raw = active_fingers[id].attribute.raw; -        } else { -            // Clear touch entry -            touch_entry.attribute.raw = 0; -            touch_entry.position = {}; -            touch_entry.diameter_x = 0; -            touch_entry.diameter_y = 0; -            touch_entry.rotation_angle = 0; -            touch_entry.delta_time = 0; -            touch_entry.finger = 0; -        } +    if (result.IsError()) { +        return result;      } -    shared_memory.touch_screen_lifo.WriteNextEntry(next_state); +    // TODO: return StopThread(); +    return ResultSuccess; +} + +Result TouchScreen::IsActive(bool& out_is_active) const { +    out_is_active = touch_resource->IsTouchActive(); +    return ResultSuccess; +} + +Result TouchScreen::SetTouchScreenAutoPilotState(const AutoPilotState& auto_pilot_state) { +    std::scoped_lock lock{mutex}; +    return touch_resource->SetTouchScreenAutoPilotState(auto_pilot_state); +} + +Result TouchScreen::UnsetTouchScreenAutoPilotState() { +    std::scoped_lock lock{mutex}; +    return touch_resource->UnsetTouchScreenAutoPilotState(); +} + +Result TouchScreen::RequestNextTouchInput() { +    std::scoped_lock lock{mutex}; +    return touch_resource->RequestNextTouchInput(); +} + +Result TouchScreen::RequestNextDummyInput() { +    std::scoped_lock lock{mutex}; +    return touch_resource->RequestNextDummyInput(); +} + +Result TouchScreen::ProcessTouchScreenAutoTune() { +    std::scoped_lock lock{mutex}; +    return touch_resource->ProcessTouchScreenAutoTune(); +} + +Result TouchScreen::SetTouchScreenMagnification(f32 point1_x, f32 point1_y, f32 point2_x, +                                                f32 point2_y) { +    std::scoped_lock lock{mutex}; +    touch_resource->SetTouchScreenMagnification(point1_x, point1_y, point2_x, point2_y); +    return ResultSuccess; +} + +Result TouchScreen::SetTouchScreenResolution(u32 width, u32 height, u64 aruid) { +    std::scoped_lock lock{mutex}; +    return touch_resource->SetTouchScreenResolution(width, height, aruid); +} + +Result TouchScreen::SetTouchScreenConfiguration( +    const Core::HID::TouchScreenConfigurationForNx& mode, u64 aruid) { +    std::scoped_lock lock{mutex}; +    return touch_resource->SetTouchScreenConfiguration(mode, aruid); +} + +Result TouchScreen::GetTouchScreenConfiguration(Core::HID::TouchScreenConfigurationForNx& out_mode, +                                                u64 aruid) const { +    std::scoped_lock lock{mutex}; +    return touch_resource->GetTouchScreenConfiguration(out_mode, aruid); +} + +Result TouchScreen::SetTouchScreenDefaultConfiguration( +    const Core::HID::TouchScreenConfigurationForNx& mode) { +    std::scoped_lock lock{mutex}; +    return touch_resource->SetTouchScreenDefaultConfiguration(mode); +} + +Result TouchScreen::GetTouchScreenDefaultConfiguration( +    Core::HID::TouchScreenConfigurationForNx& out_mode) const { +    std::scoped_lock lock{mutex}; +    return touch_resource->GetTouchScreenDefaultConfiguration(out_mode);  } -void TouchScreen::SetTouchscreenDimensions(u32 width, u32 height) { -    touchscreen_width = width; -    touchscreen_height = height; +void TouchScreen::OnTouchUpdate(u64 timestamp) { +    std::scoped_lock lock{mutex}; +    touch_resource->OnTouchUpdate(timestamp);  }  } // 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 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later  #pragma once -#include <array> +#include <mutex> -#include "hid_core/hid_types.h" -#include "hid_core/resources/controller_base.h" -#include "hid_core/resources/touch_screen/touch_types.h" +#include "common/common_types.h" +#include "core/hle/result.h"  namespace Core::HID { -class EmulatedConsole; -} // namespace Core::HID +struct TouchScreenConfigurationForNx; +} + +namespace Core::Timing { +struct EventType; +}  namespace Service::HID { -struct TouchScreenSharedMemoryFormat; +class TouchResource; +struct AutoPilotState; -class TouchScreen final : public ControllerBase { +/// Handles touch request from HID interfaces +class TouchScreen {  public: -    explicit TouchScreen(Core::HID::HIDCore& hid_core_); -    ~TouchScreen() override; +    TouchScreen(std::shared_ptr<TouchResource> resource); +    ~TouchScreen(); -    // Called when the controller is initialized -    void OnInit() override; +    Result Activate(); +    Result Activate(u64 aruid); -    // When the controller is released -    void OnRelease() override; +    Result Deactivate(); -    // When the controller is requesting an update for the shared memory -    void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; +    Result IsActive(bool& out_is_active) const; -    void SetTouchscreenDimensions(u32 width, u32 height); +    Result SetTouchScreenAutoPilotState(const AutoPilotState& auto_pilot_state); +    Result UnsetTouchScreenAutoPilotState(); -private: -    TouchScreenState next_state{}; -    Core::HID::EmulatedConsole* console = nullptr; +    Result RequestNextTouchInput(); +    Result RequestNextDummyInput(); + +    Result ProcessTouchScreenAutoTune(); + +    Result SetTouchScreenMagnification(f32 point1_x, f32 point1_y, f32 point2_x, f32 point2_y); +    Result SetTouchScreenResolution(u32 width, u32 height, u64 aruid); + +    Result SetTouchScreenConfiguration(const Core::HID::TouchScreenConfigurationForNx& mode, +                                       u64 aruid); +    Result GetTouchScreenConfiguration(Core::HID::TouchScreenConfigurationForNx& out_mode, +                                       u64 aruid) const; -    std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{}; -    u32 touchscreen_width; -    u32 touchscreen_height; +    Result SetTouchScreenDefaultConfiguration(const Core::HID::TouchScreenConfigurationForNx& mode); +    Result GetTouchScreenDefaultConfiguration( +        Core::HID::TouchScreenConfigurationForNx& out_mode) const; + +    void OnTouchUpdate(u64 timestamp); + +private: +    mutable std::mutex mutex; +    std::shared_ptr<TouchResource> touch_resource; +    std::shared_ptr<Core::Timing::EventType> touch_update_event;  }; +  } // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include <algorithm> +#include "common/settings.h" +#include "core/frontend/emu_window.h" +#include "hid_core/hid_core.h" +#include "hid_core/resources/touch_screen/touch_screen_driver.h" + +namespace Service::HID { + +TouchDriver::TouchDriver(Core::HID::HIDCore& hid_core) { +    console = hid_core.GetEmulatedConsole(); +} + +TouchDriver::~TouchDriver() = default; + +Result TouchDriver::StartTouchSensor() { +    is_running = true; +    return ResultSuccess; +} + +Result TouchDriver::StopTouchSensor() { +    is_running = false; +    return ResultSuccess; +} + +bool TouchDriver::IsRunning() const { +    return is_running; +} + +void TouchDriver::ProcessTouchScreenAutoTune() const { +    // TODO +} + +Result TouchDriver::WaitForDummyInput() { +    touch_status = {}; +    return ResultSuccess; +} + +Result TouchDriver::WaitForInput() { +    touch_status = {}; +    const auto touch_input = console->GetTouch(); +    for (std::size_t id = 0; id < touch_status.states.size(); id++) { +        const auto& current_touch = touch_input[id]; +        auto& finger = fingers[id]; +        finger.id = current_touch.id; + +        if (finger.attribute.start_touch) { +            finger.attribute.raw = 0; +            continue; +        } + +        if (finger.attribute.end_touch) { +            finger.attribute.raw = 0; +            finger.pressed = false; +            continue; +        } + +        if (!finger.pressed && current_touch.pressed) { +            finger.attribute.start_touch.Assign(1); +            finger.pressed = true; +            finger.position = current_touch.position; +            continue; +        } + +        if (finger.pressed && !current_touch.pressed) { +            finger.attribute.raw = 0; +            finger.attribute.end_touch.Assign(1); +            continue; +        } + +        // Only update position if touch is not on a special frame +        finger.position = current_touch.position; +    } + +    std::array<Core::HID::TouchFinger, MaxFingers> active_fingers; +    const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), +                                       [](const auto& finger) { return finger.pressed; }); +    const auto active_fingers_count = +        static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); + +    touch_status.entry_count = static_cast<s32>(active_fingers_count); +    for (std::size_t id = 0; id < MaxFingers; ++id) { +        auto& touch_entry = touch_status.states[id]; +        if (id < active_fingers_count) { +            const auto& [active_x, active_y] = active_fingers[id].position; +            touch_entry.position = { +                .x = static_cast<u16>(active_x * TouchSensorWidth), +                .y = static_cast<u16>(active_y * TouchSensorHeight), +            }; +            touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; +            touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; +            touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; +            touch_entry.finger = active_fingers[id].id; +            touch_entry.attribute.raw = active_fingers[id].attribute.raw; +        } +    } +    return ResultSuccess; +} + +void TouchDriver::GetNextTouchState(TouchScreenState& out_state) const { +    out_state = touch_status; +} + +void TouchDriver::SetTouchMode(Core::HID::TouchScreenModeForNx mode) { +    touch_mode = mode; +} + +Core::HID::TouchScreenModeForNx TouchDriver::GetTouchMode() const { +    return touch_mode; +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/frontend/emulated_console.h" +#include "hid_core/hid_types.h" +#include "hid_core/resources/touch_screen/touch_types.h" + +namespace Core::HID { +class HIDCore; +} // namespace Core::HID + +namespace Service::HID { + +/// This handles all request to Ftm3bd56(TouchPanel) hardware +class TouchDriver { +public: +    explicit TouchDriver(Core::HID::HIDCore& hid_core); +    ~TouchDriver(); + +    Result StartTouchSensor(); +    Result StopTouchSensor(); +    bool IsRunning() const; + +    void ProcessTouchScreenAutoTune() const; + +    Result WaitForDummyInput(); +    Result WaitForInput(); + +    void GetNextTouchState(TouchScreenState& out_state) const; + +    void SetTouchMode(Core::HID::TouchScreenModeForNx mode); +    Core::HID::TouchScreenModeForNx GetTouchMode() const; + +private: +    bool is_running{}; +    TouchScreenState touch_status{}; +    Core::HID::TouchFingerState fingers{}; +    Core::HID::TouchScreenModeForNx touch_mode{}; + +    Core::HID::EmulatedConsole* console = nullptr; +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "common/logging/log.h" +#include "core/core_timing.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/service/set/system_settings_server.h" +#include "core/hle/service/sm/sm.h" +#include "hid_core/hid_result.h" +#include "hid_core/resources/applet_resource.h" +#include "hid_core/resources/shared_memory_format.h" +#include "hid_core/resources/touch_screen/touch_screen_driver.h" +#include "hid_core/resources/touch_screen/touch_screen_resource.h" + +namespace Service::HID { +constexpr auto GestureUpdatePeriod = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz) + +TouchResource::TouchResource(Core::System& system_) : system{system_} { +    m_set_sys = system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys"); +} + +TouchResource::~TouchResource() { +    Finalize(); +}; + +Result TouchResource::ActivateTouch() { +    if (global_ref_counter == std::numeric_limits<s32>::max() - 1 || +        touch_ref_counter == std::numeric_limits<s32>::max() - 1) { +        return ResultTouchOverflow; +    } + +    if (global_ref_counter == 0) { +        std::scoped_lock lock{*shared_mutex}; + +        const auto result = touch_driver->StartTouchSensor(); +        if (result.IsError()) { +            return result; +        } + +        is_initalized = true; +        system.CoreTiming().ScheduleLoopingEvent(GestureUpdatePeriod, GestureUpdatePeriod, +                                                 timer_event); +        current_touch_state = {}; +        ReadTouchInput(); +        gesture_handler.SetTouchState(current_touch_state.states, current_touch_state.entry_count, +                                      0); +    } + +    Set::TouchScreenMode touch_mode{Set::TouchScreenMode::Standard}; +    m_set_sys->GetTouchScreenMode(touch_mode); +    default_touch_screen_mode = static_cast<Core::HID::TouchScreenModeForNx>(touch_mode); + +    global_ref_counter++; +    touch_ref_counter++; +    return ResultSuccess; +} + +Result TouchResource::ActivateTouch(u64 aruid) { +    std::scoped_lock lock{*shared_mutex}; + +    for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { +        auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); +        TouchAruidData& touch_data = aruid_data[aruid_index]; + +        if (!applet_data->flag.is_assigned) { +            touch_data = {}; +            continue; +        } + +        const u64 aruid_id = applet_data->aruid; +        if (touch_data.aruid != aruid_id) { +            touch_data = {}; +            touch_data.aruid = aruid_id; +        } + +        if (aruid != aruid_id) { +            continue; +        } + +        auto& touch_shared = applet_data->shared_memory_format->touch_screen; + +        if (touch_shared.touch_screen_lifo.buffer_count == 0) { +            StorePreviousTouchState(previous_touch_state, touch_data.finger_map, +                                    current_touch_state, +                                    applet_data->flag.enable_touchscreen.Value() != 0); +            touch_shared.touch_screen_lifo.WriteNextEntry(previous_touch_state); +        } +    } +    return ResultSuccess; +} + +Result TouchResource::ActivateGesture() { +    if (global_ref_counter == std::numeric_limits<s32>::max() - 1 || +        gesture_ref_counter == std::numeric_limits<s32>::max() - 1) { +        return ResultGestureOverflow; +    } + +    // Initialize first instance +    if (global_ref_counter == 0) { +        const auto result = touch_driver->StartTouchSensor(); +        if (result.IsError()) { +            return result; +        } + +        is_initalized = true; +        system.CoreTiming().ScheduleLoopingEvent(GestureUpdatePeriod, GestureUpdatePeriod, +                                                 timer_event); +        current_touch_state = {}; +        ReadTouchInput(); +        gesture_handler.SetTouchState(current_touch_state.states, current_touch_state.entry_count, +                                      0); +    } + +    global_ref_counter++; +    gesture_ref_counter++; +    return ResultSuccess; +} + +Result TouchResource::ActivateGesture(u64 aruid, u32 basic_gesture_id) { +    std::scoped_lock lock{*shared_mutex}; + +    for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { +        auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); +        TouchAruidData& touch_data = aruid_data[aruid_index]; + +        if (!applet_data->flag.is_assigned) { +            touch_data = {}; +            continue; +        } + +        const u64 aruid_id = applet_data->aruid; +        if (touch_data.aruid != aruid_id) { +            touch_data = {}; +            touch_data.aruid = aruid_id; +        } + +        if (aruid != aruid_id) { +            continue; +        } + +        auto& gesture_shared = applet_data->shared_memory_format->gesture; +        if (touch_data.basic_gesture_id != basic_gesture_id) { +            gesture_shared.gesture_lifo.buffer_count = 0; +        } + +        if (gesture_shared.gesture_lifo.buffer_count == 0) { +            touch_data.basic_gesture_id = basic_gesture_id; + +            gesture_shared.gesture_lifo.WriteNextEntry(gesture_state); +        } +    } + +    return ResultSuccess; +} + +Result TouchResource::DeactivateTouch() { +    if (touch_ref_counter == 0 || global_ref_counter == 0) { +        return ResultTouchNotInitialized; +    } + +    global_ref_counter--; +    touch_ref_counter--; + +    if (touch_ref_counter + global_ref_counter != 0) { +        return ResultSuccess; +    } + +    return Finalize(); +} + +Result TouchResource::DeactivateGesture() { +    if (gesture_ref_counter == 0 || global_ref_counter == 0) { +        return ResultGestureNotInitialized; +    } + +    global_ref_counter--; +    gesture_ref_counter--; + +    if (touch_ref_counter + global_ref_counter != 0) { +        return ResultSuccess; +    } + +    return Finalize(); +} + +bool TouchResource::IsTouchActive() const { +    return touch_ref_counter != 0; +} + +bool TouchResource::IsGestureActive() const { +    return gesture_ref_counter != 0; +} + +void TouchResource::SetTouchDriver(std::shared_ptr<TouchDriver> driver) { +    touch_driver = driver; +} + +void TouchResource::SetAppletResource(std::shared_ptr<AppletResource> shared, +                                      std::recursive_mutex* mutex) { +    applet_resource = shared; +    shared_mutex = mutex; +} + +void TouchResource::SetInputEvent(Kernel::KEvent* event, std::mutex* mutex) { +    input_event = event; +    input_mutex = mutex; +} + +void TouchResource::SetHandheldConfig(std::shared_ptr<HandheldConfig> config) { +    handheld_config = config; +} + +void TouchResource::SetTimerEvent(std::shared_ptr<Core::Timing::EventType> event) { +    timer_event = event; +} + +Result TouchResource::SetTouchScreenAutoPilotState(const AutoPilotState& auto_pilot_state) { +    if (global_ref_counter == 0) { +        return ResultTouchNotInitialized; +    } + +    if (!is_auto_pilot_initialized) { +        is_auto_pilot_initialized = true; +        auto_pilot = {}; +    } + +    TouchScreenState state = { +        .entry_count = static_cast<s32>(auto_pilot_state.count), +        .states = auto_pilot_state.state, +    }; + +    SanitizeInput(state); + +    auto_pilot.count = state.entry_count; +    auto_pilot.state = state.states; +    return ResultSuccess; +} + +Result TouchResource::UnsetTouchScreenAutoPilotState() { +    if (global_ref_counter == 0) { +        return ResultTouchNotInitialized; +    } + +    is_auto_pilot_initialized = false; +    auto_pilot = {}; +    return ResultSuccess; +} + +Result TouchResource::RequestNextTouchInput() { +    if (global_ref_counter == 0) { +        return ResultTouchNotInitialized; +    } + +    if (handheld_config->is_handheld_hid_enabled) { +        const Result result = touch_driver->WaitForInput(); +        if (result.IsError()) { +            return result; +        } +    } + +    is_initalized = true; +    return ResultSuccess; +} + +Result TouchResource::RequestNextDummyInput() { +    if (global_ref_counter == 0) { +        return ResultTouchNotInitialized; +    } + +    if (handheld_config->is_handheld_hid_enabled) { +        const Result result = touch_driver->WaitForDummyInput(); +        if (result.IsError()) { +            return result; +        } +    } + +    is_initalized = false; +    return ResultSuccess; +} + +Result TouchResource::ProcessTouchScreenAutoTune() { +    touch_driver->ProcessTouchScreenAutoTune(); +    return ResultSuccess; +} + +void TouchResource::SetTouchScreenMagnification(f32 point1_x, f32 point1_y, f32 point2_x, +                                                f32 point2_y) { +    offset = { +        .x = point1_x, +        .y = point1_y, +    }; +    magnification = { +        .x = point2_x, +        .y = point2_y, +    }; +} + +Result TouchResource::SetTouchScreenResolution(u32 width, u32 height, u64 aruid) { +    std::scoped_lock lock{*shared_mutex}; + +    for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { +        const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); +        TouchAruidData& data = aruid_data[aruid_index]; + +        if (!applet_data->flag.is_assigned) { +            continue; +        } +        if (aruid != data.aruid) { +            continue; +        } +        data.resolution_width = static_cast<u16>(width); +        data.resolution_height = static_cast<u16>(height); +    } + +    return ResultSuccess; +} + +Result TouchResource::SetTouchScreenConfiguration( +    const Core::HID::TouchScreenConfigurationForNx& touch_configuration, u64 aruid) { +    std::scoped_lock lock{*shared_mutex}; + +    for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { +        const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); +        TouchAruidData& data = aruid_data[aruid_index]; + +        if (!applet_data->flag.is_assigned) { +            continue; +        } +        if (aruid != data.aruid) { +            continue; +        } +        data.finger_map.touch_mode = touch_configuration.mode; +    } + +    return ResultSuccess; +} + +Result TouchResource::GetTouchScreenConfiguration( +    Core::HID::TouchScreenConfigurationForNx& out_touch_configuration, u64 aruid) const { +    std::scoped_lock lock{*shared_mutex}; + +    for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { +        const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); +        const TouchAruidData& data = aruid_data[aruid_index]; + +        if (!applet_data->flag.is_assigned) { +            continue; +        } +        if (aruid != data.aruid) { +            continue; +        } +        out_touch_configuration.mode = data.finger_map.touch_mode; +    } + +    return ResultSuccess; +} + +Result TouchResource::SetTouchScreenDefaultConfiguration( +    const Core::HID::TouchScreenConfigurationForNx& touch_configuration) { +    default_touch_screen_mode = touch_configuration.mode; +    return ResultSuccess; +} + +Result TouchResource::GetTouchScreenDefaultConfiguration( +    Core::HID::TouchScreenConfigurationForNx& out_touch_configuration) const { +    out_touch_configuration.mode = default_touch_screen_mode; +    return ResultSuccess; +} + +Result TouchResource::Finalize() { +    is_auto_pilot_initialized = false; +    auto_pilot = {}; +    system.CoreTiming().UnscheduleEvent(timer_event); + +    const auto result = touch_driver->StopTouchSensor(); +    if (result.IsError()) { +        return result; +    } + +    is_initalized = false; +    return ResultSuccess; +} + +void TouchResource::StorePreviousTouchState(TouchScreenState& out_previous_touch, +                                            TouchFingerMap& out_finger_map, +                                            const TouchScreenState& current_touch, +                                            bool is_touch_enabled) const { +    s32 finger_count{}; + +    if (is_touch_enabled) { +        finger_count = current_touch.entry_count; +        if (finger_count < 1) { +            out_finger_map.finger_count = 0; +            out_finger_map.finger_ids = {}; +            out_previous_touch.sampling_number = current_touch.sampling_number; +            out_previous_touch.entry_count = 0; +            out_previous_touch.states = {}; +            return; +        } +        for (std::size_t i = 0; i < static_cast<u32>(finger_count); i++) { +            out_finger_map.finger_ids[i] = current_touch.states[i].finger; +            out_previous_touch.states[i] = current_touch.states[i]; +        } +        out_finger_map.finger_count = finger_count; +        return; +    } + +    if (!is_touch_enabled && out_finger_map.finger_count > 0 && current_touch.entry_count > 0) { +        // TODO +    } + +    // Zero out unused entries +    for (std::size_t i = finger_count; i < MaxFingers; i++) { +        out_finger_map.finger_ids[i] = 0; +        out_previous_touch.states[i] = {}; +    } + +    out_previous_touch.sampling_number = current_touch.sampling_number; +    out_previous_touch.entry_count = finger_count; +} + +void TouchResource::ReadTouchInput() { +    previous_touch_state = current_touch_state; + +    if (!is_initalized || !handheld_config->is_handheld_hid_enabled || !touch_driver->IsRunning()) { +        touch_driver->WaitForDummyInput(); +    } else { +        touch_driver->WaitForInput(); +    } + +    touch_driver->GetNextTouchState(current_touch_state); +    SanitizeInput(current_touch_state); +    current_touch_state.sampling_number = sample_number; +    sample_number++; + +    if (is_auto_pilot_initialized && current_touch_state.entry_count == 0) { +        const std::size_t finger_count = static_cast<std::size_t>(auto_pilot.count); +        current_touch_state.entry_count = static_cast<s32>(finger_count); +        for (std::size_t i = 0; i < finger_count; i++) { +            current_touch_state.states[i] = auto_pilot.state[i]; +        } + +        std::size_t index = 0; +        for (std::size_t i = 0; i < finger_count; i++) { +            if (auto_pilot.state[i].attribute.end_touch) { +                continue; +            } +            auto_pilot.state[i].attribute.raw = 0; +            auto_pilot.state[index] = auto_pilot.state[i]; +            index++; +        } + +        auto_pilot.count = index; +        for (std::size_t i = index; i < auto_pilot.state.size(); i++) { +            auto_pilot.state[i] = {}; +        } +    } + +    for (std::size_t i = 0; i < static_cast<std::size_t>(current_touch_state.entry_count); i++) { +        auto& state = current_touch_state.states[i]; +        state.position.x = static_cast<u32>((magnification.y * static_cast<f32>(state.position.x)) + +                                            (offset.x * static_cast<f32>(TouchSensorWidth))); +        state.position.y = static_cast<u32>((magnification.y * static_cast<f32>(state.position.y)) + +                                            (offset.x * static_cast<f32>(TouchSensorHeight))); +        state.diameter_x = static_cast<u32>(magnification.x * static_cast<f32>(state.diameter_x)); +        state.diameter_y = static_cast<u32>(magnification.y * static_cast<f32>(state.diameter_y)); +    } + +    std::size_t index = 0; +    for (std::size_t i = 0; i < static_cast<std::size_t>(current_touch_state.entry_count); i++) { +        const auto& old_state = current_touch_state.states[i]; +        auto& state = current_touch_state.states[index]; +        if ((TouchSensorWidth <= old_state.position.x) || +            (TouchSensorHeight <= old_state.position.y)) { +            continue; +        } +        state = old_state; +        index++; +    } +    current_touch_state.entry_count = static_cast<s32>(index); + +    SanitizeInput(current_touch_state); + +    std::scoped_lock lock{*input_mutex}; +    if (current_touch_state.entry_count == previous_touch_state.entry_count) { +        if (current_touch_state.entry_count < 1) { +            return; +        } +        bool has_moved = false; +        for (std::size_t i = 0; i < static_cast<std::size_t>(current_touch_state.entry_count); +             i++) { +            s32 delta_x = std::abs(static_cast<s32>(current_touch_state.states[i].position.x) - +                                   static_cast<s32>(previous_touch_state.states[i].position.x)); +            s32 delta_y = std::abs(static_cast<s32>(current_touch_state.states[i].position.y) - +                                   static_cast<s32>(previous_touch_state.states[i].position.y)); +            if (delta_x > 1 || delta_y > 1) { +                has_moved = true; +            } +        } +        if (!has_moved) { +            return; +        } +    } + +    input_event->Signal(); +} + +void TouchResource::OnTouchUpdate(s64 timestamp) { +    if (global_ref_counter == 0) { +        return; +    } + +    ReadTouchInput(); +    gesture_handler.SetTouchState(current_touch_state.states, current_touch_state.entry_count, +                                  timestamp); + +    std::scoped_lock lock{*shared_mutex}; + +    for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { +        const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); +        TouchAruidData& data = aruid_data[aruid_index]; + +        if (applet_data == nullptr || !applet_data->flag.is_assigned) { +            data = {}; +            continue; +        } + +        if (data.aruid != applet_data->aruid) { +            data = {}; +            data.aruid = applet_data->aruid; +        } + +        if (gesture_ref_counter != 0) { +            if (!applet_data->flag.enable_touchscreen) { +                gesture_state = {}; +            } +            if (gesture_handler.NeedsUpdate()) { +                gesture_handler.UpdateGestureState(gesture_state, timestamp); +                auto& gesture_shared = applet_data->shared_memory_format->gesture; +                gesture_shared.gesture_lifo.WriteNextEntry(gesture_state); +            } +        } + +        if (touch_ref_counter != 0) { +            auto touch_mode = data.finger_map.touch_mode; +            if (touch_mode == Core::HID::TouchScreenModeForNx::UseSystemSetting) { +                touch_mode = default_touch_screen_mode; +            } + +            if (applet_resource->GetActiveAruid() == applet_data->aruid && +                touch_mode != Core::HID::TouchScreenModeForNx::UseSystemSetting && is_initalized && +                handheld_config->is_handheld_hid_enabled && touch_driver->IsRunning()) { +                touch_driver->SetTouchMode(touch_mode); +            } + +            auto& touch_shared = applet_data->shared_memory_format->touch_screen; +            StorePreviousTouchState(previous_touch_state, data.finger_map, current_touch_state, +                                    applet_data->flag.enable_touchscreen.As<bool>()); +            touch_shared.touch_screen_lifo.WriteNextEntry(current_touch_state); +        } +    } +} + +void TouchResource::SanitizeInput(TouchScreenState& state) const { +    for (std::size_t i = 0; i < static_cast<std::size_t>(state.entry_count); i++) { +        auto& entry = state.states[i]; +        entry.position.x = +            std::clamp(entry.position.x, TouchBorders, TouchSensorWidth - TouchBorders - 1); +        entry.position.y = +            std::clamp(entry.position.y, TouchBorders, TouchSensorHeight - TouchBorders - 1); +        entry.diameter_x = std::clamp(entry.diameter_x, 0u, TouchSensorWidth - MaxTouchDiameter); +        entry.diameter_y = std::clamp(entry.diameter_y, 0u, TouchSensorHeight - MaxTouchDiameter); +        entry.rotation_angle = +            std::clamp(entry.rotation_angle, -MaxRotationAngle, MaxRotationAngle); +    } +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <array> +#include <mutex> + +#include "common/common_types.h" +#include "common/point.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" +#include "hid_core/resources/touch_screen/gesture_handler.h" +#include "hid_core/resources/touch_screen/touch_types.h" + +namespace Core { +class System; +} + +namespace Core::Timing { +struct EventType; +} + +namespace Kernel { +class KEvent; +} // namespace Kernel + +namespace Service::Set { +class ISystemSettingsServer; +} + +namespace Service::HID { +class AppletResource; +class TouchSharedMemoryManager; +class TouchDriver; +struct HandheldConfig; + +class TouchResource { +public: +    TouchResource(Core::System& system_); +    ~TouchResource(); + +    Result ActivateTouch(); +    Result ActivateTouch(u64 aruid); + +    Result ActivateGesture(); +    Result ActivateGesture(u64 aruid, u32 basic_gesture_id); + +    Result DeactivateTouch(); +    Result DeactivateGesture(); + +    bool IsTouchActive() const; +    bool IsGestureActive() const; + +    void SetTouchDriver(std::shared_ptr<TouchDriver> driver); +    void SetAppletResource(std::shared_ptr<AppletResource> shared, std::recursive_mutex* mutex); +    void SetInputEvent(Kernel::KEvent* event, std::mutex* mutex); +    void SetHandheldConfig(std::shared_ptr<HandheldConfig> config); +    void SetTimerEvent(std::shared_ptr<Core::Timing::EventType> event); + +    Result SetTouchScreenAutoPilotState(const AutoPilotState& auto_pilot_state); +    Result UnsetTouchScreenAutoPilotState(); + +    Result RequestNextTouchInput(); +    Result RequestNextDummyInput(); + +    Result ProcessTouchScreenAutoTune(); +    void SetTouchScreenMagnification(f32 point1_x, f32 point1_y, f32 point2_x, f32 point2_y); +    Result SetTouchScreenResolution(u32 width, u32 height, u64 aruid); + +    Result SetTouchScreenConfiguration( +        const Core::HID::TouchScreenConfigurationForNx& touch_configuration, u64 aruid); +    Result GetTouchScreenConfiguration( +        Core::HID::TouchScreenConfigurationForNx& out_touch_configuration, u64 aruid) const; + +    Result SetTouchScreenDefaultConfiguration( +        const Core::HID::TouchScreenConfigurationForNx& touch_configuration); +    Result GetTouchScreenDefaultConfiguration( +        Core::HID::TouchScreenConfigurationForNx& out_touch_configuration) const; + +    void OnTouchUpdate(s64 timestamp); + +private: +    Result Finalize(); + +    void StorePreviousTouchState(TouchScreenState& out_previous_touch, +                                 TouchFingerMap& out_finger_map, +                                 const TouchScreenState& current_touch, +                                 bool is_touch_enabled) const; +    void ReadTouchInput(); + +    void SanitizeInput(TouchScreenState& state) const; + +    s32 global_ref_counter{}; +    s32 gesture_ref_counter{}; +    s32 touch_ref_counter{}; +    bool is_initalized{}; +    u64 sample_number{}; + +    // External resources +    std::shared_ptr<Core::Timing::EventType> timer_event{nullptr}; +    std::shared_ptr<TouchDriver> touch_driver{nullptr}; +    std::shared_ptr<AppletResource> applet_resource{nullptr}; +    std::recursive_mutex* shared_mutex{nullptr}; +    std::shared_ptr<HandheldConfig> handheld_config{nullptr}; +    Kernel::KEvent* input_event{nullptr}; +    std::mutex* input_mutex{nullptr}; + +    // Internal state +    TouchScreenState current_touch_state{}; +    TouchScreenState previous_touch_state{}; +    GestureState gesture_state{}; +    bool is_auto_pilot_initialized{}; +    AutoPilotState auto_pilot{}; +    GestureHandler gesture_handler{}; +    std::array<TouchAruidData, 0x20> aruid_data{}; +    Common::Point<f32> magnification{1.0f, 1.0f}; +    Common::Point<f32> offset{0.0f, 0.0f}; +    Core::HID::TouchScreenModeForNx default_touch_screen_mode{ +        Core::HID::TouchScreenModeForNx::Finger}; + +    Core::System& system; +    std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; +}; + +} // 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 @@  #include "hid_core/hid_types.h"  namespace Service::HID { -static constexpr std::size_t MAX_FINGERS = 16; -static constexpr size_t MAX_POINTS = 4; +constexpr std::size_t MaxFingers = 16; +constexpr std::size_t MaxPoints = 4; +constexpr u32 TouchSensorWidth = 1280; +constexpr u32 TouchSensorHeight = 720; +constexpr s32 MaxRotationAngle = 270; +constexpr u32 MaxTouchDiameter = 30; +constexpr u32 TouchBorders = 15; + +// HW is around 700, value is set to 400 to make it easier to trigger with mouse +constexpr f32 SwipeThreshold = 400.0f; // Threshold in pixels/s +constexpr f32 AngleThreshold = 0.015f; // Threshold in radians +constexpr f32 PinchThreshold = 0.5f;   // Threshold in pixels +constexpr f32 PressDelay = 0.5f;       // Time in seconds +constexpr f32 DoubleTapDelay = 0.35f;  // Time in seconds  // This is nn::hid::GestureType  enum class GestureType : u32 { @@ -28,6 +40,7 @@ enum class GestureType : u32 {      Swipe,    // Fast press movement and release of a single point      Pinch,    // All points moving away/closer to the midpoint      Rotate,   // All points rotating from the midpoint +    GestureTypeMax = Rotate,  };  // This is nn::hid::GestureDirection @@ -69,7 +82,7 @@ struct GestureState {  static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");  struct GestureProperties { -    std::array<Common::Point<s32>, MAX_POINTS> points{}; +    std::array<Common::Point<s32>, MaxPoints> points{};      std::size_t active_points{};      Common::Point<s32> mid_point{};      s64 detection_count{}; @@ -78,13 +91,53 @@ struct GestureProperties {      f32 angle{};  }; +// This is nn::hid::TouchState +struct TouchState { +    u64 delta_time{}; +    Core::HID::TouchAttribute attribute{}; +    u32 finger{}; +    Common::Point<u32> position{}; +    u32 diameter_x{}; +    u32 diameter_y{}; +    s32 rotation_angle{}; +}; +static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); +  // This is nn::hid::TouchScreenState  struct TouchScreenState {      s64 sampling_number{};      s32 entry_count{};      INSERT_PADDING_BYTES(4); // Reserved -    std::array<Core::HID::TouchState, MAX_FINGERS> states{}; +    std::array<TouchState, MaxFingers> states{};  };  static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); +struct TouchFingerMap { +    s32 finger_count{}; +    Core::HID::TouchScreenModeForNx touch_mode; +    INSERT_PADDING_BYTES(3); +    std::array<u32, MaxFingers> finger_ids{}; +}; +static_assert(sizeof(TouchFingerMap) == 0x48, "TouchFingerMap is an invalid size"); + +struct TouchAruidData { +    u64 aruid; +    u32 basic_gesture_id; +    u64 used_1; +    u64 used_2; +    u64 used_3; +    u64 used_4; +    GestureType gesture_type; +    u16 resolution_width; +    u16 resolution_height; +    TouchFingerMap finger_map; +}; +static_assert(sizeof(TouchAruidData) == 0x80, "TouchAruidData is an invalid size"); + +struct AutoPilotState { +    u64 count; +    std::array<TouchState, 16> state; +}; +static_assert(sizeof(AutoPilotState) == 0x288, "AutoPilotState is an invalid size"); +  } // namespace Service::HID | 
