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