diff options
Diffstat (limited to 'src/core/hle')
19 files changed, 1584 insertions, 234 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 161d9f782..2b363b1d9 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -75,10 +75,14 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_ | |||
| 75 | if (incoming) { | 75 | if (incoming) { |
| 76 | // Populate the object lists with the data in the IPC request. | 76 | // Populate the object lists with the data in the IPC request. |
| 77 | for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { | 77 | for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { |
| 78 | copy_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>())); | 78 | const u32 copy_handle{rp.Pop<Handle>()}; |
| 79 | copy_handles.push_back(copy_handle); | ||
| 80 | copy_objects.push_back(handle_table.GetGeneric(copy_handle)); | ||
| 79 | } | 81 | } |
| 80 | for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { | 82 | for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { |
| 81 | move_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>())); | 83 | const u32 move_handle{rp.Pop<Handle>()}; |
| 84 | move_handles.push_back(move_handle); | ||
| 85 | move_objects.push_back(handle_table.GetGeneric(move_handle)); | ||
| 82 | } | 86 | } |
| 83 | } else { | 87 | } else { |
| 84 | // For responses we just ignore the handles, they're empty and will be populated when | 88 | // For responses we just ignore the handles, they're empty and will be populated when |
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 9a769781b..6fba42615 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -210,6 +210,14 @@ public: | |||
| 210 | /// Helper function to test whether the output buffer at buffer_index can be written | 210 | /// Helper function to test whether the output buffer at buffer_index can be written |
| 211 | bool CanWriteBuffer(std::size_t buffer_index = 0) const; | 211 | bool CanWriteBuffer(std::size_t buffer_index = 0) const; |
| 212 | 212 | ||
| 213 | Handle GetCopyHandle(std::size_t index) const { | ||
| 214 | return copy_handles.at(index); | ||
| 215 | } | ||
| 216 | |||
| 217 | Handle GetMoveHandle(std::size_t index) const { | ||
| 218 | return move_handles.at(index); | ||
| 219 | } | ||
| 220 | |||
| 213 | template <typename T> | 221 | template <typename T> |
| 214 | std::shared_ptr<T> GetCopyObject(std::size_t index) { | 222 | std::shared_ptr<T> GetCopyObject(std::size_t index) { |
| 215 | return DynamicObjectCast<T>(copy_objects.at(index)); | 223 | return DynamicObjectCast<T>(copy_objects.at(index)); |
| @@ -285,6 +293,8 @@ private: | |||
| 285 | std::shared_ptr<Kernel::ServerSession> server_session; | 293 | std::shared_ptr<Kernel::ServerSession> server_session; |
| 286 | std::shared_ptr<KThread> thread; | 294 | std::shared_ptr<KThread> thread; |
| 287 | // TODO(yuriks): Check common usage of this and optimize size accordingly | 295 | // TODO(yuriks): Check common usage of this and optimize size accordingly |
| 296 | boost::container::small_vector<Handle, 8> move_handles; | ||
| 297 | boost::container::small_vector<Handle, 8> copy_handles; | ||
| 288 | boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects; | 298 | boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects; |
| 289 | boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects; | 299 | boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects; |
| 290 | boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; | 300 | boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 416c5239a..c59054468 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -971,7 +971,7 @@ private: | |||
| 971 | 971 | ||
| 972 | auto storage = applet->GetBroker().PopNormalDataToGame(); | 972 | auto storage = applet->GetBroker().PopNormalDataToGame(); |
| 973 | if (storage == nullptr) { | 973 | if (storage == nullptr) { |
| 974 | LOG_ERROR(Service_AM, | 974 | LOG_DEBUG(Service_AM, |
| 975 | "storage is a nullptr. There is no data in the current normal channel"); | 975 | "storage is a nullptr. There is no data in the current normal channel"); |
| 976 | IPC::ResponseBuilder rb{ctx, 2}; | 976 | IPC::ResponseBuilder rb{ctx, 2}; |
| 977 | rb.Push(ERR_NO_DATA_IN_CHANNEL); | 977 | rb.Push(ERR_NO_DATA_IN_CHANNEL); |
| @@ -1002,7 +1002,7 @@ private: | |||
| 1002 | 1002 | ||
| 1003 | auto storage = applet->GetBroker().PopInteractiveDataToGame(); | 1003 | auto storage = applet->GetBroker().PopInteractiveDataToGame(); |
| 1004 | if (storage == nullptr) { | 1004 | if (storage == nullptr) { |
| 1005 | LOG_ERROR(Service_AM, | 1005 | LOG_DEBUG(Service_AM, |
| 1006 | "storage is a nullptr. There is no data in the current interactive channel"); | 1006 | "storage is a nullptr. There is no data in the current interactive channel"); |
| 1007 | IPC::ResponseBuilder rb{ctx, 2}; | 1007 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1008 | rb.Push(ERR_NO_DATA_IN_CHANNEL); | 1008 | rb.Push(ERR_NO_DATA_IN_CHANNEL); |
| @@ -1125,7 +1125,7 @@ ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_) | |||
| 1125 | {2, nullptr, "AreAnyLibraryAppletsLeft"}, | 1125 | {2, nullptr, "AreAnyLibraryAppletsLeft"}, |
| 1126 | {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, | 1126 | {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, |
| 1127 | {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"}, | 1127 | {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"}, |
| 1128 | {12, nullptr, "CreateHandleStorage"}, | 1128 | {12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"}, |
| 1129 | }; | 1129 | }; |
| 1130 | RegisterHandlers(functions); | 1130 | RegisterHandlers(functions); |
| 1131 | } | 1131 | } |
| @@ -1134,14 +1134,15 @@ ILibraryAppletCreator::~ILibraryAppletCreator() = default; | |||
| 1134 | 1134 | ||
| 1135 | void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { | 1135 | void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { |
| 1136 | IPC::RequestParser rp{ctx}; | 1136 | IPC::RequestParser rp{ctx}; |
| 1137 | |||
| 1137 | const auto applet_id = rp.PopRaw<Applets::AppletId>(); | 1138 | const auto applet_id = rp.PopRaw<Applets::AppletId>(); |
| 1138 | const auto applet_mode = rp.PopRaw<u32>(); | 1139 | const auto applet_mode = rp.PopRaw<Applets::LibraryAppletMode>(); |
| 1139 | 1140 | ||
| 1140 | LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, | 1141 | LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, |
| 1141 | applet_mode); | 1142 | applet_mode); |
| 1142 | 1143 | ||
| 1143 | const auto& applet_manager{system.GetAppletManager()}; | 1144 | const auto& applet_manager{system.GetAppletManager()}; |
| 1144 | const auto applet = applet_manager.GetApplet(applet_id); | 1145 | const auto applet = applet_manager.GetApplet(applet_id, applet_mode); |
| 1145 | 1146 | ||
| 1146 | if (applet == nullptr) { | 1147 | if (applet == nullptr) { |
| 1147 | LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); | 1148 | LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); |
| @@ -1159,9 +1160,18 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) | |||
| 1159 | 1160 | ||
| 1160 | void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { | 1161 | void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { |
| 1161 | IPC::RequestParser rp{ctx}; | 1162 | IPC::RequestParser rp{ctx}; |
| 1162 | const u64 size{rp.Pop<u64>()}; | 1163 | |
| 1164 | const s64 size{rp.Pop<s64>()}; | ||
| 1165 | |||
| 1163 | LOG_DEBUG(Service_AM, "called, size={}", size); | 1166 | LOG_DEBUG(Service_AM, "called, size={}", size); |
| 1164 | 1167 | ||
| 1168 | if (size <= 0) { | ||
| 1169 | LOG_ERROR(Service_AM, "size is less than or equal to 0"); | ||
| 1170 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1171 | rb.Push(RESULT_UNKNOWN); | ||
| 1172 | return; | ||
| 1173 | } | ||
| 1174 | |||
| 1165 | std::vector<u8> buffer(size); | 1175 | std::vector<u8> buffer(size); |
| 1166 | 1176 | ||
| 1167 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1177 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| @@ -1170,18 +1180,65 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { | |||
| 1170 | } | 1180 | } |
| 1171 | 1181 | ||
| 1172 | void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { | 1182 | void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { |
| 1173 | LOG_DEBUG(Service_AM, "called"); | 1183 | IPC::RequestParser rp{ctx}; |
| 1184 | |||
| 1185 | struct Parameters { | ||
| 1186 | u8 permissions; | ||
| 1187 | s64 size; | ||
| 1188 | }; | ||
| 1189 | |||
| 1190 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 1191 | const auto handle{ctx.GetCopyHandle(0)}; | ||
| 1192 | |||
| 1193 | LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions, | ||
| 1194 | parameters.size, handle); | ||
| 1195 | |||
| 1196 | if (parameters.size <= 0) { | ||
| 1197 | LOG_ERROR(Service_AM, "size is less than or equal to 0"); | ||
| 1198 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1199 | rb.Push(RESULT_UNKNOWN); | ||
| 1200 | return; | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | auto transfer_mem = | ||
| 1204 | system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); | ||
| 1205 | |||
| 1206 | if (transfer_mem == nullptr) { | ||
| 1207 | LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); | ||
| 1208 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1209 | rb.Push(RESULT_UNKNOWN); | ||
| 1210 | return; | ||
| 1211 | } | ||
| 1212 | |||
| 1213 | const u8* const mem_begin = transfer_mem->GetPointer(); | ||
| 1214 | const u8* const mem_end = mem_begin + transfer_mem->GetSize(); | ||
| 1215 | std::vector<u8> memory{mem_begin, mem_end}; | ||
| 1174 | 1216 | ||
| 1217 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 1218 | rb.Push(RESULT_SUCCESS); | ||
| 1219 | rb.PushIpcInterface<IStorage>(system, std::move(memory)); | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx) { | ||
| 1175 | IPC::RequestParser rp{ctx}; | 1223 | IPC::RequestParser rp{ctx}; |
| 1176 | 1224 | ||
| 1177 | rp.SetCurrentOffset(3); | 1225 | const s64 size{rp.Pop<s64>()}; |
| 1178 | const auto handle{rp.Pop<Kernel::Handle>()}; | 1226 | const auto handle{ctx.GetCopyHandle(0)}; |
| 1227 | |||
| 1228 | LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle); | ||
| 1229 | |||
| 1230 | if (size <= 0) { | ||
| 1231 | LOG_ERROR(Service_AM, "size is less than or equal to 0"); | ||
| 1232 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1233 | rb.Push(RESULT_UNKNOWN); | ||
| 1234 | return; | ||
| 1235 | } | ||
| 1179 | 1236 | ||
| 1180 | auto transfer_mem = | 1237 | auto transfer_mem = |
| 1181 | system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); | 1238 | system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); |
| 1182 | 1239 | ||
| 1183 | if (transfer_mem == nullptr) { | 1240 | if (transfer_mem == nullptr) { |
| 1184 | LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle); | 1241 | LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); |
| 1185 | IPC::ResponseBuilder rb{ctx, 2}; | 1242 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1186 | rb.Push(RESULT_UNKNOWN); | 1243 | rb.Push(RESULT_UNKNOWN); |
| 1187 | return; | 1244 | return; |
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index f6a453ab7..aefbdf0d5 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -254,6 +254,7 @@ private: | |||
| 254 | void CreateLibraryApplet(Kernel::HLERequestContext& ctx); | 254 | void CreateLibraryApplet(Kernel::HLERequestContext& ctx); |
| 255 | void CreateStorage(Kernel::HLERequestContext& ctx); | 255 | void CreateStorage(Kernel::HLERequestContext& ctx); |
| 256 | void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); | 256 | void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); |
| 257 | void CreateHandleStorage(Kernel::HLERequestContext& ctx); | ||
| 257 | }; | 258 | }; |
| 258 | 259 | ||
| 259 | class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { | 260 | class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { |
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index e2f3b7563..5ddad851a 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp | |||
| @@ -241,31 +241,31 @@ void AppletManager::ClearAll() { | |||
| 241 | frontend = {}; | 241 | frontend = {}; |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const { | 244 | std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode mode) const { |
| 245 | switch (id) { | 245 | switch (id) { |
| 246 | case AppletId::Auth: | 246 | case AppletId::Auth: |
| 247 | return std::make_shared<Auth>(system, *frontend.parental_controls); | 247 | return std::make_shared<Auth>(system, mode, *frontend.parental_controls); |
| 248 | case AppletId::Controller: | 248 | case AppletId::Controller: |
| 249 | return std::make_shared<Controller>(system, *frontend.controller); | 249 | return std::make_shared<Controller>(system, mode, *frontend.controller); |
| 250 | case AppletId::Error: | 250 | case AppletId::Error: |
| 251 | return std::make_shared<Error>(system, *frontend.error); | 251 | return std::make_shared<Error>(system, mode, *frontend.error); |
| 252 | case AppletId::ProfileSelect: | 252 | case AppletId::ProfileSelect: |
| 253 | return std::make_shared<ProfileSelect>(system, *frontend.profile_select); | 253 | return std::make_shared<ProfileSelect>(system, mode, *frontend.profile_select); |
| 254 | case AppletId::SoftwareKeyboard: | 254 | case AppletId::SoftwareKeyboard: |
| 255 | return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard); | 255 | return std::make_shared<SoftwareKeyboard>(system, mode, *frontend.software_keyboard); |
| 256 | case AppletId::Web: | 256 | case AppletId::Web: |
| 257 | case AppletId::Shop: | 257 | case AppletId::Shop: |
| 258 | case AppletId::OfflineWeb: | 258 | case AppletId::OfflineWeb: |
| 259 | case AppletId::LoginShare: | 259 | case AppletId::LoginShare: |
| 260 | case AppletId::WebAuth: | 260 | case AppletId::WebAuth: |
| 261 | return std::make_shared<WebBrowser>(system, *frontend.web_browser); | 261 | return std::make_shared<WebBrowser>(system, mode, *frontend.web_browser); |
| 262 | case AppletId::PhotoViewer: | 262 | case AppletId::PhotoViewer: |
| 263 | return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer); | 263 | return std::make_shared<PhotoViewer>(system, mode, *frontend.photo_viewer); |
| 264 | default: | 264 | default: |
| 265 | UNIMPLEMENTED_MSG( | 265 | UNIMPLEMENTED_MSG( |
| 266 | "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", | 266 | "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", |
| 267 | static_cast<u8>(id)); | 267 | static_cast<u8>(id)); |
| 268 | return std::make_shared<StubApplet>(system, id); | 268 | return std::make_shared<StubApplet>(system, id, mode); |
| 269 | } | 269 | } |
| 270 | } | 270 | } |
| 271 | 271 | ||
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index b9a006317..26b482015 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h | |||
| @@ -62,6 +62,14 @@ enum class AppletId : u32 { | |||
| 62 | MyPage = 0x1A, | 62 | MyPage = 0x1A, |
| 63 | }; | 63 | }; |
| 64 | 64 | ||
| 65 | enum class LibraryAppletMode : u32 { | ||
| 66 | AllForeground = 0, | ||
| 67 | Background = 1, | ||
| 68 | NoUI = 2, | ||
| 69 | BackgroundIndirectDisplay = 3, | ||
| 70 | AllForegroundInitiallyHidden = 4, | ||
| 71 | }; | ||
| 72 | |||
| 65 | class AppletDataBroker final { | 73 | class AppletDataBroker final { |
| 66 | public: | 74 | public: |
| 67 | explicit AppletDataBroker(Kernel::KernelCore& kernel_); | 75 | explicit AppletDataBroker(Kernel::KernelCore& kernel_); |
| @@ -200,7 +208,7 @@ public: | |||
| 200 | void SetDefaultAppletsIfMissing(); | 208 | void SetDefaultAppletsIfMissing(); |
| 201 | void ClearAll(); | 209 | void ClearAll(); |
| 202 | 210 | ||
| 203 | std::shared_ptr<Applet> GetApplet(AppletId id) const; | 211 | std::shared_ptr<Applet> GetApplet(AppletId id, LibraryAppletMode mode) const; |
| 204 | 212 | ||
| 205 | private: | 213 | private: |
| 206 | AppletFrontendSet frontend; | 214 | AppletFrontendSet frontend; |
diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp index c2bfe698f..a33f05f97 100644 --- a/src/core/hle/service/am/applets/controller.cpp +++ b/src/core/hle/service/am/applets/controller.cpp | |||
| @@ -45,8 +45,9 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters( | |||
| 45 | }; | 45 | }; |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_) | 48 | Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_, |
| 49 | : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} | 49 | const Core::Frontend::ControllerApplet& frontend_) |
| 50 | : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {} | ||
| 50 | 51 | ||
| 51 | Controller::~Controller() = default; | 52 | Controller::~Controller() = default; |
| 52 | 53 | ||
diff --git a/src/core/hle/service/am/applets/controller.h b/src/core/hle/service/am/applets/controller.h index d4c9da7b1..07cb92bf9 100644 --- a/src/core/hle/service/am/applets/controller.h +++ b/src/core/hle/service/am/applets/controller.h | |||
| @@ -106,7 +106,8 @@ static_assert(sizeof(ControllerSupportResultInfo) == 0xC, | |||
| 106 | 106 | ||
| 107 | class Controller final : public Applet { | 107 | class Controller final : public Applet { |
| 108 | public: | 108 | public: |
| 109 | explicit Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_); | 109 | explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_, |
| 110 | const Core::Frontend::ControllerApplet& frontend_); | ||
| 110 | ~Controller() override; | 111 | ~Controller() override; |
| 111 | 112 | ||
| 112 | void Initialize() override; | 113 | void Initialize() override; |
| @@ -119,6 +120,7 @@ public: | |||
| 119 | void ConfigurationComplete(); | 120 | void ConfigurationComplete(); |
| 120 | 121 | ||
| 121 | private: | 122 | private: |
| 123 | LibraryAppletMode applet_mode; | ||
| 122 | const Core::Frontend::ControllerApplet& frontend; | 124 | const Core::Frontend::ControllerApplet& frontend; |
| 123 | Core::System& system; | 125 | Core::System& system; |
| 124 | 126 | ||
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp index 0c8b632e8..a9f0a9c95 100644 --- a/src/core/hle/service/am/applets/error.cpp +++ b/src/core/hle/service/am/applets/error.cpp | |||
| @@ -86,8 +86,9 @@ ResultCode Decode64BitError(u64 error) { | |||
| 86 | 86 | ||
| 87 | } // Anonymous namespace | 87 | } // Anonymous namespace |
| 88 | 88 | ||
| 89 | Error::Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_) | 89 | Error::Error(Core::System& system_, LibraryAppletMode applet_mode_, |
| 90 | : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} | 90 | const Core::Frontend::ErrorApplet& frontend_) |
| 91 | : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {} | ||
| 91 | 92 | ||
| 92 | Error::~Error() = default; | 93 | Error::~Error() = default; |
| 93 | 94 | ||
diff --git a/src/core/hle/service/am/applets/error.h b/src/core/hle/service/am/applets/error.h index a105cdb0c..a3e520cd4 100644 --- a/src/core/hle/service/am/applets/error.h +++ b/src/core/hle/service/am/applets/error.h | |||
| @@ -25,7 +25,8 @@ enum class ErrorAppletMode : u8 { | |||
| 25 | 25 | ||
| 26 | class Error final : public Applet { | 26 | class Error final : public Applet { |
| 27 | public: | 27 | public: |
| 28 | explicit Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_); | 28 | explicit Error(Core::System& system_, LibraryAppletMode applet_mode_, |
| 29 | const Core::Frontend::ErrorApplet& frontend_); | ||
| 29 | ~Error() override; | 30 | ~Error() override; |
| 30 | 31 | ||
| 31 | void Initialize() override; | 32 | void Initialize() override; |
| @@ -40,6 +41,7 @@ public: | |||
| 40 | private: | 41 | private: |
| 41 | union ErrorArguments; | 42 | union ErrorArguments; |
| 42 | 43 | ||
| 44 | LibraryAppletMode applet_mode; | ||
| 43 | const Core::Frontend::ErrorApplet& frontend; | 45 | const Core::Frontend::ErrorApplet& frontend; |
| 44 | ResultCode error_code = RESULT_SUCCESS; | 46 | ResultCode error_code = RESULT_SUCCESS; |
| 45 | ErrorAppletMode mode = ErrorAppletMode::ShowError; | 47 | ErrorAppletMode mode = ErrorAppletMode::ShowError; |
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp index 4d1df5cbe..71016cce7 100644 --- a/src/core/hle/service/am/applets/general_backend.cpp +++ b/src/core/hle/service/am/applets/general_backend.cpp | |||
| @@ -37,8 +37,9 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) | |||
| 37 | } | 37 | } |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | Auth::Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_) | 40 | Auth::Auth(Core::System& system_, LibraryAppletMode applet_mode_, |
| 41 | : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} | 41 | Core::Frontend::ParentalControlsApplet& frontend_) |
| 42 | : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {} | ||
| 42 | 43 | ||
| 43 | Auth::~Auth() = default; | 44 | Auth::~Auth() = default; |
| 44 | 45 | ||
| @@ -152,8 +153,9 @@ void Auth::AuthFinished(bool is_successful) { | |||
| 152 | broker.SignalStateChanged(); | 153 | broker.SignalStateChanged(); |
| 153 | } | 154 | } |
| 154 | 155 | ||
| 155 | PhotoViewer::PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_) | 156 | PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, |
| 156 | : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} | 157 | const Core::Frontend::PhotoViewerApplet& frontend_) |
| 158 | : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {} | ||
| 157 | 159 | ||
| 158 | PhotoViewer::~PhotoViewer() = default; | 160 | PhotoViewer::~PhotoViewer() = default; |
| 159 | 161 | ||
| @@ -202,8 +204,8 @@ void PhotoViewer::ViewFinished() { | |||
| 202 | broker.SignalStateChanged(); | 204 | broker.SignalStateChanged(); |
| 203 | } | 205 | } |
| 204 | 206 | ||
| 205 | StubApplet::StubApplet(Core::System& system_, AppletId id_) | 207 | StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_) |
| 206 | : Applet{system_.Kernel()}, id{id_}, system{system_} {} | 208 | : Applet{system_.Kernel()}, id{id_}, applet_mode{applet_mode_}, system{system_} {} |
| 207 | 209 | ||
| 208 | StubApplet::~StubApplet() = default; | 210 | StubApplet::~StubApplet() = default; |
| 209 | 211 | ||
diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/general_backend.h index ba76ae3d3..d9e6d4384 100644 --- a/src/core/hle/service/am/applets/general_backend.h +++ b/src/core/hle/service/am/applets/general_backend.h | |||
| @@ -20,7 +20,8 @@ enum class AuthAppletType : u32 { | |||
| 20 | 20 | ||
| 21 | class Auth final : public Applet { | 21 | class Auth final : public Applet { |
| 22 | public: | 22 | public: |
| 23 | explicit Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_); | 23 | explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_, |
| 24 | Core::Frontend::ParentalControlsApplet& frontend_); | ||
| 24 | ~Auth() override; | 25 | ~Auth() override; |
| 25 | 26 | ||
| 26 | void Initialize() override; | 27 | void Initialize() override; |
| @@ -32,6 +33,7 @@ public: | |||
| 32 | void AuthFinished(bool is_successful = true); | 33 | void AuthFinished(bool is_successful = true); |
| 33 | 34 | ||
| 34 | private: | 35 | private: |
| 36 | LibraryAppletMode applet_mode; | ||
| 35 | Core::Frontend::ParentalControlsApplet& frontend; | 37 | Core::Frontend::ParentalControlsApplet& frontend; |
| 36 | Core::System& system; | 38 | Core::System& system; |
| 37 | bool complete = false; | 39 | bool complete = false; |
| @@ -50,7 +52,8 @@ enum class PhotoViewerAppletMode : u8 { | |||
| 50 | 52 | ||
| 51 | class PhotoViewer final : public Applet { | 53 | class PhotoViewer final : public Applet { |
| 52 | public: | 54 | public: |
| 53 | explicit PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_); | 55 | explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, |
| 56 | const Core::Frontend::PhotoViewerApplet& frontend_); | ||
| 54 | ~PhotoViewer() override; | 57 | ~PhotoViewer() override; |
| 55 | 58 | ||
| 56 | void Initialize() override; | 59 | void Initialize() override; |
| @@ -62,6 +65,7 @@ public: | |||
| 62 | void ViewFinished(); | 65 | void ViewFinished(); |
| 63 | 66 | ||
| 64 | private: | 67 | private: |
| 68 | LibraryAppletMode applet_mode; | ||
| 65 | const Core::Frontend::PhotoViewerApplet& frontend; | 69 | const Core::Frontend::PhotoViewerApplet& frontend; |
| 66 | bool complete = false; | 70 | bool complete = false; |
| 67 | PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp; | 71 | PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp; |
| @@ -70,7 +74,7 @@ private: | |||
| 70 | 74 | ||
| 71 | class StubApplet final : public Applet { | 75 | class StubApplet final : public Applet { |
| 72 | public: | 76 | public: |
| 73 | explicit StubApplet(Core::System& system_, AppletId id_); | 77 | explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_); |
| 74 | ~StubApplet() override; | 78 | ~StubApplet() override; |
| 75 | 79 | ||
| 76 | void Initialize() override; | 80 | void Initialize() override; |
| @@ -82,6 +86,7 @@ public: | |||
| 82 | 86 | ||
| 83 | private: | 87 | private: |
| 84 | AppletId id; | 88 | AppletId id; |
| 89 | LibraryAppletMode applet_mode; | ||
| 85 | Core::System& system; | 90 | Core::System& system; |
| 86 | }; | 91 | }; |
| 87 | 92 | ||
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp index 77fba16c7..ab8b6fcc5 100644 --- a/src/core/hle/service/am/applets/profile_select.cpp +++ b/src/core/hle/service/am/applets/profile_select.cpp | |||
| @@ -15,9 +15,9 @@ namespace Service::AM::Applets { | |||
| 15 | 15 | ||
| 16 | constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1}; | 16 | constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1}; |
| 17 | 17 | ||
| 18 | ProfileSelect::ProfileSelect(Core::System& system_, | 18 | ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, |
| 19 | const Core::Frontend::ProfileSelectApplet& frontend_) | 19 | const Core::Frontend::ProfileSelectApplet& frontend_) |
| 20 | : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} | 20 | : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {} |
| 21 | 21 | ||
| 22 | ProfileSelect::~ProfileSelect() = default; | 22 | ProfileSelect::~ProfileSelect() = default; |
| 23 | 23 | ||
diff --git a/src/core/hle/service/am/applets/profile_select.h b/src/core/hle/service/am/applets/profile_select.h index 648d33a24..90f054030 100644 --- a/src/core/hle/service/am/applets/profile_select.h +++ b/src/core/hle/service/am/applets/profile_select.h | |||
| @@ -33,7 +33,7 @@ static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has inco | |||
| 33 | 33 | ||
| 34 | class ProfileSelect final : public Applet { | 34 | class ProfileSelect final : public Applet { |
| 35 | public: | 35 | public: |
| 36 | explicit ProfileSelect(Core::System& system_, | 36 | explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, |
| 37 | const Core::Frontend::ProfileSelectApplet& frontend_); | 37 | const Core::Frontend::ProfileSelectApplet& frontend_); |
| 38 | ~ProfileSelect() override; | 38 | ~ProfileSelect() override; |
| 39 | 39 | ||
| @@ -47,6 +47,7 @@ public: | |||
| 47 | void SelectionComplete(std::optional<Common::UUID> uuid); | 47 | void SelectionComplete(std::optional<Common::UUID> uuid); |
| 48 | 48 | ||
| 49 | private: | 49 | private: |
| 50 | LibraryAppletMode applet_mode; | ||
| 50 | const Core::Frontend::ProfileSelectApplet& frontend; | 51 | const Core::Frontend::ProfileSelectApplet& frontend; |
| 51 | 52 | ||
| 52 | UserSelectionConfig config; | 53 | UserSelectionConfig config; |
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 79b209c6b..c3a05de9c 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp | |||
| @@ -1,93 +1,80 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | 1 | // Copyright 2021 yuzu Emulator Project |
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cstring> | ||
| 6 | #include "common/assert.h" | ||
| 7 | #include "common/string_util.h" | 5 | #include "common/string_util.h" |
| 8 | #include "core/core.h" | 6 | #include "core/core.h" |
| 9 | #include "core/frontend/applets/software_keyboard.h" | 7 | #include "core/frontend/applets/software_keyboard.h" |
| 10 | #include "core/hle/result.h" | ||
| 11 | #include "core/hle/service/am/am.h" | 8 | #include "core/hle/service/am/am.h" |
| 12 | #include "core/hle/service/am/applets/software_keyboard.h" | 9 | #include "core/hle/service/am/applets/software_keyboard.h" |
| 13 | 10 | ||
| 14 | namespace Service::AM::Applets { | 11 | namespace Service::AM::Applets { |
| 15 | 12 | ||
| 16 | namespace { | 13 | namespace { |
| 17 | enum class Request : u32 { | 14 | |
| 18 | Finalize = 0x4, | 15 | // The maximum number of UTF-16 characters that can be input into the swkbd text field. |
| 19 | SetUserWordInfo = 0x6, | 16 | constexpr u32 DEFAULT_MAX_TEXT_LENGTH = 500; |
| 20 | SetCustomizeDic = 0x7, | 17 | |
| 21 | Calc = 0xa, | 18 | constexpr std::size_t REPLY_BASE_SIZE = sizeof(SwkbdState) + sizeof(SwkbdReplyType); |
| 22 | SetCustomizedDictionaries = 0xb, | 19 | constexpr std::size_t REPLY_UTF8_SIZE = 0x7D4; |
| 23 | UnsetCustomizedDictionaries = 0xc, | 20 | constexpr std::size_t REPLY_UTF16_SIZE = 0x3EC; |
| 24 | UnknownD = 0xd, | 21 | |
| 25 | UnknownE = 0xe, | 22 | constexpr const char* GetTextCheckResultName(SwkbdTextCheckResult text_check_result) { |
| 26 | }; | 23 | switch (text_check_result) { |
| 27 | constexpr std::size_t SWKBD_INLINE_INIT_SIZE = 0x8; | 24 | case SwkbdTextCheckResult::Success: |
| 28 | constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8; | 25 | return "Success"; |
| 29 | constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4; | 26 | case SwkbdTextCheckResult::Failure: |
| 30 | constexpr std::size_t DEFAULT_MAX_LENGTH = 500; | 27 | return "Failure"; |
| 31 | constexpr bool INTERACTIVE_STATUS_OK = false; | 28 | case SwkbdTextCheckResult::Confirm: |
| 29 | return "Confirm"; | ||
| 30 | case SwkbdTextCheckResult::Silent: | ||
| 31 | return "Silent"; | ||
| 32 | default: | ||
| 33 | UNIMPLEMENTED_MSG("Unknown TextCheckResult={}", text_check_result); | ||
| 34 | return "Unknown"; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | void SetReplyBase(std::vector<u8>& reply, SwkbdState state, SwkbdReplyType reply_type) { | ||
| 39 | std::memcpy(reply.data(), &state, sizeof(SwkbdState)); | ||
| 40 | std::memcpy(reply.data() + sizeof(SwkbdState), &reply_type, sizeof(SwkbdReplyType)); | ||
| 41 | } | ||
| 42 | |||
| 32 | } // Anonymous namespace | 43 | } // Anonymous namespace |
| 33 | static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( | 44 | |
| 34 | KeyboardConfig config, std::u16string initial_text) { | 45 | SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, |
| 35 | Core::Frontend::SoftwareKeyboardParameters params{}; | 46 | Core::Frontend::SoftwareKeyboardApplet& frontend_) |
| 36 | 47 | : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {} | |
| 37 | params.submit_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( | ||
| 38 | config.submit_text.data(), config.submit_text.size()); | ||
| 39 | params.header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( | ||
| 40 | config.header_text.data(), config.header_text.size()); | ||
| 41 | params.sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.sub_text.data(), | ||
| 42 | config.sub_text.size()); | ||
| 43 | params.guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.guide_text.data(), | ||
| 44 | config.guide_text.size()); | ||
| 45 | params.initial_text = std::move(initial_text); | ||
| 46 | params.max_length = config.length_limit == 0 ? DEFAULT_MAX_LENGTH : config.length_limit; | ||
| 47 | params.password = static_cast<bool>(config.is_password); | ||
| 48 | params.cursor_at_beginning = static_cast<bool>(config.initial_cursor_position); | ||
| 49 | params.value = static_cast<u8>(config.keyset_disable_bitmask); | ||
| 50 | |||
| 51 | return params; | ||
| 52 | } | ||
| 53 | |||
| 54 | SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, | ||
| 55 | const Core::Frontend::SoftwareKeyboardApplet& frontend_) | ||
| 56 | : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} | ||
| 57 | 48 | ||
| 58 | SoftwareKeyboard::~SoftwareKeyboard() = default; | 49 | SoftwareKeyboard::~SoftwareKeyboard() = default; |
| 59 | 50 | ||
| 60 | void SoftwareKeyboard::Initialize() { | 51 | void SoftwareKeyboard::Initialize() { |
| 61 | complete = false; | ||
| 62 | is_inline = false; | ||
| 63 | initial_text.clear(); | ||
| 64 | final_data.clear(); | ||
| 65 | |||
| 66 | Applet::Initialize(); | 52 | Applet::Initialize(); |
| 67 | 53 | ||
| 68 | const auto keyboard_config_storage = broker.PopNormalDataToApplet(); | 54 | LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}", |
| 69 | ASSERT(keyboard_config_storage != nullptr); | 55 | applet_mode); |
| 70 | const auto& keyboard_config = keyboard_config_storage->GetData(); | ||
| 71 | |||
| 72 | if (keyboard_config.size() == SWKBD_INLINE_INIT_SIZE) { | ||
| 73 | is_inline = true; | ||
| 74 | return; | ||
| 75 | } | ||
| 76 | |||
| 77 | ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig)); | ||
| 78 | std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig)); | ||
| 79 | 56 | ||
| 80 | const auto work_buffer_storage = broker.PopNormalDataToApplet(); | 57 | LOG_DEBUG(Service_AM, |
| 81 | ASSERT_OR_EXECUTE(work_buffer_storage != nullptr, { return; }); | 58 | "Initializing Applet with common_args: arg_version={}, lib_version={}, " |
| 82 | const auto& work_buffer = work_buffer_storage->GetData(); | 59 | "play_startup_sound={}, size={}, system_tick={}, theme_color={}", |
| 60 | common_args.arguments_version, common_args.library_version, | ||
| 61 | common_args.play_startup_sound, common_args.size, common_args.system_tick, | ||
| 62 | common_args.theme_color); | ||
| 83 | 63 | ||
| 84 | if (config.initial_string_size == 0) | 64 | swkbd_applet_version = SwkbdAppletVersion{common_args.library_version}; |
| 85 | return; | ||
| 86 | 65 | ||
| 87 | std::vector<char16_t> string(config.initial_string_size); | 66 | switch (applet_mode) { |
| 88 | std::memcpy(string.data(), work_buffer.data() + config.initial_string_offset, | 67 | case LibraryAppletMode::AllForeground: |
| 89 | string.size() * 2); | 68 | InitializeForeground(); |
| 90 | initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()); | 69 | break; |
| 70 | case LibraryAppletMode::Background: | ||
| 71 | case LibraryAppletMode::BackgroundIndirectDisplay: | ||
| 72 | InitializeBackground(applet_mode); | ||
| 73 | break; | ||
| 74 | default: | ||
| 75 | UNREACHABLE_MSG("Invalid LibraryAppletMode={}", applet_mode); | ||
| 76 | break; | ||
| 77 | } | ||
| 91 | } | 78 | } |
| 92 | 79 | ||
| 93 | bool SoftwareKeyboard::TransactionComplete() const { | 80 | bool SoftwareKeyboard::TransactionComplete() const { |
| @@ -95,106 +82,996 @@ bool SoftwareKeyboard::TransactionComplete() const { | |||
| 95 | } | 82 | } |
| 96 | 83 | ||
| 97 | ResultCode SoftwareKeyboard::GetStatus() const { | 84 | ResultCode SoftwareKeyboard::GetStatus() const { |
| 98 | return RESULT_SUCCESS; | 85 | return status; |
| 99 | } | 86 | } |
| 100 | 87 | ||
| 101 | void SoftwareKeyboard::ExecuteInteractive() { | 88 | void SoftwareKeyboard::ExecuteInteractive() { |
| 102 | if (complete) | 89 | if (complete) { |
| 103 | return; | 90 | return; |
| 91 | } | ||
| 104 | 92 | ||
| 105 | const auto storage = broker.PopInteractiveDataToApplet(); | 93 | if (is_background) { |
| 106 | ASSERT(storage != nullptr); | 94 | ProcessInlineKeyboardRequest(); |
| 107 | const auto data = storage->GetData(); | ||
| 108 | if (!is_inline) { | ||
| 109 | const auto status = static_cast<bool>(data[0]); | ||
| 110 | if (status == INTERACTIVE_STATUS_OK) { | ||
| 111 | complete = true; | ||
| 112 | } else { | ||
| 113 | std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string; | ||
| 114 | std::memcpy(string.data(), data.data() + 4, string.size() * 2); | ||
| 115 | frontend.SendTextCheckDialog( | ||
| 116 | Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), | ||
| 117 | [this] { broker.SignalStateChanged(); }); | ||
| 118 | } | ||
| 119 | } else { | 95 | } else { |
| 120 | Request request{}; | 96 | ProcessTextCheck(); |
| 121 | std::memcpy(&request, data.data(), sizeof(Request)); | 97 | } |
| 98 | } | ||
| 99 | |||
| 100 | void SoftwareKeyboard::Execute() { | ||
| 101 | if (complete) { | ||
| 102 | return; | ||
| 103 | } | ||
| 104 | |||
| 105 | if (is_background) { | ||
| 106 | return; | ||
| 107 | } | ||
| 108 | |||
| 109 | ShowNormalKeyboard(); | ||
| 110 | } | ||
| 122 | 111 | ||
| 123 | switch (request) { | 112 | void SoftwareKeyboard::SubmitTextNormal(SwkbdResult result, std::u16string submitted_text) { |
| 124 | case Request::Finalize: | 113 | if (complete) { |
| 125 | complete = true; | 114 | return; |
| 126 | broker.SignalStateChanged(); | 115 | } |
| 116 | |||
| 117 | if (swkbd_config_common.use_text_check && result == SwkbdResult::Ok) { | ||
| 118 | SubmitForTextCheck(submitted_text); | ||
| 119 | } else { | ||
| 120 | SubmitNormalOutputAndExit(result, submitted_text); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | void SoftwareKeyboard::SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text, | ||
| 125 | s32 cursor_position) { | ||
| 126 | if (complete) { | ||
| 127 | return; | ||
| 128 | } | ||
| 129 | |||
| 130 | current_text = std::move(submitted_text); | ||
| 131 | current_cursor_position = cursor_position; | ||
| 132 | |||
| 133 | if (inline_use_utf8) { | ||
| 134 | switch (reply_type) { | ||
| 135 | case SwkbdReplyType::ChangedString: | ||
| 136 | reply_type = SwkbdReplyType::ChangedStringUtf8; | ||
| 127 | break; | 137 | break; |
| 128 | case Request::Calc: { | 138 | case SwkbdReplyType::MovedCursor: |
| 129 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{1})); | 139 | reply_type = SwkbdReplyType::MovedCursorUtf8; |
| 130 | broker.SignalStateChanged(); | 140 | break; |
| 141 | case SwkbdReplyType::DecidedEnter: | ||
| 142 | reply_type = SwkbdReplyType::DecidedEnterUtf8; | ||
| 143 | break; | ||
| 144 | default: | ||
| 131 | break; | 145 | break; |
| 132 | } | 146 | } |
| 147 | } | ||
| 148 | |||
| 149 | if (use_changed_string_v2) { | ||
| 150 | switch (reply_type) { | ||
| 151 | case SwkbdReplyType::ChangedString: | ||
| 152 | reply_type = SwkbdReplyType::ChangedStringV2; | ||
| 153 | break; | ||
| 154 | case SwkbdReplyType::ChangedStringUtf8: | ||
| 155 | reply_type = SwkbdReplyType::ChangedStringUtf8V2; | ||
| 156 | break; | ||
| 133 | default: | 157 | default: |
| 134 | UNIMPLEMENTED_MSG("Request {:X} is not implemented", request); | ||
| 135 | break; | 158 | break; |
| 136 | } | 159 | } |
| 137 | } | 160 | } |
| 161 | |||
| 162 | if (use_moved_cursor_v2) { | ||
| 163 | switch (reply_type) { | ||
| 164 | case SwkbdReplyType::MovedCursor: | ||
| 165 | reply_type = SwkbdReplyType::MovedCursorV2; | ||
| 166 | break; | ||
| 167 | case SwkbdReplyType::MovedCursorUtf8: | ||
| 168 | reply_type = SwkbdReplyType::MovedCursorUtf8V2; | ||
| 169 | break; | ||
| 170 | default: | ||
| 171 | break; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | SendReply(reply_type); | ||
| 138 | } | 176 | } |
| 139 | 177 | ||
| 140 | void SoftwareKeyboard::Execute() { | 178 | void SoftwareKeyboard::InitializeForeground() { |
| 141 | if (complete) { | 179 | LOG_INFO(Service_AM, "Initializing Normal Software Keyboard Applet."); |
| 142 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); | 180 | |
| 143 | broker.SignalStateChanged(); | 181 | is_background = false; |
| 182 | |||
| 183 | const auto swkbd_config_storage = broker.PopNormalDataToApplet(); | ||
| 184 | ASSERT(swkbd_config_storage != nullptr); | ||
| 185 | |||
| 186 | const auto& swkbd_config_data = swkbd_config_storage->GetData(); | ||
| 187 | ASSERT(swkbd_config_data.size() >= sizeof(SwkbdConfigCommon)); | ||
| 188 | |||
| 189 | std::memcpy(&swkbd_config_common, swkbd_config_data.data(), sizeof(SwkbdConfigCommon)); | ||
| 190 | |||
| 191 | switch (swkbd_applet_version) { | ||
| 192 | case SwkbdAppletVersion::Version5: | ||
| 193 | case SwkbdAppletVersion::Version65542: | ||
| 194 | ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigOld)); | ||
| 195 | std::memcpy(&swkbd_config_old, swkbd_config_data.data() + sizeof(SwkbdConfigCommon), | ||
| 196 | sizeof(SwkbdConfigOld)); | ||
| 197 | break; | ||
| 198 | case SwkbdAppletVersion::Version196615: | ||
| 199 | case SwkbdAppletVersion::Version262152: | ||
| 200 | case SwkbdAppletVersion::Version327689: | ||
| 201 | ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigOld2)); | ||
| 202 | std::memcpy(&swkbd_config_old2, swkbd_config_data.data() + sizeof(SwkbdConfigCommon), | ||
| 203 | sizeof(SwkbdConfigOld2)); | ||
| 204 | break; | ||
| 205 | case SwkbdAppletVersion::Version393227: | ||
| 206 | case SwkbdAppletVersion::Version524301: | ||
| 207 | ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigNew)); | ||
| 208 | std::memcpy(&swkbd_config_new, swkbd_config_data.data() + sizeof(SwkbdConfigCommon), | ||
| 209 | sizeof(SwkbdConfigNew)); | ||
| 210 | break; | ||
| 211 | default: | ||
| 212 | UNIMPLEMENTED_MSG("Unknown SwkbdConfig revision={} with size={}", swkbd_applet_version, | ||
| 213 | swkbd_config_data.size()); | ||
| 214 | ASSERT(swkbd_config_data.size() >= sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigNew)); | ||
| 215 | std::memcpy(&swkbd_config_new, swkbd_config_data.data() + sizeof(SwkbdConfigCommon), | ||
| 216 | sizeof(SwkbdConfigNew)); | ||
| 217 | break; | ||
| 218 | } | ||
| 219 | |||
| 220 | const auto work_buffer_storage = broker.PopNormalDataToApplet(); | ||
| 221 | ASSERT(work_buffer_storage != nullptr); | ||
| 222 | |||
| 223 | if (swkbd_config_common.initial_string_length == 0) { | ||
| 224 | InitializeFrontendKeyboard(); | ||
| 144 | return; | 225 | return; |
| 145 | } | 226 | } |
| 146 | 227 | ||
| 147 | const auto parameters = ConvertToFrontendParameters(config, initial_text); | 228 | const auto& work_buffer = work_buffer_storage->GetData(); |
| 148 | if (!is_inline) { | 229 | |
| 149 | frontend.RequestText( | 230 | std::vector<char16_t> initial_string(swkbd_config_common.initial_string_length); |
| 150 | [this](std::optional<std::u16string> text) { WriteText(std::move(text)); }, parameters); | 231 | |
| 232 | std::memcpy(initial_string.data(), | ||
| 233 | work_buffer.data() + swkbd_config_common.initial_string_offset, | ||
| 234 | swkbd_config_common.initial_string_length * sizeof(char16_t)); | ||
| 235 | |||
| 236 | initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(initial_string.data(), | ||
| 237 | initial_string.size()); | ||
| 238 | |||
| 239 | LOG_DEBUG(Service_AM, "\nInitial Text: {}", Common::UTF16ToUTF8(initial_text)); | ||
| 240 | |||
| 241 | InitializeFrontendKeyboard(); | ||
| 242 | } | ||
| 243 | |||
| 244 | void SoftwareKeyboard::InitializeBackground(LibraryAppletMode applet_mode) { | ||
| 245 | LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet."); | ||
| 246 | |||
| 247 | is_background = true; | ||
| 248 | |||
| 249 | const auto swkbd_inline_initialize_arg_storage = broker.PopNormalDataToApplet(); | ||
| 250 | ASSERT(swkbd_inline_initialize_arg_storage != nullptr); | ||
| 251 | |||
| 252 | const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData(); | ||
| 253 | ASSERT(swkbd_inline_initialize_arg.size() == sizeof(SwkbdInitializeArg)); | ||
| 254 | |||
| 255 | std::memcpy(&swkbd_initialize_arg, swkbd_inline_initialize_arg.data(), | ||
| 256 | swkbd_inline_initialize_arg.size()); | ||
| 257 | |||
| 258 | if (swkbd_initialize_arg.library_applet_mode_flag) { | ||
| 259 | ASSERT(applet_mode == LibraryAppletMode::Background); | ||
| 260 | } else { | ||
| 261 | ASSERT(applet_mode == LibraryAppletMode::BackgroundIndirectDisplay); | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | void SoftwareKeyboard::ProcessTextCheck() { | ||
| 266 | const auto text_check_storage = broker.PopInteractiveDataToApplet(); | ||
| 267 | ASSERT(text_check_storage != nullptr); | ||
| 268 | |||
| 269 | const auto& text_check_data = text_check_storage->GetData(); | ||
| 270 | ASSERT(text_check_data.size() == sizeof(SwkbdTextCheck)); | ||
| 271 | |||
| 272 | SwkbdTextCheck swkbd_text_check; | ||
| 273 | |||
| 274 | std::memcpy(&swkbd_text_check, text_check_data.data(), sizeof(SwkbdTextCheck)); | ||
| 275 | |||
| 276 | std::u16string text_check_message = Common::UTF16StringFromFixedZeroTerminatedBuffer( | ||
| 277 | swkbd_text_check.text_check_message.data(), swkbd_text_check.text_check_message.size()); | ||
| 278 | |||
| 279 | LOG_INFO(Service_AM, "\nTextCheckResult: {}\nTextCheckMessage: {}", | ||
| 280 | GetTextCheckResultName(swkbd_text_check.text_check_result), | ||
| 281 | Common::UTF16ToUTF8(text_check_message)); | ||
| 282 | |||
| 283 | switch (swkbd_text_check.text_check_result) { | ||
| 284 | case SwkbdTextCheckResult::Success: | ||
| 285 | SubmitNormalOutputAndExit(SwkbdResult::Ok, current_text); | ||
| 286 | break; | ||
| 287 | case SwkbdTextCheckResult::Failure: | ||
| 288 | ShowTextCheckDialog(SwkbdTextCheckResult::Failure, text_check_message); | ||
| 289 | break; | ||
| 290 | case SwkbdTextCheckResult::Confirm: | ||
| 291 | ShowTextCheckDialog(SwkbdTextCheckResult::Confirm, text_check_message); | ||
| 292 | break; | ||
| 293 | case SwkbdTextCheckResult::Silent: | ||
| 294 | default: | ||
| 295 | break; | ||
| 151 | } | 296 | } |
| 152 | } | 297 | } |
| 153 | 298 | ||
| 154 | void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { | 299 | void SoftwareKeyboard::ProcessInlineKeyboardRequest() { |
| 155 | std::vector<u8> output_main(SWKBD_OUTPUT_BUFFER_SIZE); | 300 | const auto request_data_storage = broker.PopInteractiveDataToApplet(); |
| 301 | ASSERT(request_data_storage != nullptr); | ||
| 302 | |||
| 303 | const auto& request_data = request_data_storage->GetData(); | ||
| 304 | ASSERT(request_data.size() >= sizeof(SwkbdRequestCommand)); | ||
| 156 | 305 | ||
| 157 | if (text.has_value()) { | 306 | SwkbdRequestCommand request_command; |
| 158 | std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE); | ||
| 159 | 307 | ||
| 160 | if (config.utf_8) { | 308 | std::memcpy(&request_command, request_data.data(), sizeof(SwkbdRequestCommand)); |
| 161 | const u64 size = text->size() + sizeof(u64); | ||
| 162 | const auto new_text = Common::UTF16ToUTF8(*text); | ||
| 163 | 309 | ||
| 164 | std::memcpy(output_sub.data(), &size, sizeof(u64)); | 310 | switch (request_command) { |
| 165 | std::memcpy(output_sub.data() + 8, new_text.data(), | 311 | case SwkbdRequestCommand::Finalize: |
| 166 | std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 8)); | 312 | RequestFinalize(request_data); |
| 313 | break; | ||
| 314 | case SwkbdRequestCommand::SetUserWordInfo: | ||
| 315 | RequestSetUserWordInfo(request_data); | ||
| 316 | break; | ||
| 317 | case SwkbdRequestCommand::SetCustomizeDic: | ||
| 318 | RequestSetCustomizeDic(request_data); | ||
| 319 | break; | ||
| 320 | case SwkbdRequestCommand::Calc: | ||
| 321 | RequestCalc(request_data); | ||
| 322 | break; | ||
| 323 | case SwkbdRequestCommand::SetCustomizedDictionaries: | ||
| 324 | RequestSetCustomizedDictionaries(request_data); | ||
| 325 | break; | ||
| 326 | case SwkbdRequestCommand::UnsetCustomizedDictionaries: | ||
| 327 | RequestUnsetCustomizedDictionaries(request_data); | ||
| 328 | break; | ||
| 329 | case SwkbdRequestCommand::SetChangedStringV2Flag: | ||
| 330 | RequestSetChangedStringV2Flag(request_data); | ||
| 331 | break; | ||
| 332 | case SwkbdRequestCommand::SetMovedCursorV2Flag: | ||
| 333 | RequestSetMovedCursorV2Flag(request_data); | ||
| 334 | break; | ||
| 335 | default: | ||
| 336 | UNIMPLEMENTED_MSG("Unknown SwkbdRequestCommand={}", request_command); | ||
| 337 | break; | ||
| 338 | } | ||
| 339 | } | ||
| 167 | 340 | ||
| 168 | output_main[0] = INTERACTIVE_STATUS_OK; | 341 | void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result, |
| 169 | std::memcpy(output_main.data() + 4, new_text.data(), | 342 | std::u16string submitted_text) { |
| 170 | std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4)); | 343 | std::vector<u8> out_data(sizeof(SwkbdResult) + STRING_BUFFER_SIZE); |
| 171 | } else { | ||
| 172 | const u64 size = text->size() * 2 + sizeof(u64); | ||
| 173 | std::memcpy(output_sub.data(), &size, sizeof(u64)); | ||
| 174 | std::memcpy(output_sub.data() + 8, text->data(), | ||
| 175 | std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8)); | ||
| 176 | 344 | ||
| 177 | output_main[0] = INTERACTIVE_STATUS_OK; | 345 | if (swkbd_config_common.use_utf8) { |
| 178 | std::memcpy(output_main.data() + 4, text->data(), | 346 | std::string utf8_submitted_text = Common::UTF16ToUTF8(submitted_text); |
| 179 | std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4)); | ||
| 180 | } | ||
| 181 | 347 | ||
| 182 | complete = !config.text_check; | 348 | LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-8 Submitted Text: {}", result, |
| 183 | final_data = output_main; | 349 | utf8_submitted_text); |
| 184 | 350 | ||
| 185 | if (complete) { | 351 | std::memcpy(out_data.data(), &result, sizeof(SwkbdResult)); |
| 186 | broker.PushNormalDataFromApplet( | 352 | std::memcpy(out_data.data() + sizeof(SwkbdResult), utf8_submitted_text.data(), |
| 187 | std::make_shared<IStorage>(system, std::move(output_main))); | 353 | utf8_submitted_text.size()); |
| 188 | broker.SignalStateChanged(); | ||
| 189 | } else { | ||
| 190 | broker.PushInteractiveDataFromApplet( | ||
| 191 | std::make_shared<IStorage>(system, std::move(output_sub))); | ||
| 192 | } | ||
| 193 | } else { | 354 | } else { |
| 194 | output_main[0] = 1; | 355 | LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-16 Submitted Text: {}", result, |
| 195 | complete = true; | 356 | Common::UTF16ToUTF8(submitted_text)); |
| 196 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(output_main))); | 357 | |
| 197 | broker.SignalStateChanged(); | 358 | std::memcpy(out_data.data(), &result, sizeof(SwkbdResult)); |
| 359 | std::memcpy(out_data.data() + sizeof(SwkbdResult), submitted_text.data(), | ||
| 360 | submitted_text.size() * sizeof(char16_t)); | ||
| 361 | } | ||
| 362 | |||
| 363 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); | ||
| 364 | |||
| 365 | ExitKeyboard(); | ||
| 366 | } | ||
| 367 | |||
| 368 | void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) { | ||
| 369 | current_text = std::move(submitted_text); | ||
| 370 | |||
| 371 | std::vector<u8> out_data(sizeof(u64) + STRING_BUFFER_SIZE); | ||
| 372 | |||
| 373 | if (swkbd_config_common.use_utf8) { | ||
| 374 | std::string utf8_submitted_text = Common::UTF16ToUTF8(current_text); | ||
| 375 | const u64 buffer_size = sizeof(u64) + utf8_submitted_text.size(); | ||
| 376 | |||
| 377 | LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-8 Submitted Text: {}", buffer_size, | ||
| 378 | utf8_submitted_text); | ||
| 379 | |||
| 380 | std::memcpy(out_data.data(), &buffer_size, sizeof(u64)); | ||
| 381 | std::memcpy(out_data.data() + sizeof(u64), utf8_submitted_text.data(), | ||
| 382 | utf8_submitted_text.size()); | ||
| 383 | } else { | ||
| 384 | const u64 buffer_size = sizeof(u64) + current_text.size() * sizeof(char16_t); | ||
| 385 | |||
| 386 | LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-16 Submitted Text: {}", buffer_size, | ||
| 387 | Common::UTF16ToUTF8(current_text)); | ||
| 388 | |||
| 389 | std::memcpy(out_data.data(), &buffer_size, sizeof(u64)); | ||
| 390 | std::memcpy(out_data.data() + sizeof(u64), current_text.data(), | ||
| 391 | current_text.size() * sizeof(char16_t)); | ||
| 392 | } | ||
| 393 | |||
| 394 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); | ||
| 395 | } | ||
| 396 | |||
| 397 | void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) { | ||
| 398 | switch (reply_type) { | ||
| 399 | case SwkbdReplyType::FinishedInitialize: | ||
| 400 | ReplyFinishedInitialize(); | ||
| 401 | break; | ||
| 402 | case SwkbdReplyType::Default: | ||
| 403 | ReplyDefault(); | ||
| 404 | break; | ||
| 405 | case SwkbdReplyType::ChangedString: | ||
| 406 | ReplyChangedString(); | ||
| 407 | break; | ||
| 408 | case SwkbdReplyType::MovedCursor: | ||
| 409 | ReplyMovedCursor(); | ||
| 410 | break; | ||
| 411 | case SwkbdReplyType::MovedTab: | ||
| 412 | ReplyMovedTab(); | ||
| 413 | break; | ||
| 414 | case SwkbdReplyType::DecidedEnter: | ||
| 415 | ReplyDecidedEnter(); | ||
| 416 | break; | ||
| 417 | case SwkbdReplyType::DecidedCancel: | ||
| 418 | ReplyDecidedCancel(); | ||
| 419 | break; | ||
| 420 | case SwkbdReplyType::ChangedStringUtf8: | ||
| 421 | ReplyChangedStringUtf8(); | ||
| 422 | break; | ||
| 423 | case SwkbdReplyType::MovedCursorUtf8: | ||
| 424 | ReplyMovedCursorUtf8(); | ||
| 425 | break; | ||
| 426 | case SwkbdReplyType::DecidedEnterUtf8: | ||
| 427 | ReplyDecidedEnterUtf8(); | ||
| 428 | break; | ||
| 429 | case SwkbdReplyType::UnsetCustomizeDic: | ||
| 430 | ReplyUnsetCustomizeDic(); | ||
| 431 | break; | ||
| 432 | case SwkbdReplyType::ReleasedUserWordInfo: | ||
| 433 | ReplyReleasedUserWordInfo(); | ||
| 434 | break; | ||
| 435 | case SwkbdReplyType::UnsetCustomizedDictionaries: | ||
| 436 | ReplyUnsetCustomizedDictionaries(); | ||
| 437 | break; | ||
| 438 | case SwkbdReplyType::ChangedStringV2: | ||
| 439 | ReplyChangedStringV2(); | ||
| 440 | break; | ||
| 441 | case SwkbdReplyType::MovedCursorV2: | ||
| 442 | ReplyMovedCursorV2(); | ||
| 443 | break; | ||
| 444 | case SwkbdReplyType::ChangedStringUtf8V2: | ||
| 445 | ReplyChangedStringUtf8V2(); | ||
| 446 | break; | ||
| 447 | case SwkbdReplyType::MovedCursorUtf8V2: | ||
| 448 | ReplyMovedCursorUtf8V2(); | ||
| 449 | break; | ||
| 450 | default: | ||
| 451 | UNIMPLEMENTED_MSG("Unknown SwkbdReplyType={}", reply_type); | ||
| 452 | ReplyDefault(); | ||
| 453 | break; | ||
| 454 | } | ||
| 455 | } | ||
| 456 | |||
| 457 | void SoftwareKeyboard::ChangeState(SwkbdState state) { | ||
| 458 | swkbd_state = state; | ||
| 459 | |||
| 460 | ReplyDefault(); | ||
| 461 | } | ||
| 462 | |||
| 463 | void SoftwareKeyboard::InitializeFrontendKeyboard() { | ||
| 464 | if (is_background) { | ||
| 465 | const auto& appear_arg = swkbd_calc_arg.appear_arg; | ||
| 466 | |||
| 467 | std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( | ||
| 468 | appear_arg.ok_text.data(), appear_arg.ok_text.size()); | ||
| 469 | |||
| 470 | const u32 max_text_length = | ||
| 471 | appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH | ||
| 472 | ? appear_arg.max_text_length | ||
| 473 | : DEFAULT_MAX_TEXT_LENGTH; | ||
| 474 | |||
| 475 | const u32 min_text_length = | ||
| 476 | appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0; | ||
| 477 | |||
| 478 | const s32 initial_cursor_position = | ||
| 479 | current_cursor_position > 0 ? current_cursor_position : 0; | ||
| 480 | |||
| 481 | const auto text_draw_type = | ||
| 482 | max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box; | ||
| 483 | |||
| 484 | Core::Frontend::KeyboardInitializeParameters initialize_parameters{ | ||
| 485 | .ok_text{ok_text}, | ||
| 486 | .header_text{}, | ||
| 487 | .sub_text{}, | ||
| 488 | .guide_text{}, | ||
| 489 | .initial_text{current_text}, | ||
| 490 | .max_text_length{max_text_length}, | ||
| 491 | .min_text_length{min_text_length}, | ||
| 492 | .initial_cursor_position{initial_cursor_position}, | ||
| 493 | .type{appear_arg.type}, | ||
| 494 | .password_mode{SwkbdPasswordMode::Disabled}, | ||
| 495 | .text_draw_type{text_draw_type}, | ||
| 496 | .key_disable_flags{appear_arg.key_disable_flags}, | ||
| 497 | .use_blur_background{false}, | ||
| 498 | .enable_backspace_button{swkbd_calc_arg.enable_backspace_button}, | ||
| 499 | .enable_return_button{appear_arg.enable_return_button}, | ||
| 500 | .disable_cancel_button{appear_arg.disable_cancel_button}, | ||
| 501 | }; | ||
| 502 | |||
| 503 | frontend.InitializeKeyboard( | ||
| 504 | true, std::move(initialize_parameters), {}, | ||
| 505 | [this](SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position) { | ||
| 506 | SubmitTextInline(reply_type, submitted_text, cursor_position); | ||
| 507 | }); | ||
| 508 | } else { | ||
| 509 | std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( | ||
| 510 | swkbd_config_common.ok_text.data(), swkbd_config_common.ok_text.size()); | ||
| 511 | |||
| 512 | std::u16string header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( | ||
| 513 | swkbd_config_common.header_text.data(), swkbd_config_common.header_text.size()); | ||
| 514 | |||
| 515 | std::u16string sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( | ||
| 516 | swkbd_config_common.sub_text.data(), swkbd_config_common.sub_text.size()); | ||
| 517 | |||
| 518 | std::u16string guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( | ||
| 519 | swkbd_config_common.guide_text.data(), swkbd_config_common.guide_text.size()); | ||
| 520 | |||
| 521 | const u32 max_text_length = | ||
| 522 | swkbd_config_common.max_text_length > 0 && | ||
| 523 | swkbd_config_common.max_text_length <= DEFAULT_MAX_TEXT_LENGTH | ||
| 524 | ? swkbd_config_common.max_text_length | ||
| 525 | : DEFAULT_MAX_TEXT_LENGTH; | ||
| 526 | |||
| 527 | const u32 min_text_length = swkbd_config_common.min_text_length <= max_text_length | ||
| 528 | ? swkbd_config_common.min_text_length | ||
| 529 | : 0; | ||
| 530 | |||
| 531 | const s32 initial_cursor_position = [this] { | ||
| 532 | switch (swkbd_config_common.initial_cursor_position) { | ||
| 533 | case SwkbdInitialCursorPosition::Start: | ||
| 534 | default: | ||
| 535 | return 0; | ||
| 536 | case SwkbdInitialCursorPosition::End: | ||
| 537 | return static_cast<s32>(initial_text.size()); | ||
| 538 | } | ||
| 539 | }(); | ||
| 540 | |||
| 541 | const auto text_draw_type = [this, max_text_length] { | ||
| 542 | switch (swkbd_config_common.text_draw_type) { | ||
| 543 | case SwkbdTextDrawType::Line: | ||
| 544 | default: | ||
| 545 | return max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box; | ||
| 546 | case SwkbdTextDrawType::Box: | ||
| 547 | case SwkbdTextDrawType::DownloadCode: | ||
| 548 | return swkbd_config_common.text_draw_type; | ||
| 549 | } | ||
| 550 | }(); | ||
| 551 | |||
| 552 | const auto enable_return_button = text_draw_type == SwkbdTextDrawType::Box | ||
| 553 | ? swkbd_config_common.enable_return_button | ||
| 554 | : false; | ||
| 555 | |||
| 556 | const auto disable_cancel_button = swkbd_applet_version >= SwkbdAppletVersion::Version393227 | ||
| 557 | ? swkbd_config_new.disable_cancel_button | ||
| 558 | : false; | ||
| 559 | |||
| 560 | Core::Frontend::KeyboardInitializeParameters initialize_parameters{ | ||
| 561 | .ok_text{ok_text}, | ||
| 562 | .header_text{header_text}, | ||
| 563 | .sub_text{sub_text}, | ||
| 564 | .guide_text{guide_text}, | ||
| 565 | .initial_text{initial_text}, | ||
| 566 | .max_text_length{max_text_length}, | ||
| 567 | .min_text_length{min_text_length}, | ||
| 568 | .initial_cursor_position{initial_cursor_position}, | ||
| 569 | .type{swkbd_config_common.type}, | ||
| 570 | .password_mode{swkbd_config_common.password_mode}, | ||
| 571 | .text_draw_type{text_draw_type}, | ||
| 572 | .key_disable_flags{swkbd_config_common.key_disable_flags}, | ||
| 573 | .use_blur_background{swkbd_config_common.use_blur_background}, | ||
| 574 | .enable_backspace_button{true}, | ||
| 575 | .enable_return_button{enable_return_button}, | ||
| 576 | .disable_cancel_button{disable_cancel_button}, | ||
| 577 | }; | ||
| 578 | |||
| 579 | frontend.InitializeKeyboard(false, std::move(initialize_parameters), | ||
| 580 | [this](SwkbdResult result, std::u16string submitted_text) { | ||
| 581 | SubmitTextNormal(result, submitted_text); | ||
| 582 | }, | ||
| 583 | {}); | ||
| 584 | } | ||
| 585 | } | ||
| 586 | |||
| 587 | void SoftwareKeyboard::ShowNormalKeyboard() { | ||
| 588 | frontend.ShowNormalKeyboard(); | ||
| 589 | } | ||
| 590 | |||
| 591 | void SoftwareKeyboard::ShowTextCheckDialog(SwkbdTextCheckResult text_check_result, | ||
| 592 | std::u16string text_check_message) { | ||
| 593 | frontend.ShowTextCheckDialog(text_check_result, text_check_message); | ||
| 594 | } | ||
| 595 | |||
| 596 | void SoftwareKeyboard::ShowInlineKeyboard() { | ||
| 597 | if (swkbd_state != SwkbdState::InitializedIsHidden) { | ||
| 598 | return; | ||
| 599 | } | ||
| 600 | |||
| 601 | ChangeState(SwkbdState::InitializedIsAppearing); | ||
| 602 | |||
| 603 | const auto& appear_arg = swkbd_calc_arg.appear_arg; | ||
| 604 | |||
| 605 | const u32 max_text_length = | ||
| 606 | appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH | ||
| 607 | ? appear_arg.max_text_length | ||
| 608 | : DEFAULT_MAX_TEXT_LENGTH; | ||
| 609 | |||
| 610 | const u32 min_text_length = | ||
| 611 | appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0; | ||
| 612 | |||
| 613 | Core::Frontend::InlineAppearParameters appear_parameters{ | ||
| 614 | .max_text_length{max_text_length}, | ||
| 615 | .min_text_length{min_text_length}, | ||
| 616 | .key_top_scale_x{swkbd_calc_arg.key_top_scale_x}, | ||
| 617 | .key_top_scale_y{swkbd_calc_arg.key_top_scale_y}, | ||
| 618 | .key_top_translate_x{swkbd_calc_arg.key_top_translate_x}, | ||
| 619 | .key_top_translate_y{swkbd_calc_arg.key_top_translate_y}, | ||
| 620 | .type{appear_arg.type}, | ||
| 621 | .key_disable_flags{appear_arg.key_disable_flags}, | ||
| 622 | .key_top_as_floating{swkbd_calc_arg.key_top_as_floating}, | ||
| 623 | .enable_backspace_button{swkbd_calc_arg.enable_backspace_button}, | ||
| 624 | .enable_return_button{appear_arg.enable_return_button}, | ||
| 625 | .disable_cancel_button{appear_arg.disable_cancel_button}, | ||
| 626 | }; | ||
| 627 | |||
| 628 | frontend.ShowInlineKeyboard(std::move(appear_parameters)); | ||
| 629 | |||
| 630 | ChangeState(SwkbdState::InitializedIsShown); | ||
| 631 | } | ||
| 632 | |||
| 633 | void SoftwareKeyboard::HideInlineKeyboard() { | ||
| 634 | if (swkbd_state != SwkbdState::InitializedIsShown) { | ||
| 635 | return; | ||
| 636 | } | ||
| 637 | |||
| 638 | ChangeState(SwkbdState::InitializedIsDisappearing); | ||
| 639 | |||
| 640 | frontend.HideInlineKeyboard(); | ||
| 641 | |||
| 642 | ChangeState(SwkbdState::InitializedIsHidden); | ||
| 643 | } | ||
| 644 | |||
| 645 | void SoftwareKeyboard::InlineTextChanged() { | ||
| 646 | Core::Frontend::InlineTextParameters text_parameters{ | ||
| 647 | .input_text{current_text}, | ||
| 648 | .cursor_position{current_cursor_position}, | ||
| 649 | }; | ||
| 650 | |||
| 651 | frontend.InlineTextChanged(std::move(text_parameters)); | ||
| 652 | } | ||
| 653 | |||
| 654 | void SoftwareKeyboard::ExitKeyboard() { | ||
| 655 | complete = true; | ||
| 656 | status = RESULT_SUCCESS; | ||
| 657 | |||
| 658 | frontend.ExitKeyboard(); | ||
| 659 | |||
| 660 | broker.SignalStateChanged(); | ||
| 661 | } | ||
| 662 | |||
| 663 | // Inline Software Keyboard Requests | ||
| 664 | |||
| 665 | void SoftwareKeyboard::RequestFinalize(const std::vector<u8>& request_data) { | ||
| 666 | LOG_DEBUG(Service_AM, "Processing Request: Finalize"); | ||
| 667 | |||
| 668 | ChangeState(SwkbdState::NotInitialized); | ||
| 669 | |||
| 670 | ExitKeyboard(); | ||
| 671 | } | ||
| 672 | |||
| 673 | void SoftwareKeyboard::RequestSetUserWordInfo(const std::vector<u8>& request_data) { | ||
| 674 | LOG_WARNING(Service_AM, "SetUserWordInfo is not implemented."); | ||
| 675 | } | ||
| 676 | |||
| 677 | void SoftwareKeyboard::RequestSetCustomizeDic(const std::vector<u8>& request_data) { | ||
| 678 | LOG_WARNING(Service_AM, "SetCustomizeDic is not implemented."); | ||
| 679 | } | ||
| 680 | |||
| 681 | void SoftwareKeyboard::RequestCalc(const std::vector<u8>& request_data) { | ||
| 682 | LOG_DEBUG(Service_AM, "Processing Request: Calc"); | ||
| 683 | |||
| 684 | ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArg)); | ||
| 685 | |||
| 686 | std::memcpy(&swkbd_calc_arg, request_data.data() + sizeof(SwkbdRequestCommand), | ||
| 687 | sizeof(SwkbdCalcArg)); | ||
| 688 | |||
| 689 | if (swkbd_calc_arg.flags.set_input_text) { | ||
| 690 | current_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( | ||
| 691 | swkbd_calc_arg.input_text.data(), swkbd_calc_arg.input_text.size()); | ||
| 692 | } | ||
| 693 | |||
| 694 | if (swkbd_calc_arg.flags.set_cursor_position) { | ||
| 695 | current_cursor_position = swkbd_calc_arg.cursor_position; | ||
| 696 | } | ||
| 697 | |||
| 698 | if (swkbd_calc_arg.flags.set_utf8_mode) { | ||
| 699 | inline_use_utf8 = swkbd_calc_arg.utf8_mode; | ||
| 700 | } | ||
| 701 | |||
| 702 | if (swkbd_state <= SwkbdState::InitializedIsHidden && | ||
| 703 | swkbd_calc_arg.flags.unset_customize_dic) { | ||
| 704 | ReplyUnsetCustomizeDic(); | ||
| 198 | } | 705 | } |
| 706 | |||
| 707 | if (swkbd_state <= SwkbdState::InitializedIsHidden && | ||
| 708 | swkbd_calc_arg.flags.unset_user_word_info) { | ||
| 709 | ReplyReleasedUserWordInfo(); | ||
| 710 | } | ||
| 711 | |||
| 712 | if (swkbd_state == SwkbdState::NotInitialized && swkbd_calc_arg.flags.set_initialize_arg) { | ||
| 713 | InitializeFrontendKeyboard(); | ||
| 714 | |||
| 715 | ChangeState(SwkbdState::InitializedIsHidden); | ||
| 716 | |||
| 717 | ReplyFinishedInitialize(); | ||
| 718 | } | ||
| 719 | |||
| 720 | if (!swkbd_calc_arg.flags.set_initialize_arg && | ||
| 721 | (swkbd_calc_arg.flags.set_input_text || swkbd_calc_arg.flags.set_cursor_position)) { | ||
| 722 | InlineTextChanged(); | ||
| 723 | } | ||
| 724 | |||
| 725 | if (swkbd_state == SwkbdState::InitializedIsHidden && swkbd_calc_arg.flags.appear) { | ||
| 726 | ShowInlineKeyboard(); | ||
| 727 | return; | ||
| 728 | } | ||
| 729 | |||
| 730 | if (swkbd_state == SwkbdState::InitializedIsShown && swkbd_calc_arg.flags.disappear) { | ||
| 731 | HideInlineKeyboard(); | ||
| 732 | return; | ||
| 733 | } | ||
| 734 | } | ||
| 735 | |||
| 736 | void SoftwareKeyboard::RequestSetCustomizedDictionaries(const std::vector<u8>& request_data) { | ||
| 737 | LOG_WARNING(Service_AM, "SetCustomizedDictionaries is not implemented."); | ||
| 738 | } | ||
| 739 | |||
| 740 | void SoftwareKeyboard::RequestUnsetCustomizedDictionaries(const std::vector<u8>& request_data) { | ||
| 741 | LOG_WARNING(Service_AM, "(STUBBED) Processing Request: UnsetCustomizedDictionaries"); | ||
| 742 | |||
| 743 | ReplyUnsetCustomizedDictionaries(); | ||
| 744 | } | ||
| 745 | |||
| 746 | void SoftwareKeyboard::RequestSetChangedStringV2Flag(const std::vector<u8>& request_data) { | ||
| 747 | LOG_DEBUG(Service_AM, "Processing Request: SetChangedStringV2Flag"); | ||
| 748 | |||
| 749 | ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + 1); | ||
| 750 | |||
| 751 | std::memcpy(&use_changed_string_v2, request_data.data() + sizeof(SwkbdRequestCommand), 1); | ||
| 752 | } | ||
| 753 | |||
| 754 | void SoftwareKeyboard::RequestSetMovedCursorV2Flag(const std::vector<u8>& request_data) { | ||
| 755 | LOG_DEBUG(Service_AM, "Processing Request: SetMovedCursorV2Flag"); | ||
| 756 | |||
| 757 | ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + 1); | ||
| 758 | |||
| 759 | std::memcpy(&use_moved_cursor_v2, request_data.data() + sizeof(SwkbdRequestCommand), 1); | ||
| 760 | } | ||
| 761 | |||
| 762 | // Inline Software Keyboard Replies | ||
| 763 | |||
| 764 | void SoftwareKeyboard::ReplyFinishedInitialize() { | ||
| 765 | LOG_DEBUG(Service_AM, "Sending Reply: FinishedInitialize"); | ||
| 766 | |||
| 767 | std::vector<u8> reply(REPLY_BASE_SIZE + 1); | ||
| 768 | |||
| 769 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize); | ||
| 770 | |||
| 771 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 772 | } | ||
| 773 | |||
| 774 | void SoftwareKeyboard::ReplyDefault() { | ||
| 775 | LOG_DEBUG(Service_AM, "Sending Reply: Default"); | ||
| 776 | |||
| 777 | std::vector<u8> reply(REPLY_BASE_SIZE); | ||
| 778 | |||
| 779 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default); | ||
| 780 | |||
| 781 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 782 | } | ||
| 783 | |||
| 784 | void SoftwareKeyboard::ReplyChangedString() { | ||
| 785 | LOG_DEBUG(Service_AM, "Sending Reply: ChangedString"); | ||
| 786 | |||
| 787 | std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg)); | ||
| 788 | |||
| 789 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedString); | ||
| 790 | |||
| 791 | const SwkbdChangedStringArg changed_string_arg{ | ||
| 792 | .text_length{static_cast<u32>(current_text.size())}, | ||
| 793 | .dictionary_start_cursor_position{-1}, | ||
| 794 | .dictionary_end_cursor_position{-1}, | ||
| 795 | .cursor_position{current_cursor_position}, | ||
| 796 | }; | ||
| 797 | |||
| 798 | std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), | ||
| 799 | current_text.size() * sizeof(char16_t)); | ||
| 800 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg, | ||
| 801 | sizeof(SwkbdChangedStringArg)); | ||
| 802 | |||
| 803 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 804 | } | ||
| 805 | |||
| 806 | void SoftwareKeyboard::ReplyMovedCursor() { | ||
| 807 | LOG_DEBUG(Service_AM, "Sending Reply: MovedCursor"); | ||
| 808 | |||
| 809 | std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg)); | ||
| 810 | |||
| 811 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursor); | ||
| 812 | |||
| 813 | const SwkbdMovedCursorArg moved_cursor_arg{ | ||
| 814 | .text_length{static_cast<u32>(current_text.size())}, | ||
| 815 | .cursor_position{current_cursor_position}, | ||
| 816 | }; | ||
| 817 | |||
| 818 | std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), | ||
| 819 | current_text.size() * sizeof(char16_t)); | ||
| 820 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg, | ||
| 821 | sizeof(SwkbdMovedCursorArg)); | ||
| 822 | |||
| 823 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 824 | } | ||
| 825 | |||
| 826 | void SoftwareKeyboard::ReplyMovedTab() { | ||
| 827 | LOG_DEBUG(Service_AM, "Sending Reply: MovedTab"); | ||
| 828 | |||
| 829 | std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedTabArg)); | ||
| 830 | |||
| 831 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedTab); | ||
| 832 | |||
| 833 | const SwkbdMovedTabArg moved_tab_arg{ | ||
| 834 | .text_length{static_cast<u32>(current_text.size())}, | ||
| 835 | .cursor_position{current_cursor_position}, | ||
| 836 | }; | ||
| 837 | |||
| 838 | std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), | ||
| 839 | current_text.size() * sizeof(char16_t)); | ||
| 840 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg, | ||
| 841 | sizeof(SwkbdMovedTabArg)); | ||
| 842 | |||
| 843 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 844 | } | ||
| 845 | |||
| 846 | void SoftwareKeyboard::ReplyDecidedEnter() { | ||
| 847 | LOG_DEBUG(Service_AM, "Sending Reply: DecidedEnter"); | ||
| 848 | |||
| 849 | std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdDecidedEnterArg)); | ||
| 850 | |||
| 851 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedEnter); | ||
| 852 | |||
| 853 | const SwkbdDecidedEnterArg decided_enter_arg{ | ||
| 854 | .text_length{static_cast<u32>(current_text.size())}, | ||
| 855 | }; | ||
| 856 | |||
| 857 | std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), | ||
| 858 | current_text.size() * sizeof(char16_t)); | ||
| 859 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg, | ||
| 860 | sizeof(SwkbdDecidedEnterArg)); | ||
| 861 | |||
| 862 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 863 | |||
| 864 | HideInlineKeyboard(); | ||
| 865 | } | ||
| 866 | |||
| 867 | void SoftwareKeyboard::ReplyDecidedCancel() { | ||
| 868 | LOG_DEBUG(Service_AM, "Sending Reply: DecidedCancel"); | ||
| 869 | |||
| 870 | std::vector<u8> reply(REPLY_BASE_SIZE); | ||
| 871 | |||
| 872 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel); | ||
| 873 | |||
| 874 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 875 | |||
| 876 | HideInlineKeyboard(); | ||
| 877 | } | ||
| 878 | |||
| 879 | void SoftwareKeyboard::ReplyChangedStringUtf8() { | ||
| 880 | LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringUtf8"); | ||
| 881 | |||
| 882 | std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg)); | ||
| 883 | |||
| 884 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringUtf8); | ||
| 885 | |||
| 886 | std::string utf8_current_text = Common::UTF16ToUTF8(current_text); | ||
| 887 | |||
| 888 | const SwkbdChangedStringArg changed_string_arg{ | ||
| 889 | .text_length{static_cast<u32>(current_text.size())}, | ||
| 890 | .dictionary_start_cursor_position{-1}, | ||
| 891 | .dictionary_end_cursor_position{-1}, | ||
| 892 | .cursor_position{current_cursor_position}, | ||
| 893 | }; | ||
| 894 | |||
| 895 | std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); | ||
| 896 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg, | ||
| 897 | sizeof(SwkbdChangedStringArg)); | ||
| 898 | |||
| 899 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 199 | } | 900 | } |
| 901 | |||
| 902 | void SoftwareKeyboard::ReplyMovedCursorUtf8() { | ||
| 903 | LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorUtf8"); | ||
| 904 | |||
| 905 | std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg)); | ||
| 906 | |||
| 907 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorUtf8); | ||
| 908 | |||
| 909 | std::string utf8_current_text = Common::UTF16ToUTF8(current_text); | ||
| 910 | |||
| 911 | const SwkbdMovedCursorArg moved_cursor_arg{ | ||
| 912 | .text_length{static_cast<u32>(current_text.size())}, | ||
| 913 | .cursor_position{current_cursor_position}, | ||
| 914 | }; | ||
| 915 | |||
| 916 | std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); | ||
| 917 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg, | ||
| 918 | sizeof(SwkbdMovedCursorArg)); | ||
| 919 | |||
| 920 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 921 | } | ||
| 922 | |||
| 923 | void SoftwareKeyboard::ReplyDecidedEnterUtf8() { | ||
| 924 | LOG_DEBUG(Service_AM, "Sending Reply: DecidedEnterUtf8"); | ||
| 925 | |||
| 926 | std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdDecidedEnterArg)); | ||
| 927 | |||
| 928 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedEnterUtf8); | ||
| 929 | |||
| 930 | std::string utf8_current_text = Common::UTF16ToUTF8(current_text); | ||
| 931 | |||
| 932 | const SwkbdDecidedEnterArg decided_enter_arg{ | ||
| 933 | .text_length{static_cast<u32>(current_text.size())}, | ||
| 934 | }; | ||
| 935 | |||
| 936 | std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); | ||
| 937 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg, | ||
| 938 | sizeof(SwkbdDecidedEnterArg)); | ||
| 939 | |||
| 940 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 941 | |||
| 942 | HideInlineKeyboard(); | ||
| 943 | } | ||
| 944 | |||
| 945 | void SoftwareKeyboard::ReplyUnsetCustomizeDic() { | ||
| 946 | LOG_DEBUG(Service_AM, "Sending Reply: UnsetCustomizeDic"); | ||
| 947 | |||
| 948 | std::vector<u8> reply(REPLY_BASE_SIZE); | ||
| 949 | |||
| 950 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic); | ||
| 951 | |||
| 952 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 953 | } | ||
| 954 | |||
| 955 | void SoftwareKeyboard::ReplyReleasedUserWordInfo() { | ||
| 956 | LOG_DEBUG(Service_AM, "Sending Reply: ReleasedUserWordInfo"); | ||
| 957 | |||
| 958 | std::vector<u8> reply(REPLY_BASE_SIZE); | ||
| 959 | |||
| 960 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo); | ||
| 961 | |||
| 962 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 963 | } | ||
| 964 | |||
| 965 | void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() { | ||
| 966 | LOG_DEBUG(Service_AM, "Sending Reply: UnsetCustomizedDictionaries"); | ||
| 967 | |||
| 968 | std::vector<u8> reply(REPLY_BASE_SIZE); | ||
| 969 | |||
| 970 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries); | ||
| 971 | |||
| 972 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 973 | } | ||
| 974 | |||
| 975 | void SoftwareKeyboard::ReplyChangedStringV2() { | ||
| 976 | LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringV2"); | ||
| 977 | |||
| 978 | std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg) + 1); | ||
| 979 | |||
| 980 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringV2); | ||
| 981 | |||
| 982 | const SwkbdChangedStringArg changed_string_arg{ | ||
| 983 | .text_length{static_cast<u32>(current_text.size())}, | ||
| 984 | .dictionary_start_cursor_position{-1}, | ||
| 985 | .dictionary_end_cursor_position{-1}, | ||
| 986 | .cursor_position{current_cursor_position}, | ||
| 987 | }; | ||
| 988 | |||
| 989 | constexpr u8 flag = 0; | ||
| 990 | |||
| 991 | std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), | ||
| 992 | current_text.size() * sizeof(char16_t)); | ||
| 993 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg, | ||
| 994 | sizeof(SwkbdChangedStringArg)); | ||
| 995 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg), | ||
| 996 | &flag, 1); | ||
| 997 | |||
| 998 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 999 | } | ||
| 1000 | |||
| 1001 | void SoftwareKeyboard::ReplyMovedCursorV2() { | ||
| 1002 | LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorV2"); | ||
| 1003 | |||
| 1004 | std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg) + 1); | ||
| 1005 | |||
| 1006 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorV2); | ||
| 1007 | |||
| 1008 | const SwkbdMovedCursorArg moved_cursor_arg{ | ||
| 1009 | .text_length{static_cast<u32>(current_text.size())}, | ||
| 1010 | .cursor_position{current_cursor_position}, | ||
| 1011 | }; | ||
| 1012 | |||
| 1013 | constexpr u8 flag = 0; | ||
| 1014 | |||
| 1015 | std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(), | ||
| 1016 | current_text.size() * sizeof(char16_t)); | ||
| 1017 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg, | ||
| 1018 | sizeof(SwkbdMovedCursorArg)); | ||
| 1019 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg), | ||
| 1020 | &flag, 1); | ||
| 1021 | |||
| 1022 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | void SoftwareKeyboard::ReplyChangedStringUtf8V2() { | ||
| 1026 | LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringUtf8V2"); | ||
| 1027 | |||
| 1028 | std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg) + 1); | ||
| 1029 | |||
| 1030 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringUtf8V2); | ||
| 1031 | |||
| 1032 | std::string utf8_current_text = Common::UTF16ToUTF8(current_text); | ||
| 1033 | |||
| 1034 | const SwkbdChangedStringArg changed_string_arg{ | ||
| 1035 | .text_length{static_cast<u32>(current_text.size())}, | ||
| 1036 | .dictionary_start_cursor_position{-1}, | ||
| 1037 | .dictionary_end_cursor_position{-1}, | ||
| 1038 | .cursor_position{current_cursor_position}, | ||
| 1039 | }; | ||
| 1040 | |||
| 1041 | constexpr u8 flag = 0; | ||
| 1042 | |||
| 1043 | std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); | ||
| 1044 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg, | ||
| 1045 | sizeof(SwkbdChangedStringArg)); | ||
| 1046 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg), | ||
| 1047 | &flag, 1); | ||
| 1048 | |||
| 1049 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | void SoftwareKeyboard::ReplyMovedCursorUtf8V2() { | ||
| 1053 | LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorUtf8V2"); | ||
| 1054 | |||
| 1055 | std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg) + 1); | ||
| 1056 | |||
| 1057 | SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorUtf8V2); | ||
| 1058 | |||
| 1059 | std::string utf8_current_text = Common::UTF16ToUTF8(current_text); | ||
| 1060 | |||
| 1061 | const SwkbdMovedCursorArg moved_cursor_arg{ | ||
| 1062 | .text_length{static_cast<u32>(current_text.size())}, | ||
| 1063 | .cursor_position{current_cursor_position}, | ||
| 1064 | }; | ||
| 1065 | |||
| 1066 | constexpr u8 flag = 0; | ||
| 1067 | |||
| 1068 | std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size()); | ||
| 1069 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg, | ||
| 1070 | sizeof(SwkbdMovedCursorArg)); | ||
| 1071 | std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg), | ||
| 1072 | &flag, 1); | ||
| 1073 | |||
| 1074 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); | ||
| 1075 | } | ||
| 1076 | |||
| 200 | } // namespace Service::AM::Applets | 1077 | } // namespace Service::AM::Applets |
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index 1d260fef8..85aeb4eb1 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h | |||
| @@ -1,20 +1,14 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | 1 | // Copyright 2021 yuzu Emulator Project |
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 8 | #include <string> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "common/common_funcs.h" | 7 | #include "common/common_funcs.h" |
| 12 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 13 | #include "common/swap.h" | 9 | #include "core/hle/result.h" |
| 14 | #include "core/hle/service/am/am.h" | ||
| 15 | #include "core/hle/service/am/applets/applets.h" | 10 | #include "core/hle/service/am/applets/applets.h" |
| 16 | 11 | #include "core/hle/service/am/applets/software_keyboard_types.h" | |
| 17 | union ResultCode; | ||
| 18 | 12 | ||
| 19 | namespace Core { | 13 | namespace Core { |
| 20 | class System; | 14 | class System; |
| @@ -22,45 +16,10 @@ class System; | |||
| 22 | 16 | ||
| 23 | namespace Service::AM::Applets { | 17 | namespace Service::AM::Applets { |
| 24 | 18 | ||
| 25 | enum class KeysetDisable : u32 { | ||
| 26 | Space = 0x02, | ||
| 27 | Address = 0x04, | ||
| 28 | Percent = 0x08, | ||
| 29 | Slashes = 0x10, | ||
| 30 | Numbers = 0x40, | ||
| 31 | DownloadCode = 0x80, | ||
| 32 | }; | ||
| 33 | |||
| 34 | struct KeyboardConfig { | ||
| 35 | INSERT_PADDING_BYTES(4); | ||
| 36 | std::array<char16_t, 9> submit_text; | ||
| 37 | u16_le left_symbol_key; | ||
| 38 | u16_le right_symbol_key; | ||
| 39 | INSERT_PADDING_BYTES(1); | ||
| 40 | KeysetDisable keyset_disable_bitmask; | ||
| 41 | u32_le initial_cursor_position; | ||
| 42 | std::array<char16_t, 65> header_text; | ||
| 43 | std::array<char16_t, 129> sub_text; | ||
| 44 | std::array<char16_t, 257> guide_text; | ||
| 45 | u32_le length_limit; | ||
| 46 | INSERT_PADDING_BYTES(4); | ||
| 47 | u32_le is_password; | ||
| 48 | INSERT_PADDING_BYTES(5); | ||
| 49 | bool utf_8; | ||
| 50 | bool draw_background; | ||
| 51 | u32_le initial_string_offset; | ||
| 52 | u32_le initial_string_size; | ||
| 53 | u32_le user_dictionary_offset; | ||
| 54 | u32_le user_dictionary_size; | ||
| 55 | bool text_check; | ||
| 56 | u64_le text_check_callback; | ||
| 57 | }; | ||
| 58 | static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect size."); | ||
| 59 | |||
| 60 | class SoftwareKeyboard final : public Applet { | 19 | class SoftwareKeyboard final : public Applet { |
| 61 | public: | 20 | public: |
| 62 | explicit SoftwareKeyboard(Core::System& system_, | 21 | explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, |
| 63 | const Core::Frontend::SoftwareKeyboardApplet& frontend_); | 22 | Core::Frontend::SoftwareKeyboardApplet& frontend_); |
| 64 | ~SoftwareKeyboard() override; | 23 | ~SoftwareKeyboard() override; |
| 65 | 24 | ||
| 66 | void Initialize() override; | 25 | void Initialize() override; |
| @@ -70,17 +29,139 @@ public: | |||
| 70 | void ExecuteInteractive() override; | 29 | void ExecuteInteractive() override; |
| 71 | void Execute() override; | 30 | void Execute() override; |
| 72 | 31 | ||
| 73 | void WriteText(std::optional<std::u16string> text); | 32 | /** |
| 33 | * Submits the input text to the application. | ||
| 34 | * If text checking is enabled, the application will verify the input text. | ||
| 35 | * If use_utf8 is enabled, the input text will be converted to UTF-8 prior to being submitted. | ||
| 36 | * This should only be used by the normal software keyboard. | ||
| 37 | * | ||
| 38 | * @param result SwkbdResult enum | ||
| 39 | * @param submitted_text UTF-16 encoded string | ||
| 40 | */ | ||
| 41 | void SubmitTextNormal(SwkbdResult result, std::u16string submitted_text); | ||
| 42 | |||
| 43 | /** | ||
| 44 | * Submits the input text to the application. | ||
| 45 | * If utf8_mode is enabled, the input text will be converted to UTF-8 prior to being submitted. | ||
| 46 | * This should only be used by the inline software keyboard. | ||
| 47 | * | ||
| 48 | * @param reply_type SwkbdReplyType enum | ||
| 49 | * @param submitted_text UTF-16 encoded string | ||
| 50 | * @param cursor_position The current position of the text cursor | ||
| 51 | */ | ||
| 52 | void SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text, | ||
| 53 | s32 cursor_position); | ||
| 74 | 54 | ||
| 75 | private: | 55 | private: |
| 76 | const Core::Frontend::SoftwareKeyboardApplet& frontend; | 56 | /// Initializes the normal software keyboard. |
| 57 | void InitializeForeground(); | ||
| 77 | 58 | ||
| 78 | KeyboardConfig config; | 59 | /// Initializes the inline software keyboard. |
| 79 | std::u16string initial_text; | 60 | void InitializeBackground(LibraryAppletMode applet_mode); |
| 80 | bool complete = false; | 61 | |
| 81 | bool is_inline = false; | 62 | /// Processes the text check sent by the application. |
| 82 | std::vector<u8> final_data; | 63 | void ProcessTextCheck(); |
| 64 | |||
| 65 | /// Processes the inline software keyboard request command sent by the application. | ||
| 66 | void ProcessInlineKeyboardRequest(); | ||
| 67 | |||
| 68 | /// Submits the input text and exits the applet. | ||
| 69 | void SubmitNormalOutputAndExit(SwkbdResult result, std::u16string submitted_text); | ||
| 70 | |||
| 71 | /// Submits the input text for text checking. | ||
| 72 | void SubmitForTextCheck(std::u16string submitted_text); | ||
| 73 | |||
| 74 | /// Sends a reply to the application after processing a request command. | ||
| 75 | void SendReply(SwkbdReplyType reply_type); | ||
| 76 | |||
| 77 | /// Changes the inline keyboard state. | ||
| 78 | void ChangeState(SwkbdState state); | ||
| 79 | |||
| 80 | /** | ||
| 81 | * Signals the frontend to initialize the software keyboard with common parameters. | ||
| 82 | * This initializes either the normal software keyboard or the inline software keyboard | ||
| 83 | * depending on the state of is_background. | ||
| 84 | * Note that this does not cause the keyboard to appear. | ||
| 85 | * Use the respective Show*Keyboard() functions to cause the respective keyboards to appear. | ||
| 86 | */ | ||
| 87 | void InitializeFrontendKeyboard(); | ||
| 88 | |||
| 89 | /// Signals the frontend to show the normal software keyboard. | ||
| 90 | void ShowNormalKeyboard(); | ||
| 91 | |||
| 92 | /// Signals the frontend to show the text check dialog. | ||
| 93 | void ShowTextCheckDialog(SwkbdTextCheckResult text_check_result, | ||
| 94 | std::u16string text_check_message); | ||
| 95 | |||
| 96 | /// Signals the frontend to show the inline software keyboard. | ||
| 97 | void ShowInlineKeyboard(); | ||
| 98 | |||
| 99 | /// Signals the frontend to hide the inline software keyboard. | ||
| 100 | void HideInlineKeyboard(); | ||
| 101 | |||
| 102 | /// Signals the frontend that the current inline keyboard text has changed. | ||
| 103 | void InlineTextChanged(); | ||
| 104 | |||
| 105 | /// Signals both the frontend and application that the software keyboard is exiting. | ||
| 106 | void ExitKeyboard(); | ||
| 107 | |||
| 108 | // Inline Software Keyboard Requests | ||
| 109 | |||
| 110 | void RequestFinalize(const std::vector<u8>& request_data); | ||
| 111 | void RequestSetUserWordInfo(const std::vector<u8>& request_data); | ||
| 112 | void RequestSetCustomizeDic(const std::vector<u8>& request_data); | ||
| 113 | void RequestCalc(const std::vector<u8>& request_data); | ||
| 114 | void RequestSetCustomizedDictionaries(const std::vector<u8>& request_data); | ||
| 115 | void RequestUnsetCustomizedDictionaries(const std::vector<u8>& request_data); | ||
| 116 | void RequestSetChangedStringV2Flag(const std::vector<u8>& request_data); | ||
| 117 | void RequestSetMovedCursorV2Flag(const std::vector<u8>& request_data); | ||
| 118 | |||
| 119 | // Inline Software Keyboard Replies | ||
| 120 | |||
| 121 | void ReplyFinishedInitialize(); | ||
| 122 | void ReplyDefault(); | ||
| 123 | void ReplyChangedString(); | ||
| 124 | void ReplyMovedCursor(); | ||
| 125 | void ReplyMovedTab(); | ||
| 126 | void ReplyDecidedEnter(); | ||
| 127 | void ReplyDecidedCancel(); | ||
| 128 | void ReplyChangedStringUtf8(); | ||
| 129 | void ReplyMovedCursorUtf8(); | ||
| 130 | void ReplyDecidedEnterUtf8(); | ||
| 131 | void ReplyUnsetCustomizeDic(); | ||
| 132 | void ReplyReleasedUserWordInfo(); | ||
| 133 | void ReplyUnsetCustomizedDictionaries(); | ||
| 134 | void ReplyChangedStringV2(); | ||
| 135 | void ReplyMovedCursorV2(); | ||
| 136 | void ReplyChangedStringUtf8V2(); | ||
| 137 | void ReplyMovedCursorUtf8V2(); | ||
| 138 | |||
| 139 | LibraryAppletMode applet_mode; | ||
| 140 | Core::Frontend::SoftwareKeyboardApplet& frontend; | ||
| 83 | Core::System& system; | 141 | Core::System& system; |
| 142 | |||
| 143 | SwkbdAppletVersion swkbd_applet_version; | ||
| 144 | |||
| 145 | SwkbdConfigCommon swkbd_config_common; | ||
| 146 | SwkbdConfigOld swkbd_config_old; | ||
| 147 | SwkbdConfigOld2 swkbd_config_old2; | ||
| 148 | SwkbdConfigNew swkbd_config_new; | ||
| 149 | std::u16string initial_text; | ||
| 150 | |||
| 151 | SwkbdState swkbd_state{SwkbdState::NotInitialized}; | ||
| 152 | SwkbdInitializeArg swkbd_initialize_arg; | ||
| 153 | SwkbdCalcArg swkbd_calc_arg; | ||
| 154 | bool use_changed_string_v2{false}; | ||
| 155 | bool use_moved_cursor_v2{false}; | ||
| 156 | bool inline_use_utf8{false}; | ||
| 157 | s32 current_cursor_position{}; | ||
| 158 | |||
| 159 | std::u16string current_text; | ||
| 160 | |||
| 161 | bool is_background{false}; | ||
| 162 | |||
| 163 | bool complete{false}; | ||
| 164 | ResultCode status{RESULT_SUCCESS}; | ||
| 84 | }; | 165 | }; |
| 85 | 166 | ||
| 86 | } // namespace Service::AM::Applets | 167 | } // namespace Service::AM::Applets |
diff --git a/src/core/hle/service/am/applets/software_keyboard_types.h b/src/core/hle/service/am/applets/software_keyboard_types.h new file mode 100644 index 000000000..21aa8e800 --- /dev/null +++ b/src/core/hle/service/am/applets/software_keyboard_types.h | |||
| @@ -0,0 +1,295 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | |||
| 9 | #include "common/bit_field.h" | ||
| 10 | #include "common/common_funcs.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "common/swap.h" | ||
| 13 | |||
| 14 | namespace Service::AM::Applets { | ||
| 15 | |||
| 16 | constexpr std::size_t MAX_OK_TEXT_LENGTH = 8; | ||
| 17 | constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64; | ||
| 18 | constexpr std::size_t MAX_SUB_TEXT_LENGTH = 128; | ||
| 19 | constexpr std::size_t MAX_GUIDE_TEXT_LENGTH = 256; | ||
| 20 | constexpr std::size_t STRING_BUFFER_SIZE = 0x7D4; | ||
| 21 | |||
| 22 | enum class SwkbdAppletVersion : u32_le { | ||
| 23 | Version5 = 0x5, // 1.0.0 | ||
| 24 | Version65542 = 0x10006, // 2.0.0 - 2.3.0 | ||
| 25 | Version196615 = 0x30007, // 3.0.0 - 3.0.2 | ||
| 26 | Version262152 = 0x40008, // 4.0.0 - 4.1.0 | ||
| 27 | Version327689 = 0x50009, // 5.0.0 - 5.1.0 | ||
| 28 | Version393227 = 0x6000B, // 6.0.0 - 7.0.1 | ||
| 29 | Version524301 = 0x8000D, // 8.0.0+ | ||
| 30 | }; | ||
| 31 | |||
| 32 | enum class SwkbdType : u32 { | ||
| 33 | Normal, | ||
| 34 | NumberPad, | ||
| 35 | Qwerty, | ||
| 36 | Unknown3, | ||
| 37 | Latin, | ||
| 38 | SimplifiedChinese, | ||
| 39 | TraditionalChinese, | ||
| 40 | Korean, | ||
| 41 | }; | ||
| 42 | |||
| 43 | enum class SwkbdInitialCursorPosition : u32 { | ||
| 44 | Start, | ||
| 45 | End, | ||
| 46 | }; | ||
| 47 | |||
| 48 | enum class SwkbdPasswordMode : u32 { | ||
| 49 | Disabled, | ||
| 50 | Enabled, | ||
| 51 | }; | ||
| 52 | |||
| 53 | enum class SwkbdTextDrawType : u32 { | ||
| 54 | Line, | ||
| 55 | Box, | ||
| 56 | DownloadCode, | ||
| 57 | }; | ||
| 58 | |||
| 59 | enum class SwkbdResult : u32 { | ||
| 60 | Ok, | ||
| 61 | Cancel, | ||
| 62 | }; | ||
| 63 | |||
| 64 | enum class SwkbdTextCheckResult : u32 { | ||
| 65 | Success, | ||
| 66 | Failure, | ||
| 67 | Confirm, | ||
| 68 | Silent, | ||
| 69 | }; | ||
| 70 | |||
| 71 | enum class SwkbdState : u32 { | ||
| 72 | NotInitialized = 0x0, | ||
| 73 | InitializedIsHidden = 0x1, | ||
| 74 | InitializedIsAppearing = 0x2, | ||
| 75 | InitializedIsShown = 0x3, | ||
| 76 | InitializedIsDisappearing = 0x4, | ||
| 77 | }; | ||
| 78 | |||
| 79 | enum class SwkbdRequestCommand : u32 { | ||
| 80 | Finalize = 0x4, | ||
| 81 | SetUserWordInfo = 0x6, | ||
| 82 | SetCustomizeDic = 0x7, | ||
| 83 | Calc = 0xA, | ||
| 84 | SetCustomizedDictionaries = 0xB, | ||
| 85 | UnsetCustomizedDictionaries = 0xC, | ||
| 86 | SetChangedStringV2Flag = 0xD, | ||
| 87 | SetMovedCursorV2Flag = 0xE, | ||
| 88 | }; | ||
| 89 | |||
| 90 | enum class SwkbdReplyType : u32 { | ||
| 91 | FinishedInitialize = 0x0, | ||
| 92 | Default = 0x1, | ||
| 93 | ChangedString = 0x2, | ||
| 94 | MovedCursor = 0x3, | ||
| 95 | MovedTab = 0x4, | ||
| 96 | DecidedEnter = 0x5, | ||
| 97 | DecidedCancel = 0x6, | ||
| 98 | ChangedStringUtf8 = 0x7, | ||
| 99 | MovedCursorUtf8 = 0x8, | ||
| 100 | DecidedEnterUtf8 = 0x9, | ||
| 101 | UnsetCustomizeDic = 0xA, | ||
| 102 | ReleasedUserWordInfo = 0xB, | ||
| 103 | UnsetCustomizedDictionaries = 0xC, | ||
| 104 | ChangedStringV2 = 0xD, | ||
| 105 | MovedCursorV2 = 0xE, | ||
| 106 | ChangedStringUtf8V2 = 0xF, | ||
| 107 | MovedCursorUtf8V2 = 0x10, | ||
| 108 | }; | ||
| 109 | |||
| 110 | struct SwkbdKeyDisableFlags { | ||
| 111 | union { | ||
| 112 | u32 raw{}; | ||
| 113 | |||
| 114 | BitField<1, 1, u32> space; | ||
| 115 | BitField<2, 1, u32> at; | ||
| 116 | BitField<3, 1, u32> percent; | ||
| 117 | BitField<4, 1, u32> slash; | ||
| 118 | BitField<5, 1, u32> backslash; | ||
| 119 | BitField<6, 1, u32> numbers; | ||
| 120 | BitField<7, 1, u32> download_code; | ||
| 121 | BitField<8, 1, u32> username; | ||
| 122 | }; | ||
| 123 | }; | ||
| 124 | static_assert(sizeof(SwkbdKeyDisableFlags) == 0x4, "SwkbdKeyDisableFlags has incorrect size."); | ||
| 125 | |||
| 126 | struct SwkbdConfigCommon { | ||
| 127 | SwkbdType type{}; | ||
| 128 | std::array<char16_t, MAX_OK_TEXT_LENGTH + 1> ok_text{}; | ||
| 129 | char16_t left_optional_symbol_key{}; | ||
| 130 | char16_t right_optional_symbol_key{}; | ||
| 131 | bool use_prediction{}; | ||
| 132 | INSERT_PADDING_BYTES(1); | ||
| 133 | SwkbdKeyDisableFlags key_disable_flags{}; | ||
| 134 | SwkbdInitialCursorPosition initial_cursor_position{}; | ||
| 135 | std::array<char16_t, MAX_HEADER_TEXT_LENGTH + 1> header_text{}; | ||
| 136 | std::array<char16_t, MAX_SUB_TEXT_LENGTH + 1> sub_text{}; | ||
| 137 | std::array<char16_t, MAX_GUIDE_TEXT_LENGTH + 1> guide_text{}; | ||
| 138 | u32 max_text_length{}; | ||
| 139 | u32 min_text_length{}; | ||
| 140 | SwkbdPasswordMode password_mode{}; | ||
| 141 | SwkbdTextDrawType text_draw_type{}; | ||
| 142 | bool enable_return_button{}; | ||
| 143 | bool use_utf8{}; | ||
| 144 | bool use_blur_background{}; | ||
| 145 | INSERT_PADDING_BYTES(1); | ||
| 146 | u32 initial_string_offset{}; | ||
| 147 | u32 initial_string_length{}; | ||
| 148 | u32 user_dictionary_offset{}; | ||
| 149 | u32 user_dictionary_entries{}; | ||
| 150 | bool use_text_check{}; | ||
| 151 | INSERT_PADDING_BYTES(3); | ||
| 152 | }; | ||
| 153 | static_assert(sizeof(SwkbdConfigCommon) == 0x3D4, "SwkbdConfigCommon has incorrect size."); | ||
| 154 | |||
| 155 | #pragma pack(push, 4) | ||
| 156 | // SwkbdAppletVersion 0x5, 0x10006 | ||
| 157 | struct SwkbdConfigOld { | ||
| 158 | INSERT_PADDING_WORDS(1); | ||
| 159 | VAddr text_check_callback{}; | ||
| 160 | }; | ||
| 161 | static_assert(sizeof(SwkbdConfigOld) == 0x3E0 - sizeof(SwkbdConfigCommon), | ||
| 162 | "SwkbdConfigOld has incorrect size."); | ||
| 163 | |||
| 164 | // SwkbdAppletVersion 0x30007, 0x40008, 0x50009 | ||
| 165 | struct SwkbdConfigOld2 { | ||
| 166 | INSERT_PADDING_WORDS(1); | ||
| 167 | VAddr text_check_callback{}; | ||
| 168 | std::array<u32, 8> text_grouping{}; | ||
| 169 | }; | ||
| 170 | static_assert(sizeof(SwkbdConfigOld2) == 0x400 - sizeof(SwkbdConfigCommon), | ||
| 171 | "SwkbdConfigOld2 has incorrect size."); | ||
| 172 | |||
| 173 | // SwkbdAppletVersion 0x6000B, 0x8000D | ||
| 174 | struct SwkbdConfigNew { | ||
| 175 | std::array<u32, 8> text_grouping{}; | ||
| 176 | std::array<u64, 24> customized_dictionary_set_entries{}; | ||
| 177 | u8 total_customized_dictionary_set_entries{}; | ||
| 178 | bool disable_cancel_button{}; | ||
| 179 | INSERT_PADDING_BYTES(18); | ||
| 180 | }; | ||
| 181 | static_assert(sizeof(SwkbdConfigNew) == 0x4C8 - sizeof(SwkbdConfigCommon), | ||
| 182 | "SwkbdConfigNew has incorrect size."); | ||
| 183 | #pragma pack(pop) | ||
| 184 | |||
| 185 | struct SwkbdTextCheck { | ||
| 186 | SwkbdTextCheckResult text_check_result{}; | ||
| 187 | std::array<char16_t, STRING_BUFFER_SIZE / 2> text_check_message{}; | ||
| 188 | }; | ||
| 189 | static_assert(sizeof(SwkbdTextCheck) == 0x7D8, "SwkbdTextCheck has incorrect size."); | ||
| 190 | |||
| 191 | struct SwkbdCalcArgFlags { | ||
| 192 | union { | ||
| 193 | u64 raw{}; | ||
| 194 | |||
| 195 | BitField<0, 1, u64> set_initialize_arg; | ||
| 196 | BitField<1, 1, u64> set_volume; | ||
| 197 | BitField<2, 1, u64> appear; | ||
| 198 | BitField<3, 1, u64> set_input_text; | ||
| 199 | BitField<4, 1, u64> set_cursor_position; | ||
| 200 | BitField<5, 1, u64> set_utf8_mode; | ||
| 201 | BitField<6, 1, u64> unset_customize_dic; | ||
| 202 | BitField<7, 1, u64> disappear; | ||
| 203 | BitField<8, 1, u64> unknown; | ||
| 204 | BitField<9, 1, u64> set_key_top_translate_scale; | ||
| 205 | BitField<10, 1, u64> unset_user_word_info; | ||
| 206 | BitField<11, 1, u64> set_disable_hardware_keyboard; | ||
| 207 | }; | ||
| 208 | }; | ||
| 209 | static_assert(sizeof(SwkbdCalcArgFlags) == 0x8, "SwkbdCalcArgFlags has incorrect size."); | ||
| 210 | |||
| 211 | struct SwkbdInitializeArg { | ||
| 212 | u32 unknown{}; | ||
| 213 | bool library_applet_mode_flag{}; | ||
| 214 | bool is_above_hos_500{}; | ||
| 215 | INSERT_PADDING_BYTES(2); | ||
| 216 | }; | ||
| 217 | static_assert(sizeof(SwkbdInitializeArg) == 0x8, "SwkbdInitializeArg has incorrect size."); | ||
| 218 | |||
| 219 | struct SwkbdAppearArg { | ||
| 220 | SwkbdType type{}; | ||
| 221 | std::array<char16_t, MAX_OK_TEXT_LENGTH + 1> ok_text{}; | ||
| 222 | char16_t left_optional_symbol_key{}; | ||
| 223 | char16_t right_optional_symbol_key{}; | ||
| 224 | bool use_prediction{}; | ||
| 225 | bool disable_cancel_button{}; | ||
| 226 | SwkbdKeyDisableFlags key_disable_flags{}; | ||
| 227 | u32 max_text_length{}; | ||
| 228 | u32 min_text_length{}; | ||
| 229 | bool enable_return_button{}; | ||
| 230 | INSERT_PADDING_BYTES(3); | ||
| 231 | u32 flags{}; | ||
| 232 | INSERT_PADDING_WORDS(6); | ||
| 233 | }; | ||
| 234 | static_assert(sizeof(SwkbdAppearArg) == 0x48, "SwkbdAppearArg has incorrect size."); | ||
| 235 | |||
| 236 | struct SwkbdCalcArg { | ||
| 237 | u32 unknown{}; | ||
| 238 | u16 calc_arg_size{}; | ||
| 239 | INSERT_PADDING_BYTES(2); | ||
| 240 | SwkbdCalcArgFlags flags{}; | ||
| 241 | SwkbdInitializeArg initialize_arg{}; | ||
| 242 | f32 volume{}; | ||
| 243 | s32 cursor_position{}; | ||
| 244 | SwkbdAppearArg appear_arg{}; | ||
| 245 | std::array<char16_t, 0x1FA> input_text{}; | ||
| 246 | bool utf8_mode{}; | ||
| 247 | INSERT_PADDING_BYTES(1); | ||
| 248 | bool enable_backspace_button{}; | ||
| 249 | INSERT_PADDING_BYTES(3); | ||
| 250 | bool key_top_as_floating{}; | ||
| 251 | bool footer_scalable{}; | ||
| 252 | bool alpha_enabled_in_input_mode{}; | ||
| 253 | u8 input_mode_fade_type{}; | ||
| 254 | bool disable_touch{}; | ||
| 255 | bool disable_hardware_keyboard{}; | ||
| 256 | INSERT_PADDING_BYTES(8); | ||
| 257 | f32 key_top_scale_x{}; | ||
| 258 | f32 key_top_scale_y{}; | ||
| 259 | f32 key_top_translate_x{}; | ||
| 260 | f32 key_top_translate_y{}; | ||
| 261 | f32 key_top_bg_alpha{}; | ||
| 262 | f32 footer_bg_alpha{}; | ||
| 263 | f32 balloon_scale{}; | ||
| 264 | INSERT_PADDING_WORDS(4); | ||
| 265 | u8 se_group{}; | ||
| 266 | INSERT_PADDING_BYTES(3); | ||
| 267 | }; | ||
| 268 | static_assert(sizeof(SwkbdCalcArg) == 0x4A0, "SwkbdCalcArg has incorrect size."); | ||
| 269 | |||
| 270 | struct SwkbdChangedStringArg { | ||
| 271 | u32 text_length{}; | ||
| 272 | s32 dictionary_start_cursor_position{}; | ||
| 273 | s32 dictionary_end_cursor_position{}; | ||
| 274 | s32 cursor_position{}; | ||
| 275 | }; | ||
| 276 | static_assert(sizeof(SwkbdChangedStringArg) == 0x10, "SwkbdChangedStringArg has incorrect size."); | ||
| 277 | |||
| 278 | struct SwkbdMovedCursorArg { | ||
| 279 | u32 text_length{}; | ||
| 280 | s32 cursor_position{}; | ||
| 281 | }; | ||
| 282 | static_assert(sizeof(SwkbdMovedCursorArg) == 0x8, "SwkbdMovedCursorArg has incorrect size."); | ||
| 283 | |||
| 284 | struct SwkbdMovedTabArg { | ||
| 285 | u32 text_length{}; | ||
| 286 | s32 cursor_position{}; | ||
| 287 | }; | ||
| 288 | static_assert(sizeof(SwkbdMovedTabArg) == 0x8, "SwkbdMovedTabArg has incorrect size."); | ||
| 289 | |||
| 290 | struct SwkbdDecidedEnterArg { | ||
| 291 | u32 text_length{}; | ||
| 292 | }; | ||
| 293 | static_assert(sizeof(SwkbdDecidedEnterArg) == 0x4, "SwkbdDecidedEnterArg has incorrect size."); | ||
| 294 | |||
| 295 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 2ab420789..b28b849bc 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp | |||
| @@ -208,8 +208,9 @@ void ExtractSharedFonts(Core::System& system) { | |||
| 208 | 208 | ||
| 209 | } // namespace | 209 | } // namespace |
| 210 | 210 | ||
| 211 | WebBrowser::WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_) | 211 | WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, |
| 212 | : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {} | 212 | const Core::Frontend::WebBrowserApplet& frontend_) |
| 213 | : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend(frontend_), system{system_} {} | ||
| 213 | 214 | ||
| 214 | WebBrowser::~WebBrowser() = default; | 215 | WebBrowser::~WebBrowser() = default; |
| 215 | 216 | ||
diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h index 04c274754..5eafbae7b 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h | |||
| @@ -25,7 +25,8 @@ namespace Service::AM::Applets { | |||
| 25 | 25 | ||
| 26 | class WebBrowser final : public Applet { | 26 | class WebBrowser final : public Applet { |
| 27 | public: | 27 | public: |
| 28 | WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_); | 28 | WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, |
| 29 | const Core::Frontend::WebBrowserApplet& frontend_); | ||
| 29 | 30 | ||
| 30 | ~WebBrowser() override; | 31 | ~WebBrowser() override; |
| 31 | 32 | ||
| @@ -63,6 +64,7 @@ private: | |||
| 63 | void ExecuteWifi(); | 64 | void ExecuteWifi(); |
| 64 | void ExecuteLobby(); | 65 | void ExecuteLobby(); |
| 65 | 66 | ||
| 67 | LibraryAppletMode applet_mode; | ||
| 66 | const Core::Frontend::WebBrowserApplet& frontend; | 68 | const Core::Frontend::WebBrowserApplet& frontend; |
| 67 | 69 | ||
| 68 | bool complete{false}; | 70 | bool complete{false}; |