diff options
| -rw-r--r-- | src/core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/software_keyboard.cpp | 1067 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/software_keyboard.h | 138 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/software_keyboard_types.h | 295 |
4 files changed, 1488 insertions, 13 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 286e912e3..532e418b0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -273,6 +273,7 @@ add_library(core STATIC | |||
| 273 | hle/service/am/applets/profile_select.h | 273 | hle/service/am/applets/profile_select.h |
| 274 | hle/service/am/applets/software_keyboard.cpp | 274 | hle/service/am/applets/software_keyboard.cpp |
| 275 | hle/service/am/applets/software_keyboard.h | 275 | hle/service/am/applets/software_keyboard.h |
| 276 | hle/service/am/applets/software_keyboard_types.h | ||
| 276 | hle/service/am/applets/web_browser.cpp | 277 | hle/service/am/applets/web_browser.cpp |
| 277 | hle/service/am/applets/web_browser.h | 278 | hle/service/am/applets/web_browser.h |
| 278 | hle/service/am/applets/web_types.h | 279 | hle/service/am/applets/web_types.h |
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index f966cf67b..c3a05de9c 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp | |||
| @@ -1,7 +1,8 @@ | |||
| 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 "common/string_util.h" | ||
| 5 | #include "core/core.h" | 6 | #include "core/core.h" |
| 6 | #include "core/frontend/applets/software_keyboard.h" | 7 | #include "core/frontend/applets/software_keyboard.h" |
| 7 | #include "core/hle/service/am/am.h" | 8 | #include "core/hle/service/am/am.h" |
| @@ -9,20 +10,1068 @@ | |||
| 9 | 10 | ||
| 10 | namespace Service::AM::Applets { | 11 | namespace Service::AM::Applets { |
| 11 | 12 | ||
| 12 | SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, | 13 | namespace { |
| 13 | const Core::Frontend::SoftwareKeyboardApplet& frontend_) | 14 | |
| 14 | : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} | 15 | // The maximum number of UTF-16 characters that can be input into the swkbd text field. |
| 16 | constexpr u32 DEFAULT_MAX_TEXT_LENGTH = 500; | ||
| 17 | |||
| 18 | constexpr std::size_t REPLY_BASE_SIZE = sizeof(SwkbdState) + sizeof(SwkbdReplyType); | ||
| 19 | constexpr std::size_t REPLY_UTF8_SIZE = 0x7D4; | ||
| 20 | constexpr std::size_t REPLY_UTF16_SIZE = 0x3EC; | ||
| 21 | |||
| 22 | constexpr const char* GetTextCheckResultName(SwkbdTextCheckResult text_check_result) { | ||
| 23 | switch (text_check_result) { | ||
| 24 | case SwkbdTextCheckResult::Success: | ||
| 25 | return "Success"; | ||
| 26 | case SwkbdTextCheckResult::Failure: | ||
| 27 | return "Failure"; | ||
| 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 | |||
| 43 | } // Anonymous namespace | ||
| 44 | |||
| 45 | SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, | ||
| 46 | Core::Frontend::SoftwareKeyboardApplet& frontend_) | ||
| 47 | : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {} | ||
| 15 | 48 | ||
| 16 | SoftwareKeyboard::~SoftwareKeyboard() = default; | 49 | SoftwareKeyboard::~SoftwareKeyboard() = default; |
| 17 | 50 | ||
| 18 | void SoftwareKeyboard::Initialize() {} | 51 | void SoftwareKeyboard::Initialize() { |
| 52 | Applet::Initialize(); | ||
| 53 | |||
| 54 | LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}", | ||
| 55 | applet_mode); | ||
| 56 | |||
| 57 | LOG_DEBUG(Service_AM, | ||
| 58 | "Initializing Applet with common_args: arg_version={}, lib_version={}, " | ||
| 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); | ||
| 63 | |||
| 64 | swkbd_applet_version = SwkbdAppletVersion{common_args.library_version}; | ||
| 65 | |||
| 66 | switch (applet_mode) { | ||
| 67 | case LibraryAppletMode::AllForeground: | ||
| 68 | InitializeForeground(); | ||
| 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 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | bool SoftwareKeyboard::TransactionComplete() const { | ||
| 81 | return complete; | ||
| 82 | } | ||
| 83 | |||
| 84 | ResultCode SoftwareKeyboard::GetStatus() const { | ||
| 85 | return status; | ||
| 86 | } | ||
| 87 | |||
| 88 | void SoftwareKeyboard::ExecuteInteractive() { | ||
| 89 | if (complete) { | ||
| 90 | return; | ||
| 91 | } | ||
| 92 | |||
| 93 | if (is_background) { | ||
| 94 | ProcessInlineKeyboardRequest(); | ||
| 95 | } else { | ||
| 96 | ProcessTextCheck(); | ||
| 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 | } | ||
| 111 | |||
| 112 | void SoftwareKeyboard::SubmitTextNormal(SwkbdResult result, std::u16string submitted_text) { | ||
| 113 | if (complete) { | ||
| 114 | return; | ||
| 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; | ||
| 137 | break; | ||
| 138 | case SwkbdReplyType::MovedCursor: | ||
| 139 | reply_type = SwkbdReplyType::MovedCursorUtf8; | ||
| 140 | break; | ||
| 141 | case SwkbdReplyType::DecidedEnter: | ||
| 142 | reply_type = SwkbdReplyType::DecidedEnterUtf8; | ||
| 143 | break; | ||
| 144 | default: | ||
| 145 | break; | ||
| 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; | ||
| 157 | default: | ||
| 158 | break; | ||
| 159 | } | ||
| 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); | ||
| 176 | } | ||
| 177 | |||
| 178 | void SoftwareKeyboard::InitializeForeground() { | ||
| 179 | LOG_INFO(Service_AM, "Initializing Normal Software Keyboard Applet."); | ||
| 180 | |||
| 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(); | ||
| 225 | return; | ||
| 226 | } | ||
| 227 | |||
| 228 | const auto& work_buffer = work_buffer_storage->GetData(); | ||
| 229 | |||
| 230 | std::vector<char16_t> initial_string(swkbd_config_common.initial_string_length); | ||
| 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; | ||
| 296 | } | ||
| 297 | } | ||
| 298 | |||
| 299 | void SoftwareKeyboard::ProcessInlineKeyboardRequest() { | ||
| 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)); | ||
| 305 | |||
| 306 | SwkbdRequestCommand request_command; | ||
| 307 | |||
| 308 | std::memcpy(&request_command, request_data.data(), sizeof(SwkbdRequestCommand)); | ||
| 309 | |||
| 310 | switch (request_command) { | ||
| 311 | case SwkbdRequestCommand::Finalize: | ||
| 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 | } | ||
| 340 | |||
| 341 | void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result, | ||
| 342 | std::u16string submitted_text) { | ||
| 343 | std::vector<u8> out_data(sizeof(SwkbdResult) + STRING_BUFFER_SIZE); | ||
| 344 | |||
| 345 | if (swkbd_config_common.use_utf8) { | ||
| 346 | std::string utf8_submitted_text = Common::UTF16ToUTF8(submitted_text); | ||
| 347 | |||
| 348 | LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-8 Submitted Text: {}", result, | ||
| 349 | utf8_submitted_text); | ||
| 350 | |||
| 351 | std::memcpy(out_data.data(), &result, sizeof(SwkbdResult)); | ||
| 352 | std::memcpy(out_data.data() + sizeof(SwkbdResult), utf8_submitted_text.data(), | ||
| 353 | utf8_submitted_text.size()); | ||
| 354 | } else { | ||
| 355 | LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-16 Submitted Text: {}", result, | ||
| 356 | Common::UTF16ToUTF8(submitted_text)); | ||
| 357 | |||
| 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(); | ||
| 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))); | ||
| 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); | ||
| 19 | 1060 | ||
| 20 | bool SoftwareKeyboard::TransactionComplete() const {} | 1061 | const SwkbdMovedCursorArg moved_cursor_arg{ |
| 1062 | .text_length{static_cast<u32>(current_text.size())}, | ||
| 1063 | .cursor_position{current_cursor_position}, | ||
| 1064 | }; | ||
| 21 | 1065 | ||
| 22 | ResultCode SoftwareKeyboard::GetStatus() const {} | 1066 | constexpr u8 flag = 0; |
| 23 | 1067 | ||
| 24 | void SoftwareKeyboard::ExecuteInteractive() {} | 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); | ||
| 25 | 1073 | ||
| 26 | void SoftwareKeyboard::Execute() {} | 1074 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); |
| 1075 | } | ||
| 27 | 1076 | ||
| 28 | } // 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 c161ec9ac..85aeb4eb1 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h | |||
| @@ -1,4 +1,4 @@ | |||
| 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 | ||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "core/hle/result.h" | 9 | #include "core/hle/result.h" |
| 10 | #include "core/hle/service/am/applets/applets.h" | 10 | #include "core/hle/service/am/applets/applets.h" |
| 11 | #include "core/hle/service/am/applets/software_keyboard_types.h" | ||
| 11 | 12 | ||
| 12 | namespace Core { | 13 | namespace Core { |
| 13 | class System; | 14 | class System; |
| @@ -17,8 +18,8 @@ namespace Service::AM::Applets { | |||
| 17 | 18 | ||
| 18 | class SoftwareKeyboard final : public Applet { | 19 | class SoftwareKeyboard final : public Applet { |
| 19 | public: | 20 | public: |
| 20 | explicit SoftwareKeyboard(Core::System& system_, | 21 | explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, |
| 21 | const Core::Frontend::SoftwareKeyboardApplet& frontend_); | 22 | Core::Frontend::SoftwareKeyboardApplet& frontend_); |
| 22 | ~SoftwareKeyboard() override; | 23 | ~SoftwareKeyboard() override; |
| 23 | 24 | ||
| 24 | void Initialize() override; | 25 | void Initialize() override; |
| @@ -28,10 +29,139 @@ public: | |||
| 28 | void ExecuteInteractive() override; | 29 | void ExecuteInteractive() override; |
| 29 | void Execute() override; | 30 | void Execute() override; |
| 30 | 31 | ||
| 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); | ||
| 54 | |||
| 31 | private: | 55 | private: |
| 32 | const Core::Frontend::SoftwareKeyboardApplet& frontend; | 56 | /// Initializes the normal software keyboard. |
| 57 | void InitializeForeground(); | ||
| 58 | |||
| 59 | /// Initializes the inline software keyboard. | ||
| 60 | void InitializeBackground(LibraryAppletMode applet_mode); | ||
| 61 | |||
| 62 | /// Processes the text check sent by the application. | ||
| 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(); | ||
| 33 | 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; | ||
| 34 | 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}; | ||
| 35 | }; | 165 | }; |
| 36 | 166 | ||
| 37 | } // 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 | ||