diff options
Diffstat (limited to 'src')
38 files changed, 8204 insertions, 496 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/frontend/applets/software_keyboard.cpp b/src/core/frontend/applets/software_keyboard.cpp index 856ed33da..12c76c9ee 100644 --- a/src/core/frontend/applets/software_keyboard.cpp +++ b/src/core/frontend/applets/software_keyboard.cpp | |||
| @@ -1,29 +1,149 @@ | |||
| 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/logging/backend.h" | 5 | #include <thread> |
| 6 | |||
| 7 | #include "common/logging/log.h" | ||
| 6 | #include "common/string_util.h" | 8 | #include "common/string_util.h" |
| 7 | #include "core/frontend/applets/software_keyboard.h" | 9 | #include "core/frontend/applets/software_keyboard.h" |
| 8 | 10 | ||
| 9 | namespace Core::Frontend { | 11 | namespace Core::Frontend { |
| 12 | |||
| 10 | SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default; | 13 | SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default; |
| 11 | 14 | ||
| 12 | void DefaultSoftwareKeyboardApplet::RequestText( | 15 | DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default; |
| 13 | std::function<void(std::optional<std::u16string>)> out, | 16 | |
| 14 | SoftwareKeyboardParameters parameters) const { | 17 | void DefaultSoftwareKeyboardApplet::InitializeKeyboard( |
| 15 | if (parameters.initial_text.empty()) | 18 | bool is_inline, KeyboardInitializeParameters initialize_parameters, |
| 16 | out(u"yuzu"); | 19 | std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> submit_normal_callback_, |
| 20 | std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> | ||
| 21 | submit_inline_callback_) { | ||
| 22 | if (is_inline) { | ||
| 23 | LOG_WARNING( | ||
| 24 | Service_AM, | ||
| 25 | "(STUBBED) called, backend requested to initialize the inline software keyboard."); | ||
| 26 | |||
| 27 | submit_inline_callback = std::move(submit_inline_callback_); | ||
| 28 | } else { | ||
| 29 | LOG_WARNING( | ||
| 30 | Service_AM, | ||
| 31 | "(STUBBED) called, backend requested to initialize the normal software keyboard."); | ||
| 32 | |||
| 33 | submit_normal_callback = std::move(submit_normal_callback_); | ||
| 34 | } | ||
| 35 | |||
| 36 | parameters = std::move(initialize_parameters); | ||
| 37 | |||
| 38 | LOG_INFO(Service_AM, | ||
| 39 | "\nKeyboardInitializeParameters:" | ||
| 40 | "\nok_text={}" | ||
| 41 | "\nheader_text={}" | ||
| 42 | "\nsub_text={}" | ||
| 43 | "\nguide_text={}" | ||
| 44 | "\ninitial_text={}" | ||
| 45 | "\nmax_text_length={}" | ||
| 46 | "\nmin_text_length={}" | ||
| 47 | "\ninitial_cursor_position={}" | ||
| 48 | "\ntype={}" | ||
| 49 | "\npassword_mode={}" | ||
| 50 | "\ntext_draw_type={}" | ||
| 51 | "\nkey_disable_flags={}" | ||
| 52 | "\nuse_blur_background={}" | ||
| 53 | "\nenable_backspace_button={}" | ||
| 54 | "\nenable_return_button={}" | ||
| 55 | "\ndisable_cancel_button={}", | ||
| 56 | Common::UTF16ToUTF8(parameters.ok_text), Common::UTF16ToUTF8(parameters.header_text), | ||
| 57 | Common::UTF16ToUTF8(parameters.sub_text), Common::UTF16ToUTF8(parameters.guide_text), | ||
| 58 | Common::UTF16ToUTF8(parameters.initial_text), parameters.max_text_length, | ||
| 59 | parameters.min_text_length, parameters.initial_cursor_position, parameters.type, | ||
| 60 | parameters.password_mode, parameters.text_draw_type, parameters.key_disable_flags.raw, | ||
| 61 | parameters.use_blur_background, parameters.enable_backspace_button, | ||
| 62 | parameters.enable_return_button, parameters.disable_cancel_button); | ||
| 63 | } | ||
| 64 | |||
| 65 | void DefaultSoftwareKeyboardApplet::ShowNormalKeyboard() const { | ||
| 66 | LOG_WARNING(Service_AM, | ||
| 67 | "(STUBBED) called, backend requested to show the normal software keyboard."); | ||
| 68 | |||
| 69 | SubmitNormalText(u"yuzu"); | ||
| 70 | } | ||
| 71 | |||
| 72 | void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog( | ||
| 73 | Service::AM::Applets::SwkbdTextCheckResult text_check_result, | ||
| 74 | std::u16string text_check_message) const { | ||
| 75 | LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog."); | ||
| 76 | } | ||
| 77 | |||
| 78 | void DefaultSoftwareKeyboardApplet::ShowInlineKeyboard( | ||
| 79 | InlineAppearParameters appear_parameters) const { | ||
| 80 | LOG_WARNING(Service_AM, | ||
| 81 | "(STUBBED) called, backend requested to show the inline software keyboard."); | ||
| 82 | |||
| 83 | LOG_INFO(Service_AM, | ||
| 84 | "\nInlineAppearParameters:" | ||
| 85 | "\nmax_text_length={}" | ||
| 86 | "\nmin_text_length={}" | ||
| 87 | "\nkey_top_scale_x={}" | ||
| 88 | "\nkey_top_scale_y={}" | ||
| 89 | "\nkey_top_translate_x={}" | ||
| 90 | "\nkey_top_translate_y={}" | ||
| 91 | "\ntype={}" | ||
| 92 | "\nkey_disable_flags={}" | ||
| 93 | "\nkey_top_as_floating={}" | ||
| 94 | "\nenable_backspace_button={}" | ||
| 95 | "\nenable_return_button={}" | ||
| 96 | "\ndisable_cancel_button={}", | ||
| 97 | appear_parameters.max_text_length, appear_parameters.min_text_length, | ||
| 98 | appear_parameters.key_top_scale_x, appear_parameters.key_top_scale_y, | ||
| 99 | appear_parameters.key_top_translate_x, appear_parameters.key_top_translate_y, | ||
| 100 | appear_parameters.type, appear_parameters.key_disable_flags.raw, | ||
| 101 | appear_parameters.key_top_as_floating, appear_parameters.enable_backspace_button, | ||
| 102 | appear_parameters.enable_return_button, appear_parameters.disable_cancel_button); | ||
| 103 | |||
| 104 | std::thread([this] { SubmitInlineText(u"yuzu"); }).detach(); | ||
| 105 | } | ||
| 17 | 106 | ||
| 18 | out(parameters.initial_text); | 107 | void DefaultSoftwareKeyboardApplet::HideInlineKeyboard() const { |
| 108 | LOG_WARNING(Service_AM, | ||
| 109 | "(STUBBED) called, backend requested to hide the inline software keyboard."); | ||
| 19 | } | 110 | } |
| 20 | 111 | ||
| 21 | void DefaultSoftwareKeyboardApplet::SendTextCheckDialog( | 112 | void DefaultSoftwareKeyboardApplet::InlineTextChanged(InlineTextParameters text_parameters) const { |
| 22 | std::u16string error_message, std::function<void()> finished_check) const { | ||
| 23 | LOG_WARNING(Service_AM, | 113 | LOG_WARNING(Service_AM, |
| 24 | "(STUBBED) called - Default fallback software keyboard does not support text " | 114 | "(STUBBED) called, backend requested to change the inline keyboard text."); |
| 25 | "check! (error_message={})", | 115 | |
| 26 | Common::UTF16ToUTF8(error_message)); | 116 | LOG_INFO(Service_AM, |
| 27 | finished_check(); | 117 | "\nInlineTextParameters:" |
| 118 | "\ninput_text={}" | ||
| 119 | "\ncursor_position={}", | ||
| 120 | Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position); | ||
| 121 | |||
| 122 | submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, | ||
| 123 | text_parameters.input_text, text_parameters.cursor_position); | ||
| 124 | } | ||
| 125 | |||
| 126 | void DefaultSoftwareKeyboardApplet::ExitKeyboard() const { | ||
| 127 | LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to exit the software keyboard."); | ||
| 28 | } | 128 | } |
| 129 | |||
| 130 | void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const { | ||
| 131 | submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text); | ||
| 132 | } | ||
| 133 | |||
| 134 | void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const { | ||
| 135 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); | ||
| 136 | |||
| 137 | for (std::size_t index = 0; index < text.size(); ++index) { | ||
| 138 | submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, | ||
| 139 | std::u16string(text.data(), text.data() + index + 1), | ||
| 140 | static_cast<s32>(index) + 1); | ||
| 141 | |||
| 142 | std::this_thread::sleep_for(std::chrono::milliseconds(250)); | ||
| 143 | } | ||
| 144 | |||
| 145 | submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, std::u16string(text), | ||
| 146 | static_cast<s32>(text.size())); | ||
| 147 | } | ||
| 148 | |||
| 29 | } // namespace Core::Frontend | 149 | } // namespace Core::Frontend |
diff --git a/src/core/frontend/applets/software_keyboard.h b/src/core/frontend/applets/software_keyboard.h index f9b202664..506eb35bb 100644 --- a/src/core/frontend/applets/software_keyboard.h +++ b/src/core/frontend/applets/software_keyboard.h | |||
| @@ -1,54 +1,116 @@ | |||
| 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 <functional> | 7 | #include <functional> |
| 8 | #include <optional> | 8 | #include <thread> |
| 9 | #include <string> | 9 | |
| 10 | #include "common/bit_field.h" | ||
| 11 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 12 | 11 | ||
| 12 | #include "core/hle/service/am/applets/software_keyboard_types.h" | ||
| 13 | |||
| 13 | namespace Core::Frontend { | 14 | namespace Core::Frontend { |
| 14 | struct SoftwareKeyboardParameters { | 15 | |
| 15 | std::u16string submit_text; | 16 | struct KeyboardInitializeParameters { |
| 17 | std::u16string ok_text; | ||
| 16 | std::u16string header_text; | 18 | std::u16string header_text; |
| 17 | std::u16string sub_text; | 19 | std::u16string sub_text; |
| 18 | std::u16string guide_text; | 20 | std::u16string guide_text; |
| 19 | std::u16string initial_text; | 21 | std::u16string initial_text; |
| 20 | std::size_t max_length; | 22 | u32 max_text_length; |
| 21 | bool password; | 23 | u32 min_text_length; |
| 22 | bool cursor_at_beginning; | 24 | s32 initial_cursor_position; |
| 23 | 25 | Service::AM::Applets::SwkbdType type; | |
| 24 | union { | 26 | Service::AM::Applets::SwkbdPasswordMode password_mode; |
| 25 | u8 value; | 27 | Service::AM::Applets::SwkbdTextDrawType text_draw_type; |
| 26 | 28 | Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags; | |
| 27 | BitField<1, 1, u8> disable_space; | 29 | bool use_blur_background; |
| 28 | BitField<2, 1, u8> disable_address; | 30 | bool enable_backspace_button; |
| 29 | BitField<3, 1, u8> disable_percent; | 31 | bool enable_return_button; |
| 30 | BitField<4, 1, u8> disable_slash; | 32 | bool disable_cancel_button; |
| 31 | BitField<6, 1, u8> disable_number; | 33 | }; |
| 32 | BitField<7, 1, u8> disable_download_code; | 34 | |
| 33 | }; | 35 | struct InlineAppearParameters { |
| 36 | u32 max_text_length; | ||
| 37 | u32 min_text_length; | ||
| 38 | f32 key_top_scale_x; | ||
| 39 | f32 key_top_scale_y; | ||
| 40 | f32 key_top_translate_x; | ||
| 41 | f32 key_top_translate_y; | ||
| 42 | Service::AM::Applets::SwkbdType type; | ||
| 43 | Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags; | ||
| 44 | bool key_top_as_floating; | ||
| 45 | bool enable_backspace_button; | ||
| 46 | bool enable_return_button; | ||
| 47 | bool disable_cancel_button; | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct InlineTextParameters { | ||
| 51 | std::u16string input_text; | ||
| 52 | s32 cursor_position; | ||
| 34 | }; | 53 | }; |
| 35 | 54 | ||
| 36 | class SoftwareKeyboardApplet { | 55 | class SoftwareKeyboardApplet { |
| 37 | public: | 56 | public: |
| 38 | virtual ~SoftwareKeyboardApplet(); | 57 | virtual ~SoftwareKeyboardApplet(); |
| 39 | 58 | ||
| 40 | virtual void RequestText(std::function<void(std::optional<std::u16string>)> out, | 59 | virtual void InitializeKeyboard( |
| 41 | SoftwareKeyboardParameters parameters) const = 0; | 60 | bool is_inline, KeyboardInitializeParameters initialize_parameters, |
| 42 | virtual void SendTextCheckDialog(std::u16string error_message, | 61 | std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> |
| 43 | std::function<void()> finished_check) const = 0; | 62 | submit_normal_callback_, |
| 63 | std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> | ||
| 64 | submit_inline_callback_) = 0; | ||
| 65 | |||
| 66 | virtual void ShowNormalKeyboard() const = 0; | ||
| 67 | |||
| 68 | virtual void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, | ||
| 69 | std::u16string text_check_message) const = 0; | ||
| 70 | |||
| 71 | virtual void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const = 0; | ||
| 72 | |||
| 73 | virtual void HideInlineKeyboard() const = 0; | ||
| 74 | |||
| 75 | virtual void InlineTextChanged(InlineTextParameters text_parameters) const = 0; | ||
| 76 | |||
| 77 | virtual void ExitKeyboard() const = 0; | ||
| 44 | }; | 78 | }; |
| 45 | 79 | ||
| 46 | class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet { | 80 | class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet { |
| 47 | public: | 81 | public: |
| 48 | void RequestText(std::function<void(std::optional<std::u16string>)> out, | 82 | ~DefaultSoftwareKeyboardApplet() override; |
| 49 | SoftwareKeyboardParameters parameters) const override; | 83 | |
| 50 | void SendTextCheckDialog(std::u16string error_message, | 84 | void InitializeKeyboard( |
| 51 | std::function<void()> finished_check) const override; | 85 | bool is_inline, KeyboardInitializeParameters initialize_parameters, |
| 86 | std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> | ||
| 87 | submit_normal_callback_, | ||
| 88 | std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> | ||
| 89 | submit_inline_callback_) override; | ||
| 90 | |||
| 91 | void ShowNormalKeyboard() const override; | ||
| 92 | |||
| 93 | void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, | ||
| 94 | std::u16string text_check_message) const override; | ||
| 95 | |||
| 96 | void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const override; | ||
| 97 | |||
| 98 | void HideInlineKeyboard() const override; | ||
| 99 | |||
| 100 | void InlineTextChanged(InlineTextParameters text_parameters) const override; | ||
| 101 | |||
| 102 | void ExitKeyboard() const override; | ||
| 103 | |||
| 104 | private: | ||
| 105 | void SubmitNormalText(std::u16string text) const; | ||
| 106 | void SubmitInlineText(std::u16string_view text) const; | ||
| 107 | |||
| 108 | KeyboardInitializeParameters parameters; | ||
| 109 | |||
| 110 | mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> | ||
| 111 | submit_normal_callback; | ||
| 112 | mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> | ||
| 113 | submit_inline_callback; | ||
| 52 | }; | 114 | }; |
| 53 | 115 | ||
| 54 | } // namespace Core::Frontend | 116 | } // namespace Core::Frontend |
diff --git a/src/core/frontend/input_interpreter.cpp b/src/core/frontend/input_interpreter.cpp index ec5fe660e..9f6a90e8f 100644 --- a/src/core/frontend/input_interpreter.cpp +++ b/src/core/frontend/input_interpreter.cpp | |||
| @@ -12,7 +12,9 @@ InputInterpreter::InputInterpreter(Core::System& system) | |||
| 12 | : npad{system.ServiceManager() | 12 | : npad{system.ServiceManager() |
| 13 | .GetService<Service::HID::Hid>("hid") | 13 | .GetService<Service::HID::Hid>("hid") |
| 14 | ->GetAppletResource() | 14 | ->GetAppletResource() |
| 15 | ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {} | 15 | ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} { |
| 16 | ResetButtonStates(); | ||
| 17 | } | ||
| 16 | 18 | ||
| 17 | InputInterpreter::~InputInterpreter() = default; | 19 | InputInterpreter::~InputInterpreter() = default; |
| 18 | 20 | ||
| @@ -25,6 +27,17 @@ void InputInterpreter::PollInput() { | |||
| 25 | button_states[current_index] = button_state; | 27 | button_states[current_index] = button_state; |
| 26 | } | 28 | } |
| 27 | 29 | ||
| 30 | void InputInterpreter::ResetButtonStates() { | ||
| 31 | previous_index = 0; | ||
| 32 | current_index = 0; | ||
| 33 | |||
| 34 | button_states[0] = 0xFFFFFFFF; | ||
| 35 | |||
| 36 | for (std::size_t i = 1; i < button_states.size(); ++i) { | ||
| 37 | button_states[i] = 0; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 28 | bool InputInterpreter::IsButtonPressed(HIDButton button) const { | 41 | bool InputInterpreter::IsButtonPressed(HIDButton button) const { |
| 29 | return (button_states[current_index] & (1U << static_cast<u8>(button))) != 0; | 42 | return (button_states[current_index] & (1U << static_cast<u8>(button))) != 0; |
| 30 | } | 43 | } |
diff --git a/src/core/frontend/input_interpreter.h b/src/core/frontend/input_interpreter.h index 73fc47ffb..9495e3daf 100644 --- a/src/core/frontend/input_interpreter.h +++ b/src/core/frontend/input_interpreter.h | |||
| @@ -66,6 +66,9 @@ public: | |||
| 66 | /// Gets a button state from HID and inserts it into the array of button states. | 66 | /// Gets a button state from HID and inserts it into the array of button states. |
| 67 | void PollInput(); | 67 | void PollInput(); |
| 68 | 68 | ||
| 69 | /// Resets all the button states to their defaults. | ||
| 70 | void ResetButtonStates(); | ||
| 71 | |||
| 69 | /** | 72 | /** |
| 70 | * Checks whether the button is pressed. | 73 | * Checks whether the button is pressed. |
| 71 | * | 74 | * |
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..4c8216b47 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -619,16 +619,20 @@ std::size_t AppletMessageQueue::GetMessageCount() const { | |||
| 619 | return messages.size(); | 619 | return messages.size(); |
| 620 | } | 620 | } |
| 621 | 621 | ||
| 622 | void AppletMessageQueue::RequestExit() { | ||
| 623 | PushMessage(AppletMessage::ExitRequested); | ||
| 624 | } | ||
| 625 | |||
| 626 | void AppletMessageQueue::FocusStateChanged() { | ||
| 627 | PushMessage(AppletMessage::FocusStateChanged); | ||
| 628 | } | ||
| 629 | |||
| 622 | void AppletMessageQueue::OperationModeChanged() { | 630 | void AppletMessageQueue::OperationModeChanged() { |
| 623 | PushMessage(AppletMessage::OperationModeChanged); | 631 | PushMessage(AppletMessage::OperationModeChanged); |
| 624 | PushMessage(AppletMessage::PerformanceModeChanged); | 632 | PushMessage(AppletMessage::PerformanceModeChanged); |
| 625 | on_operation_mode_changed->GetWritableEvent()->Signal(); | 633 | on_operation_mode_changed->GetWritableEvent()->Signal(); |
| 626 | } | 634 | } |
| 627 | 635 | ||
| 628 | void AppletMessageQueue::RequestExit() { | ||
| 629 | PushMessage(AppletMessage::ExitRequested); | ||
| 630 | } | ||
| 631 | |||
| 632 | ICommonStateGetter::ICommonStateGetter(Core::System& system_, | 636 | ICommonStateGetter::ICommonStateGetter(Core::System& system_, |
| 633 | std::shared_ptr<AppletMessageQueue> msg_queue_) | 637 | std::shared_ptr<AppletMessageQueue> msg_queue_) |
| 634 | : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)} { | 638 | : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)} { |
| @@ -971,7 +975,7 @@ private: | |||
| 971 | 975 | ||
| 972 | auto storage = applet->GetBroker().PopNormalDataToGame(); | 976 | auto storage = applet->GetBroker().PopNormalDataToGame(); |
| 973 | if (storage == nullptr) { | 977 | if (storage == nullptr) { |
| 974 | LOG_ERROR(Service_AM, | 978 | LOG_DEBUG(Service_AM, |
| 975 | "storage is a nullptr. There is no data in the current normal channel"); | 979 | "storage is a nullptr. There is no data in the current normal channel"); |
| 976 | IPC::ResponseBuilder rb{ctx, 2}; | 980 | IPC::ResponseBuilder rb{ctx, 2}; |
| 977 | rb.Push(ERR_NO_DATA_IN_CHANNEL); | 981 | rb.Push(ERR_NO_DATA_IN_CHANNEL); |
| @@ -1002,7 +1006,7 @@ private: | |||
| 1002 | 1006 | ||
| 1003 | auto storage = applet->GetBroker().PopInteractiveDataToGame(); | 1007 | auto storage = applet->GetBroker().PopInteractiveDataToGame(); |
| 1004 | if (storage == nullptr) { | 1008 | if (storage == nullptr) { |
| 1005 | LOG_ERROR(Service_AM, | 1009 | LOG_DEBUG(Service_AM, |
| 1006 | "storage is a nullptr. There is no data in the current interactive channel"); | 1010 | "storage is a nullptr. There is no data in the current interactive channel"); |
| 1007 | IPC::ResponseBuilder rb{ctx, 2}; | 1011 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1008 | rb.Push(ERR_NO_DATA_IN_CHANNEL); | 1012 | rb.Push(ERR_NO_DATA_IN_CHANNEL); |
| @@ -1125,7 +1129,7 @@ ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_) | |||
| 1125 | {2, nullptr, "AreAnyLibraryAppletsLeft"}, | 1129 | {2, nullptr, "AreAnyLibraryAppletsLeft"}, |
| 1126 | {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, | 1130 | {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, |
| 1127 | {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"}, | 1131 | {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"}, |
| 1128 | {12, nullptr, "CreateHandleStorage"}, | 1132 | {12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"}, |
| 1129 | }; | 1133 | }; |
| 1130 | RegisterHandlers(functions); | 1134 | RegisterHandlers(functions); |
| 1131 | } | 1135 | } |
| @@ -1134,14 +1138,15 @@ ILibraryAppletCreator::~ILibraryAppletCreator() = default; | |||
| 1134 | 1138 | ||
| 1135 | void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { | 1139 | void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { |
| 1136 | IPC::RequestParser rp{ctx}; | 1140 | IPC::RequestParser rp{ctx}; |
| 1141 | |||
| 1137 | const auto applet_id = rp.PopRaw<Applets::AppletId>(); | 1142 | const auto applet_id = rp.PopRaw<Applets::AppletId>(); |
| 1138 | const auto applet_mode = rp.PopRaw<u32>(); | 1143 | const auto applet_mode = rp.PopRaw<Applets::LibraryAppletMode>(); |
| 1139 | 1144 | ||
| 1140 | LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, | 1145 | LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, |
| 1141 | applet_mode); | 1146 | applet_mode); |
| 1142 | 1147 | ||
| 1143 | const auto& applet_manager{system.GetAppletManager()}; | 1148 | const auto& applet_manager{system.GetAppletManager()}; |
| 1144 | const auto applet = applet_manager.GetApplet(applet_id); | 1149 | const auto applet = applet_manager.GetApplet(applet_id, applet_mode); |
| 1145 | 1150 | ||
| 1146 | if (applet == nullptr) { | 1151 | if (applet == nullptr) { |
| 1147 | LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); | 1152 | LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); |
| @@ -1159,9 +1164,18 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) | |||
| 1159 | 1164 | ||
| 1160 | void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { | 1165 | void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { |
| 1161 | IPC::RequestParser rp{ctx}; | 1166 | IPC::RequestParser rp{ctx}; |
| 1162 | const u64 size{rp.Pop<u64>()}; | 1167 | |
| 1168 | const s64 size{rp.Pop<s64>()}; | ||
| 1169 | |||
| 1163 | LOG_DEBUG(Service_AM, "called, size={}", size); | 1170 | LOG_DEBUG(Service_AM, "called, size={}", size); |
| 1164 | 1171 | ||
| 1172 | if (size <= 0) { | ||
| 1173 | LOG_ERROR(Service_AM, "size is less than or equal to 0"); | ||
| 1174 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1175 | rb.Push(RESULT_UNKNOWN); | ||
| 1176 | return; | ||
| 1177 | } | ||
| 1178 | |||
| 1165 | std::vector<u8> buffer(size); | 1179 | std::vector<u8> buffer(size); |
| 1166 | 1180 | ||
| 1167 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1181 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| @@ -1170,18 +1184,65 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { | |||
| 1170 | } | 1184 | } |
| 1171 | 1185 | ||
| 1172 | void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { | 1186 | void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { |
| 1173 | LOG_DEBUG(Service_AM, "called"); | 1187 | IPC::RequestParser rp{ctx}; |
| 1188 | |||
| 1189 | struct Parameters { | ||
| 1190 | u8 permissions; | ||
| 1191 | s64 size; | ||
| 1192 | }; | ||
| 1193 | |||
| 1194 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 1195 | const auto handle{ctx.GetCopyHandle(0)}; | ||
| 1196 | |||
| 1197 | LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions, | ||
| 1198 | parameters.size, handle); | ||
| 1199 | |||
| 1200 | if (parameters.size <= 0) { | ||
| 1201 | LOG_ERROR(Service_AM, "size is less than or equal to 0"); | ||
| 1202 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1203 | rb.Push(RESULT_UNKNOWN); | ||
| 1204 | return; | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | auto transfer_mem = | ||
| 1208 | system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); | ||
| 1209 | |||
| 1210 | if (transfer_mem == nullptr) { | ||
| 1211 | LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); | ||
| 1212 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1213 | rb.Push(RESULT_UNKNOWN); | ||
| 1214 | return; | ||
| 1215 | } | ||
| 1174 | 1216 | ||
| 1217 | const u8* const mem_begin = transfer_mem->GetPointer(); | ||
| 1218 | const u8* const mem_end = mem_begin + transfer_mem->GetSize(); | ||
| 1219 | std::vector<u8> memory{mem_begin, mem_end}; | ||
| 1220 | |||
| 1221 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 1222 | rb.Push(RESULT_SUCCESS); | ||
| 1223 | rb.PushIpcInterface<IStorage>(system, std::move(memory)); | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx) { | ||
| 1175 | IPC::RequestParser rp{ctx}; | 1227 | IPC::RequestParser rp{ctx}; |
| 1176 | 1228 | ||
| 1177 | rp.SetCurrentOffset(3); | 1229 | const s64 size{rp.Pop<s64>()}; |
| 1178 | const auto handle{rp.Pop<Kernel::Handle>()}; | 1230 | const auto handle{ctx.GetCopyHandle(0)}; |
| 1231 | |||
| 1232 | LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle); | ||
| 1233 | |||
| 1234 | if (size <= 0) { | ||
| 1235 | LOG_ERROR(Service_AM, "size is less than or equal to 0"); | ||
| 1236 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1237 | rb.Push(RESULT_UNKNOWN); | ||
| 1238 | return; | ||
| 1239 | } | ||
| 1179 | 1240 | ||
| 1180 | auto transfer_mem = | 1241 | auto transfer_mem = |
| 1181 | system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); | 1242 | system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); |
| 1182 | 1243 | ||
| 1183 | if (transfer_mem == nullptr) { | 1244 | if (transfer_mem == nullptr) { |
| 1184 | LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle); | 1245 | LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); |
| 1185 | IPC::ResponseBuilder rb{ctx, 2}; | 1246 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1186 | rb.Push(RESULT_UNKNOWN); | 1247 | rb.Push(RESULT_UNKNOWN); |
| 1187 | return; | 1248 | return; |
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index f6a453ab7..756434716 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -61,8 +61,9 @@ public: | |||
| 61 | void PushMessage(AppletMessage msg); | 61 | void PushMessage(AppletMessage msg); |
| 62 | AppletMessage PopMessage(); | 62 | AppletMessage PopMessage(); |
| 63 | std::size_t GetMessageCount() const; | 63 | std::size_t GetMessageCount() const; |
| 64 | void OperationModeChanged(); | ||
| 65 | void RequestExit(); | 64 | void RequestExit(); |
| 65 | void FocusStateChanged(); | ||
| 66 | void OperationModeChanged(); | ||
| 66 | 67 | ||
| 67 | private: | 68 | private: |
| 68 | std::queue<AppletMessage> messages; | 69 | std::queue<AppletMessage> messages; |
| @@ -254,6 +255,7 @@ private: | |||
| 254 | void CreateLibraryApplet(Kernel::HLERequestContext& ctx); | 255 | void CreateLibraryApplet(Kernel::HLERequestContext& ctx); |
| 255 | void CreateStorage(Kernel::HLERequestContext& ctx); | 256 | void CreateStorage(Kernel::HLERequestContext& ctx); |
| 256 | void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); | 257 | void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); |
| 258 | void CreateHandleStorage(Kernel::HLERequestContext& ctx); | ||
| 257 | }; | 259 | }; |
| 258 | 260 | ||
| 259 | class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { | 261 | 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..a56df6a7e 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | #include "core/hle/kernel/k_writable_event.h" | 17 | #include "core/hle/kernel/k_writable_event.h" |
| 18 | #include "core/hle/kernel/server_session.h" | 18 | #include "core/hle/kernel/server_session.h" |
| 19 | #include "core/hle/service/am/am.h" | 19 | #include "core/hle/service/am/am.h" |
| 20 | #include "core/hle/service/am/applet_ae.h" | ||
| 21 | #include "core/hle/service/am/applet_oe.h" | ||
| 20 | #include "core/hle/service/am/applets/applets.h" | 22 | #include "core/hle/service/am/applets/applets.h" |
| 21 | #include "core/hle/service/am/applets/controller.h" | 23 | #include "core/hle/service/am/applets/controller.h" |
| 22 | #include "core/hle/service/am/applets/error.h" | 24 | #include "core/hle/service/am/applets/error.h" |
| @@ -24,17 +26,20 @@ | |||
| 24 | #include "core/hle/service/am/applets/profile_select.h" | 26 | #include "core/hle/service/am/applets/profile_select.h" |
| 25 | #include "core/hle/service/am/applets/software_keyboard.h" | 27 | #include "core/hle/service/am/applets/software_keyboard.h" |
| 26 | #include "core/hle/service/am/applets/web_browser.h" | 28 | #include "core/hle/service/am/applets/web_browser.h" |
| 29 | #include "core/hle/service/sm/sm.h" | ||
| 27 | 30 | ||
| 28 | namespace Service::AM::Applets { | 31 | namespace Service::AM::Applets { |
| 29 | 32 | ||
| 30 | AppletDataBroker::AppletDataBroker(Kernel::KernelCore& kernel) { | 33 | AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_) |
| 34 | : system{system_}, applet_mode{applet_mode_} { | ||
| 31 | state_changed_event = | 35 | state_changed_event = |
| 32 | Kernel::KEvent::Create(kernel, "ILibraryAppletAccessor:StateChangedEvent"); | 36 | Kernel::KEvent::Create(system.Kernel(), "ILibraryAppletAccessor:StateChangedEvent"); |
| 33 | state_changed_event->Initialize(); | 37 | state_changed_event->Initialize(); |
| 34 | pop_out_data_event = Kernel::KEvent::Create(kernel, "ILibraryAppletAccessor:PopDataOutEvent"); | 38 | pop_out_data_event = |
| 39 | Kernel::KEvent::Create(system.Kernel(), "ILibraryAppletAccessor:PopDataOutEvent"); | ||
| 35 | pop_out_data_event->Initialize(); | 40 | pop_out_data_event->Initialize(); |
| 36 | pop_interactive_out_data_event = | 41 | pop_interactive_out_data_event = Kernel::KEvent::Create( |
| 37 | Kernel::KEvent::Create(kernel, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); | 42 | system.Kernel(), "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); |
| 38 | pop_interactive_out_data_event->Initialize(); | 43 | pop_interactive_out_data_event->Initialize(); |
| 39 | } | 44 | } |
| 40 | 45 | ||
| @@ -114,6 +119,27 @@ void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& | |||
| 114 | 119 | ||
| 115 | void AppletDataBroker::SignalStateChanged() const { | 120 | void AppletDataBroker::SignalStateChanged() const { |
| 116 | state_changed_event->GetWritableEvent()->Signal(); | 121 | state_changed_event->GetWritableEvent()->Signal(); |
| 122 | |||
| 123 | switch (applet_mode) { | ||
| 124 | case LibraryAppletMode::AllForeground: | ||
| 125 | case LibraryAppletMode::AllForegroundInitiallyHidden: { | ||
| 126 | auto applet_oe = system.ServiceManager().GetService<AppletOE>("appletOE"); | ||
| 127 | auto applet_ae = system.ServiceManager().GetService<AppletAE>("appletAE"); | ||
| 128 | |||
| 129 | if (applet_oe) { | ||
| 130 | applet_oe->GetMessageQueue()->FocusStateChanged(); | ||
| 131 | break; | ||
| 132 | } | ||
| 133 | |||
| 134 | if (applet_ae) { | ||
| 135 | applet_ae->GetMessageQueue()->FocusStateChanged(); | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | break; | ||
| 139 | } | ||
| 140 | default: | ||
| 141 | break; | ||
| 142 | } | ||
| 117 | } | 143 | } |
| 118 | 144 | ||
| 119 | std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetNormalDataEvent() const { | 145 | std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetNormalDataEvent() const { |
| @@ -128,7 +154,8 @@ std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetStateChangedEvent() | |||
| 128 | return state_changed_event->GetReadableEvent(); | 154 | return state_changed_event->GetReadableEvent(); |
| 129 | } | 155 | } |
| 130 | 156 | ||
| 131 | Applet::Applet(Kernel::KernelCore& kernel_) : broker{kernel_} {} | 157 | Applet::Applet(Core::System& system_, LibraryAppletMode applet_mode_) |
| 158 | : broker{system_, applet_mode_}, applet_mode{applet_mode_} {} | ||
| 132 | 159 | ||
| 133 | Applet::~Applet() = default; | 160 | Applet::~Applet() = default; |
| 134 | 161 | ||
| @@ -241,31 +268,31 @@ void AppletManager::ClearAll() { | |||
| 241 | frontend = {}; | 268 | frontend = {}; |
| 242 | } | 269 | } |
| 243 | 270 | ||
| 244 | std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const { | 271 | std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode mode) const { |
| 245 | switch (id) { | 272 | switch (id) { |
| 246 | case AppletId::Auth: | 273 | case AppletId::Auth: |
| 247 | return std::make_shared<Auth>(system, *frontend.parental_controls); | 274 | return std::make_shared<Auth>(system, mode, *frontend.parental_controls); |
| 248 | case AppletId::Controller: | 275 | case AppletId::Controller: |
| 249 | return std::make_shared<Controller>(system, *frontend.controller); | 276 | return std::make_shared<Controller>(system, mode, *frontend.controller); |
| 250 | case AppletId::Error: | 277 | case AppletId::Error: |
| 251 | return std::make_shared<Error>(system, *frontend.error); | 278 | return std::make_shared<Error>(system, mode, *frontend.error); |
| 252 | case AppletId::ProfileSelect: | 279 | case AppletId::ProfileSelect: |
| 253 | return std::make_shared<ProfileSelect>(system, *frontend.profile_select); | 280 | return std::make_shared<ProfileSelect>(system, mode, *frontend.profile_select); |
| 254 | case AppletId::SoftwareKeyboard: | 281 | case AppletId::SoftwareKeyboard: |
| 255 | return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard); | 282 | return std::make_shared<SoftwareKeyboard>(system, mode, *frontend.software_keyboard); |
| 256 | case AppletId::Web: | 283 | case AppletId::Web: |
| 257 | case AppletId::Shop: | 284 | case AppletId::Shop: |
| 258 | case AppletId::OfflineWeb: | 285 | case AppletId::OfflineWeb: |
| 259 | case AppletId::LoginShare: | 286 | case AppletId::LoginShare: |
| 260 | case AppletId::WebAuth: | 287 | case AppletId::WebAuth: |
| 261 | return std::make_shared<WebBrowser>(system, *frontend.web_browser); | 288 | return std::make_shared<WebBrowser>(system, mode, *frontend.web_browser); |
| 262 | case AppletId::PhotoViewer: | 289 | case AppletId::PhotoViewer: |
| 263 | return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer); | 290 | return std::make_shared<PhotoViewer>(system, mode, *frontend.photo_viewer); |
| 264 | default: | 291 | default: |
| 265 | UNIMPLEMENTED_MSG( | 292 | UNIMPLEMENTED_MSG( |
| 266 | "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", | 293 | "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", |
| 267 | static_cast<u8>(id)); | 294 | static_cast<u8>(id)); |
| 268 | return std::make_shared<StubApplet>(system, id); | 295 | return std::make_shared<StubApplet>(system, id, mode); |
| 269 | } | 296 | } |
| 270 | } | 297 | } |
| 271 | 298 | ||
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index b9a006317..4215d2232 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h | |||
| @@ -62,9 +62,17 @@ 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(Core::System& system_, LibraryAppletMode applet_mode_); |
| 68 | ~AppletDataBroker(); | 76 | ~AppletDataBroker(); |
| 69 | 77 | ||
| 70 | struct RawChannelData { | 78 | struct RawChannelData { |
| @@ -94,6 +102,9 @@ public: | |||
| 94 | std::shared_ptr<Kernel::KReadableEvent> GetStateChangedEvent() const; | 102 | std::shared_ptr<Kernel::KReadableEvent> GetStateChangedEvent() const; |
| 95 | 103 | ||
| 96 | private: | 104 | private: |
| 105 | Core::System& system; | ||
| 106 | LibraryAppletMode applet_mode; | ||
| 107 | |||
| 97 | // Queues are named from applet's perspective | 108 | // Queues are named from applet's perspective |
| 98 | 109 | ||
| 99 | // PopNormalDataToApplet and PushNormalDataFromGame | 110 | // PopNormalDataToApplet and PushNormalDataFromGame |
| @@ -119,7 +130,7 @@ private: | |||
| 119 | 130 | ||
| 120 | class Applet { | 131 | class Applet { |
| 121 | public: | 132 | public: |
| 122 | explicit Applet(Kernel::KernelCore& kernel_); | 133 | explicit Applet(Core::System& system_, LibraryAppletMode applet_mode_); |
| 123 | virtual ~Applet(); | 134 | virtual ~Applet(); |
| 124 | 135 | ||
| 125 | virtual void Initialize(); | 136 | virtual void Initialize(); |
| @@ -129,10 +140,6 @@ public: | |||
| 129 | virtual void ExecuteInteractive() = 0; | 140 | virtual void ExecuteInteractive() = 0; |
| 130 | virtual void Execute() = 0; | 141 | virtual void Execute() = 0; |
| 131 | 142 | ||
| 132 | bool IsInitialized() const { | ||
| 133 | return initialized; | ||
| 134 | } | ||
| 135 | |||
| 136 | AppletDataBroker& GetBroker() { | 143 | AppletDataBroker& GetBroker() { |
| 137 | return broker; | 144 | return broker; |
| 138 | } | 145 | } |
| @@ -141,6 +148,14 @@ public: | |||
| 141 | return broker; | 148 | return broker; |
| 142 | } | 149 | } |
| 143 | 150 | ||
| 151 | LibraryAppletMode GetLibraryAppletMode() const { | ||
| 152 | return applet_mode; | ||
| 153 | } | ||
| 154 | |||
| 155 | bool IsInitialized() const { | ||
| 156 | return initialized; | ||
| 157 | } | ||
| 158 | |||
| 144 | protected: | 159 | protected: |
| 145 | struct CommonArguments { | 160 | struct CommonArguments { |
| 146 | u32_le arguments_version; | 161 | u32_le arguments_version; |
| @@ -154,6 +169,7 @@ protected: | |||
| 154 | 169 | ||
| 155 | CommonArguments common_args{}; | 170 | CommonArguments common_args{}; |
| 156 | AppletDataBroker broker; | 171 | AppletDataBroker broker; |
| 172 | LibraryAppletMode applet_mode; | ||
| 157 | bool initialized = false; | 173 | bool initialized = false; |
| 158 | }; | 174 | }; |
| 159 | 175 | ||
| @@ -200,7 +216,7 @@ public: | |||
| 200 | void SetDefaultAppletsIfMissing(); | 216 | void SetDefaultAppletsIfMissing(); |
| 201 | void ClearAll(); | 217 | void ClearAll(); |
| 202 | 218 | ||
| 203 | std::shared_ptr<Applet> GetApplet(AppletId id) const; | 219 | std::shared_ptr<Applet> GetApplet(AppletId id, LibraryAppletMode mode) const; |
| 204 | 220 | ||
| 205 | private: | 221 | private: |
| 206 | AppletFrontendSet frontend; | 222 | AppletFrontendSet frontend; |
diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp index c2bfe698f..218c8d1e4 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_, 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..2d4dae0bd 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; |
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp index 0c8b632e8..23e30aa45 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_, 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..e606d12ce 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; |
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp index 4d1df5cbe..b26abad36 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_, 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_, 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_, applet_mode_}, id{id_}, 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..7496ded88 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; |
| @@ -50,7 +51,8 @@ enum class PhotoViewerAppletMode : u8 { | |||
| 50 | 51 | ||
| 51 | class PhotoViewer final : public Applet { | 52 | class PhotoViewer final : public Applet { |
| 52 | public: | 53 | public: |
| 53 | explicit PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_); | 54 | explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, |
| 55 | const Core::Frontend::PhotoViewerApplet& frontend_); | ||
| 54 | ~PhotoViewer() override; | 56 | ~PhotoViewer() override; |
| 55 | 57 | ||
| 56 | void Initialize() override; | 58 | void Initialize() override; |
| @@ -70,7 +72,7 @@ private: | |||
| 70 | 72 | ||
| 71 | class StubApplet final : public Applet { | 73 | class StubApplet final : public Applet { |
| 72 | public: | 74 | public: |
| 73 | explicit StubApplet(Core::System& system_, AppletId id_); | 75 | explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_); |
| 74 | ~StubApplet() override; | 76 | ~StubApplet() override; |
| 75 | 77 | ||
| 76 | void Initialize() override; | 78 | void Initialize() override; |
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp index 77fba16c7..c91a9776a 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_, 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..f0dd6c1f3 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 | ||
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 79b209c6b..73a06def1 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_, 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..7c67b7574 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,138 @@ 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 | Core::Frontend::SoftwareKeyboardApplet& frontend; | ||
| 83 | Core::System& system; | 140 | Core::System& system; |
| 141 | |||
| 142 | SwkbdAppletVersion swkbd_applet_version; | ||
| 143 | |||
| 144 | SwkbdConfigCommon swkbd_config_common; | ||
| 145 | SwkbdConfigOld swkbd_config_old; | ||
| 146 | SwkbdConfigOld2 swkbd_config_old2; | ||
| 147 | SwkbdConfigNew swkbd_config_new; | ||
| 148 | std::u16string initial_text; | ||
| 149 | |||
| 150 | SwkbdState swkbd_state{SwkbdState::NotInitialized}; | ||
| 151 | SwkbdInitializeArg swkbd_initialize_arg; | ||
| 152 | SwkbdCalcArg swkbd_calc_arg; | ||
| 153 | bool use_changed_string_v2{false}; | ||
| 154 | bool use_moved_cursor_v2{false}; | ||
| 155 | bool inline_use_utf8{false}; | ||
| 156 | s32 current_cursor_position{}; | ||
| 157 | |||
| 158 | std::u16string current_text; | ||
| 159 | |||
| 160 | bool is_background{false}; | ||
| 161 | |||
| 162 | bool complete{false}; | ||
| 163 | ResultCode status{RESULT_SUCCESS}; | ||
| 84 | }; | 164 | }; |
| 85 | 165 | ||
| 86 | } // namespace Service::AM::Applets | 166 | } // 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..2404921fd 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_, 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..21fd910c2 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 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index c8031970b..4e58b9b80 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | |||
| @@ -32,11 +32,6 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& | |||
| 32 | case 0x9: | 32 | case 0x9: |
| 33 | return MapBuffer(input, output); | 33 | return MapBuffer(input, output); |
| 34 | case 0xa: { | 34 | case 0xa: { |
| 35 | if (command.length == 0x1c) { | ||
| 36 | LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); | ||
| 37 | Tegra::ChCommandHeaderList cmdlist{{0xDEADB33F}}; | ||
| 38 | system.GPU().PushCommandBuffer(cmdlist); | ||
| 39 | } | ||
| 40 | return UnmapBuffer(input, output); | 35 | return UnmapBuffer(input, output); |
| 41 | } | 36 | } |
| 42 | default: | 37 | default: |
| @@ -70,6 +65,9 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& | |||
| 70 | } | 65 | } |
| 71 | 66 | ||
| 72 | void nvhost_nvdec::OnOpen(DeviceFD fd) {} | 67 | void nvhost_nvdec::OnOpen(DeviceFD fd) {} |
| 73 | void nvhost_nvdec::OnClose(DeviceFD fd) {} | 68 | |
| 69 | void nvhost_nvdec::OnClose(DeviceFD fd) { | ||
| 70 | system.GPU().ClearCommandBuffer(); | ||
| 71 | } | ||
| 74 | 72 | ||
| 75 | } // namespace Service::Nvidia::Devices | 73 | } // namespace Service::Nvidia::Devices |
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 9bdb282d2..7c42f1177 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -480,11 +480,7 @@ void GPU::PushCommandBuffer(Tegra::ChCommandHeaderList& entries) { | |||
| 480 | if (!use_nvdec) { | 480 | if (!use_nvdec) { |
| 481 | return; | 481 | return; |
| 482 | } | 482 | } |
| 483 | // This condition fires when a video stream ends, clear all intermediary data | 483 | |
| 484 | if (entries[0].raw == 0xDEADB33F) { | ||
| 485 | cdma_pusher.reset(); | ||
| 486 | return; | ||
| 487 | } | ||
| 488 | if (!cdma_pusher) { | 484 | if (!cdma_pusher) { |
| 489 | cdma_pusher = std::make_unique<Tegra::CDmaPusher>(*this); | 485 | cdma_pusher = std::make_unique<Tegra::CDmaPusher>(*this); |
| 490 | } | 486 | } |
| @@ -496,6 +492,12 @@ void GPU::PushCommandBuffer(Tegra::ChCommandHeaderList& entries) { | |||
| 496 | cdma_pusher->ProcessEntries(std::move(entries)); | 492 | cdma_pusher->ProcessEntries(std::move(entries)); |
| 497 | } | 493 | } |
| 498 | 494 | ||
| 495 | void GPU::ClearCommandBuffer() { | ||
| 496 | // This condition fires when a video stream ends, clear all intermediary data | ||
| 497 | cdma_pusher.reset(); | ||
| 498 | LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); | ||
| 499 | } | ||
| 500 | |||
| 499 | void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | 501 | void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { |
| 500 | gpu_thread.SwapBuffers(framebuffer); | 502 | gpu_thread.SwapBuffers(framebuffer); |
| 501 | } | 503 | } |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index ecab35d3b..b1960ea86 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -324,6 +324,9 @@ public: | |||
| 324 | /// Push GPU command buffer entries to be processed | 324 | /// Push GPU command buffer entries to be processed |
| 325 | void PushCommandBuffer(Tegra::ChCommandHeaderList& entries); | 325 | void PushCommandBuffer(Tegra::ChCommandHeaderList& entries); |
| 326 | 326 | ||
| 327 | /// Frees the CDMAPusher to free up resources | ||
| 328 | void ClearCommandBuffer(); | ||
| 329 | |||
| 327 | /// Swap buffers (render frame) | 330 | /// Swap buffers (render frame) |
| 328 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer); | 331 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer); |
| 329 | 332 | ||
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index b025ced1c..cc0790e07 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -18,6 +18,7 @@ add_executable(yuzu | |||
| 18 | applets/profile_select.h | 18 | applets/profile_select.h |
| 19 | applets/software_keyboard.cpp | 19 | applets/software_keyboard.cpp |
| 20 | applets/software_keyboard.h | 20 | applets/software_keyboard.h |
| 21 | applets/software_keyboard.ui | ||
| 21 | applets/web_browser.cpp | 22 | applets/web_browser.cpp |
| 22 | applets/web_browser.h | 23 | applets/web_browser.h |
| 23 | bootmanager.cpp | 24 | bootmanager.cpp |
| @@ -143,6 +144,9 @@ add_executable(yuzu | |||
| 143 | uisettings.h | 144 | uisettings.h |
| 144 | util/limitable_input_dialog.cpp | 145 | util/limitable_input_dialog.cpp |
| 145 | util/limitable_input_dialog.h | 146 | util/limitable_input_dialog.h |
| 147 | util/overlay_dialog.cpp | ||
| 148 | util/overlay_dialog.h | ||
| 149 | util/overlay_dialog.ui | ||
| 146 | util/sequence_dialog/sequence_dialog.cpp | 150 | util/sequence_dialog/sequence_dialog.cpp |
| 147 | util/sequence_dialog/sequence_dialog.h | 151 | util/sequence_dialog/sequence_dialog.h |
| 148 | util/url_request_interceptor.cpp | 152 | util/url_request_interceptor.cpp |
diff --git a/src/yuzu/applets/error.cpp b/src/yuzu/applets/error.cpp index 8ee03ddb3..085688cd4 100644 --- a/src/yuzu/applets/error.cpp +++ b/src/yuzu/applets/error.cpp | |||
| @@ -19,11 +19,11 @@ QtErrorDisplay::~QtErrorDisplay() = default; | |||
| 19 | void QtErrorDisplay::ShowError(ResultCode error, std::function<void()> finished) const { | 19 | void QtErrorDisplay::ShowError(ResultCode error, std::function<void()> finished) const { |
| 20 | callback = std::move(finished); | 20 | callback = std::move(finished); |
| 21 | emit MainWindowDisplayError( | 21 | emit MainWindowDisplayError( |
| 22 | tr("An error has occurred.\nPlease try again or contact the developer of the " | 22 | tr("Error Code: %1-%2 (0x%3)") |
| 23 | "software.\n\nError Code: %1-%2 (0x%3)") | ||
| 24 | .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) | 23 | .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) |
| 25 | .arg(error.description, 4, 10, QChar::fromLatin1('0')) | 24 | .arg(error.description, 4, 10, QChar::fromLatin1('0')) |
| 26 | .arg(error.raw, 8, 16, QChar::fromLatin1('0'))); | 25 | .arg(error.raw, 8, 16, QChar::fromLatin1('0')), |
| 26 | tr("An error has occurred.\nPlease try again or contact the developer of the software.")); | ||
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, | 29 | void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, |
| @@ -32,13 +32,14 @@ void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::secon | |||
| 32 | 32 | ||
| 33 | const QDateTime date_time = QDateTime::fromSecsSinceEpoch(time.count()); | 33 | const QDateTime date_time = QDateTime::fromSecsSinceEpoch(time.count()); |
| 34 | emit MainWindowDisplayError( | 34 | emit MainWindowDisplayError( |
| 35 | tr("An error occurred on %1 at %2.\nPlease try again or contact the " | 35 | tr("Error Code: %1-%2 (0x%3)") |
| 36 | "developer of the software.\n\nError Code: %3-%4 (0x%5)") | ||
| 37 | .arg(date_time.toString(QStringLiteral("dddd, MMMM d, yyyy"))) | ||
| 38 | .arg(date_time.toString(QStringLiteral("h:mm:ss A"))) | ||
| 39 | .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) | 36 | .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) |
| 40 | .arg(error.description, 4, 10, QChar::fromLatin1('0')) | 37 | .arg(error.description, 4, 10, QChar::fromLatin1('0')) |
| 41 | .arg(error.raw, 8, 16, QChar::fromLatin1('0'))); | 38 | .arg(error.raw, 8, 16, QChar::fromLatin1('0')), |
| 39 | tr("An error occurred on %1 at %2.\nPlease try again or contact the developer of the " | ||
| 40 | "software.") | ||
| 41 | .arg(date_time.toString(QStringLiteral("dddd, MMMM d, yyyy"))) | ||
| 42 | .arg(date_time.toString(QStringLiteral("h:mm:ss A")))); | ||
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_text, | 45 | void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_text, |
| @@ -46,10 +47,11 @@ void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_te | |||
| 46 | std::function<void()> finished) const { | 47 | std::function<void()> finished) const { |
| 47 | callback = std::move(finished); | 48 | callback = std::move(finished); |
| 48 | emit MainWindowDisplayError( | 49 | emit MainWindowDisplayError( |
| 49 | tr("An error has occurred.\nError Code: %1-%2 (0x%3)\n\n%4\n\n%5") | 50 | tr("Error Code: %1-%2 (0x%3)") |
| 50 | .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) | 51 | .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) |
| 51 | .arg(error.description, 4, 10, QChar::fromLatin1('0')) | 52 | .arg(error.description, 4, 10, QChar::fromLatin1('0')) |
| 52 | .arg(error.raw, 8, 16, QChar::fromLatin1('0')) | 53 | .arg(error.raw, 8, 16, QChar::fromLatin1('0')), |
| 54 | tr("An error has occurred.\n\n%1\n\n%2") | ||
| 53 | .arg(QString::fromStdString(dialog_text)) | 55 | .arg(QString::fromStdString(dialog_text)) |
| 54 | .arg(QString::fromStdString(fullscreen_text))); | 56 | .arg(QString::fromStdString(fullscreen_text))); |
| 55 | } | 57 | } |
diff --git a/src/yuzu/applets/error.h b/src/yuzu/applets/error.h index b0932d895..8bd895a32 100644 --- a/src/yuzu/applets/error.h +++ b/src/yuzu/applets/error.h | |||
| @@ -24,7 +24,7 @@ public: | |||
| 24 | std::function<void()> finished) const override; | 24 | std::function<void()> finished) const override; |
| 25 | 25 | ||
| 26 | signals: | 26 | signals: |
| 27 | void MainWindowDisplayError(QString error) const; | 27 | void MainWindowDisplayError(QString error_code, QString error_text) const; |
| 28 | 28 | ||
| 29 | private: | 29 | private: |
| 30 | void MainWindowFinishedError(); | 30 | void MainWindowFinishedError(); |
diff --git a/src/yuzu/applets/software_keyboard.cpp b/src/yuzu/applets/software_keyboard.cpp index ab8cfd8ee..fd3368479 100644 --- a/src/yuzu/applets/software_keyboard.cpp +++ b/src/yuzu/applets/software_keyboard.cpp | |||
| @@ -1,153 +1,1641 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | 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 <algorithm> | 5 | #include <QCursor> |
| 6 | #include <mutex> | 6 | #include <QKeyEvent> |
| 7 | #include <QDialogButtonBox> | 7 | #include <QScreen> |
| 8 | #include <QFont> | 8 | |
| 9 | #include <QLabel> | 9 | #include "common/logging/log.h" |
| 10 | #include <QLineEdit> | 10 | #include "common/settings.h" |
| 11 | #include <QVBoxLayout> | 11 | #include "common/string_util.h" |
| 12 | #include "core/hle/lock.h" | 12 | #include "core/core.h" |
| 13 | #include "core/frontend/input_interpreter.h" | ||
| 14 | #include "ui_software_keyboard.h" | ||
| 13 | #include "yuzu/applets/software_keyboard.h" | 15 | #include "yuzu/applets/software_keyboard.h" |
| 14 | #include "yuzu/main.h" | 16 | #include "yuzu/main.h" |
| 17 | #include "yuzu/util/overlay_dialog.h" | ||
| 18 | |||
| 19 | namespace { | ||
| 20 | |||
| 21 | using namespace Service::AM::Applets; | ||
| 22 | |||
| 23 | constexpr float BASE_HEADER_FONT_SIZE = 23.0f; | ||
| 24 | constexpr float BASE_SUB_FONT_SIZE = 17.0f; | ||
| 25 | constexpr float BASE_EDITOR_FONT_SIZE = 26.0f; | ||
| 26 | constexpr float BASE_CHAR_BUTTON_FONT_SIZE = 28.0f; | ||
| 27 | constexpr float BASE_LABEL_BUTTON_FONT_SIZE = 18.0f; | ||
| 28 | constexpr float BASE_ICON_BUTTON_SIZE = 36.0f; | ||
| 29 | [[maybe_unused]] constexpr float BASE_WIDTH = 1280.0f; | ||
| 30 | constexpr float BASE_HEIGHT = 720.0f; | ||
| 31 | |||
| 32 | } // Anonymous namespace | ||
| 33 | |||
| 34 | QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog( | ||
| 35 | QWidget* parent, Core::System& system_, bool is_inline_, | ||
| 36 | Core::Frontend::KeyboardInitializeParameters initialize_parameters_) | ||
| 37 | : QDialog(parent), ui{std::make_unique<Ui::QtSoftwareKeyboardDialog>()}, system{system_}, | ||
| 38 | is_inline{is_inline_}, initialize_parameters{std::move(initialize_parameters_)} { | ||
| 39 | ui->setupUi(this); | ||
| 40 | |||
| 41 | setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowTitleHint | | ||
| 42 | Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint); | ||
| 43 | setWindowModality(Qt::WindowModal); | ||
| 44 | setAttribute(Qt::WA_DeleteOnClose); | ||
| 45 | setAttribute(Qt::WA_TranslucentBackground); | ||
| 46 | |||
| 47 | keyboard_buttons = {{ | ||
| 48 | {{ | ||
| 49 | { | ||
| 50 | ui->button_1, | ||
| 51 | ui->button_2, | ||
| 52 | ui->button_3, | ||
| 53 | ui->button_4, | ||
| 54 | ui->button_5, | ||
| 55 | ui->button_6, | ||
| 56 | ui->button_7, | ||
| 57 | ui->button_8, | ||
| 58 | ui->button_9, | ||
| 59 | ui->button_0, | ||
| 60 | ui->button_minus, | ||
| 61 | ui->button_backspace, | ||
| 62 | }, | ||
| 63 | { | ||
| 64 | ui->button_q, | ||
| 65 | ui->button_w, | ||
| 66 | ui->button_e, | ||
| 67 | ui->button_r, | ||
| 68 | ui->button_t, | ||
| 69 | ui->button_y, | ||
| 70 | ui->button_u, | ||
| 71 | ui->button_i, | ||
| 72 | ui->button_o, | ||
| 73 | ui->button_p, | ||
| 74 | ui->button_slash, | ||
| 75 | ui->button_return, | ||
| 76 | }, | ||
| 77 | { | ||
| 78 | ui->button_a, | ||
| 79 | ui->button_s, | ||
| 80 | ui->button_d, | ||
| 81 | ui->button_f, | ||
| 82 | ui->button_g, | ||
| 83 | ui->button_h, | ||
| 84 | ui->button_j, | ||
| 85 | ui->button_k, | ||
| 86 | ui->button_l, | ||
| 87 | ui->button_colon, | ||
| 88 | ui->button_apostrophe, | ||
| 89 | ui->button_return, | ||
| 90 | }, | ||
| 91 | { | ||
| 92 | ui->button_z, | ||
| 93 | ui->button_x, | ||
| 94 | ui->button_c, | ||
| 95 | ui->button_v, | ||
| 96 | ui->button_b, | ||
| 97 | ui->button_n, | ||
| 98 | ui->button_m, | ||
| 99 | ui->button_comma, | ||
| 100 | ui->button_dot, | ||
| 101 | ui->button_question, | ||
| 102 | ui->button_exclamation, | ||
| 103 | ui->button_ok, | ||
| 104 | }, | ||
| 105 | { | ||
| 106 | ui->button_shift, | ||
| 107 | ui->button_shift, | ||
| 108 | ui->button_space, | ||
| 109 | ui->button_space, | ||
| 110 | ui->button_space, | ||
| 111 | ui->button_space, | ||
| 112 | ui->button_space, | ||
| 113 | ui->button_space, | ||
| 114 | ui->button_space, | ||
| 115 | ui->button_space, | ||
| 116 | ui->button_space, | ||
| 117 | ui->button_ok, | ||
| 118 | }, | ||
| 119 | }}, | ||
| 120 | {{ | ||
| 121 | { | ||
| 122 | ui->button_hash, | ||
| 123 | ui->button_left_bracket, | ||
| 124 | ui->button_right_bracket, | ||
| 125 | ui->button_dollar, | ||
| 126 | ui->button_percent, | ||
| 127 | ui->button_circumflex, | ||
| 128 | ui->button_ampersand, | ||
| 129 | ui->button_asterisk, | ||
| 130 | ui->button_left_parenthesis, | ||
| 131 | ui->button_right_parenthesis, | ||
| 132 | ui->button_underscore, | ||
| 133 | ui->button_backspace_shift, | ||
| 134 | }, | ||
| 135 | { | ||
| 136 | ui->button_q_shift, | ||
| 137 | ui->button_w_shift, | ||
| 138 | ui->button_e_shift, | ||
| 139 | ui->button_r_shift, | ||
| 140 | ui->button_t_shift, | ||
| 141 | ui->button_y_shift, | ||
| 142 | ui->button_u_shift, | ||
| 143 | ui->button_i_shift, | ||
| 144 | ui->button_o_shift, | ||
| 145 | ui->button_p_shift, | ||
| 146 | ui->button_at, | ||
| 147 | ui->button_return_shift, | ||
| 148 | }, | ||
| 149 | { | ||
| 150 | ui->button_a_shift, | ||
| 151 | ui->button_s_shift, | ||
| 152 | ui->button_d_shift, | ||
| 153 | ui->button_f_shift, | ||
| 154 | ui->button_g_shift, | ||
| 155 | ui->button_h_shift, | ||
| 156 | ui->button_j_shift, | ||
| 157 | ui->button_k_shift, | ||
| 158 | ui->button_l_shift, | ||
| 159 | ui->button_semicolon, | ||
| 160 | ui->button_quotation, | ||
| 161 | ui->button_return_shift, | ||
| 162 | }, | ||
| 163 | { | ||
| 164 | ui->button_z_shift, | ||
| 165 | ui->button_x_shift, | ||
| 166 | ui->button_c_shift, | ||
| 167 | ui->button_v_shift, | ||
| 168 | ui->button_b_shift, | ||
| 169 | ui->button_n_shift, | ||
| 170 | ui->button_m_shift, | ||
| 171 | ui->button_less_than, | ||
| 172 | ui->button_greater_than, | ||
| 173 | ui->button_plus, | ||
| 174 | ui->button_equal, | ||
| 175 | ui->button_ok_shift, | ||
| 176 | }, | ||
| 177 | { | ||
| 178 | ui->button_shift_shift, | ||
| 179 | ui->button_shift_shift, | ||
| 180 | ui->button_space_shift, | ||
| 181 | ui->button_space_shift, | ||
| 182 | ui->button_space_shift, | ||
| 183 | ui->button_space_shift, | ||
| 184 | ui->button_space_shift, | ||
| 185 | ui->button_space_shift, | ||
| 186 | ui->button_space_shift, | ||
| 187 | ui->button_space_shift, | ||
| 188 | ui->button_space_shift, | ||
| 189 | ui->button_ok_shift, | ||
| 190 | }, | ||
| 191 | }}, | ||
| 192 | }}; | ||
| 15 | 193 | ||
| 16 | QtSoftwareKeyboardValidator::QtSoftwareKeyboardValidator( | 194 | numberpad_buttons = {{ |
| 17 | Core::Frontend::SoftwareKeyboardParameters parameters) | 195 | { |
| 18 | : parameters(std::move(parameters)) {} | 196 | ui->button_1_num, |
| 197 | ui->button_2_num, | ||
| 198 | ui->button_3_num, | ||
| 199 | ui->button_backspace_num, | ||
| 200 | }, | ||
| 201 | { | ||
| 202 | ui->button_4_num, | ||
| 203 | ui->button_5_num, | ||
| 204 | ui->button_6_num, | ||
| 205 | ui->button_ok_num, | ||
| 206 | }, | ||
| 207 | { | ||
| 208 | ui->button_7_num, | ||
| 209 | ui->button_8_num, | ||
| 210 | ui->button_9_num, | ||
| 211 | ui->button_ok_num, | ||
| 212 | }, | ||
| 213 | { | ||
| 214 | nullptr, | ||
| 215 | ui->button_0_num, | ||
| 216 | nullptr, | ||
| 217 | ui->button_ok_num, | ||
| 218 | }, | ||
| 219 | }}; | ||
| 19 | 220 | ||
| 20 | QValidator::State QtSoftwareKeyboardValidator::validate(QString& input, int& pos) const { | 221 | all_buttons = { |
| 21 | if (input.size() > static_cast<s64>(parameters.max_length)) { | 222 | ui->button_1, |
| 22 | return Invalid; | 223 | ui->button_2, |
| 224 | ui->button_3, | ||
| 225 | ui->button_4, | ||
| 226 | ui->button_5, | ||
| 227 | ui->button_6, | ||
| 228 | ui->button_7, | ||
| 229 | ui->button_8, | ||
| 230 | ui->button_9, | ||
| 231 | ui->button_0, | ||
| 232 | ui->button_minus, | ||
| 233 | ui->button_backspace, | ||
| 234 | ui->button_q, | ||
| 235 | ui->button_w, | ||
| 236 | ui->button_e, | ||
| 237 | ui->button_r, | ||
| 238 | ui->button_t, | ||
| 239 | ui->button_y, | ||
| 240 | ui->button_u, | ||
| 241 | ui->button_i, | ||
| 242 | ui->button_o, | ||
| 243 | ui->button_p, | ||
| 244 | ui->button_slash, | ||
| 245 | ui->button_return, | ||
| 246 | ui->button_a, | ||
| 247 | ui->button_s, | ||
| 248 | ui->button_d, | ||
| 249 | ui->button_f, | ||
| 250 | ui->button_g, | ||
| 251 | ui->button_h, | ||
| 252 | ui->button_j, | ||
| 253 | ui->button_k, | ||
| 254 | ui->button_l, | ||
| 255 | ui->button_colon, | ||
| 256 | ui->button_apostrophe, | ||
| 257 | ui->button_z, | ||
| 258 | ui->button_x, | ||
| 259 | ui->button_c, | ||
| 260 | ui->button_v, | ||
| 261 | ui->button_b, | ||
| 262 | ui->button_n, | ||
| 263 | ui->button_m, | ||
| 264 | ui->button_comma, | ||
| 265 | ui->button_dot, | ||
| 266 | ui->button_question, | ||
| 267 | ui->button_exclamation, | ||
| 268 | ui->button_ok, | ||
| 269 | ui->button_shift, | ||
| 270 | ui->button_space, | ||
| 271 | ui->button_hash, | ||
| 272 | ui->button_left_bracket, | ||
| 273 | ui->button_right_bracket, | ||
| 274 | ui->button_dollar, | ||
| 275 | ui->button_percent, | ||
| 276 | ui->button_circumflex, | ||
| 277 | ui->button_ampersand, | ||
| 278 | ui->button_asterisk, | ||
| 279 | ui->button_left_parenthesis, | ||
| 280 | ui->button_right_parenthesis, | ||
| 281 | ui->button_underscore, | ||
| 282 | ui->button_backspace_shift, | ||
| 283 | ui->button_q_shift, | ||
| 284 | ui->button_w_shift, | ||
| 285 | ui->button_e_shift, | ||
| 286 | ui->button_r_shift, | ||
| 287 | ui->button_t_shift, | ||
| 288 | ui->button_y_shift, | ||
| 289 | ui->button_u_shift, | ||
| 290 | ui->button_i_shift, | ||
| 291 | ui->button_o_shift, | ||
| 292 | ui->button_p_shift, | ||
| 293 | ui->button_at, | ||
| 294 | ui->button_return_shift, | ||
| 295 | ui->button_a_shift, | ||
| 296 | ui->button_s_shift, | ||
| 297 | ui->button_d_shift, | ||
| 298 | ui->button_f_shift, | ||
| 299 | ui->button_g_shift, | ||
| 300 | ui->button_h_shift, | ||
| 301 | ui->button_j_shift, | ||
| 302 | ui->button_k_shift, | ||
| 303 | ui->button_l_shift, | ||
| 304 | ui->button_semicolon, | ||
| 305 | ui->button_quotation, | ||
| 306 | ui->button_z_shift, | ||
| 307 | ui->button_x_shift, | ||
| 308 | ui->button_c_shift, | ||
| 309 | ui->button_v_shift, | ||
| 310 | ui->button_b_shift, | ||
| 311 | ui->button_n_shift, | ||
| 312 | ui->button_m_shift, | ||
| 313 | ui->button_less_than, | ||
| 314 | ui->button_greater_than, | ||
| 315 | ui->button_plus, | ||
| 316 | ui->button_equal, | ||
| 317 | ui->button_ok_shift, | ||
| 318 | ui->button_shift_shift, | ||
| 319 | ui->button_space_shift, | ||
| 320 | ui->button_1_num, | ||
| 321 | ui->button_2_num, | ||
| 322 | ui->button_3_num, | ||
| 323 | ui->button_backspace_num, | ||
| 324 | ui->button_4_num, | ||
| 325 | ui->button_5_num, | ||
| 326 | ui->button_6_num, | ||
| 327 | ui->button_ok_num, | ||
| 328 | ui->button_7_num, | ||
| 329 | ui->button_8_num, | ||
| 330 | ui->button_9_num, | ||
| 331 | ui->button_0_num, | ||
| 332 | }; | ||
| 333 | |||
| 334 | SetupMouseHover(); | ||
| 335 | |||
| 336 | if (!initialize_parameters.ok_text.empty()) { | ||
| 337 | ui->button_ok->setText(QString::fromStdU16String(initialize_parameters.ok_text)); | ||
| 23 | } | 338 | } |
| 24 | if (parameters.disable_space && input.contains(QLatin1Char{' '})) { | 339 | |
| 25 | return Invalid; | 340 | ui->label_header->setText(QString::fromStdU16String(initialize_parameters.header_text)); |
| 341 | ui->label_sub->setText(QString::fromStdU16String(initialize_parameters.sub_text)); | ||
| 342 | |||
| 343 | current_text = initialize_parameters.initial_text; | ||
| 344 | cursor_position = initialize_parameters.initial_cursor_position; | ||
| 345 | |||
| 346 | SetTextDrawType(); | ||
| 347 | |||
| 348 | for (auto* button : all_buttons) { | ||
| 349 | connect(button, &QPushButton::clicked, this, [this, button](bool) { | ||
| 350 | if (is_inline) { | ||
| 351 | InlineKeyboardButtonClicked(button); | ||
| 352 | } else { | ||
| 353 | NormalKeyboardButtonClicked(button); | ||
| 354 | } | ||
| 355 | }); | ||
| 26 | } | 356 | } |
| 27 | if (parameters.disable_address && input.contains(QLatin1Char{'@'})) { | 357 | |
| 28 | return Invalid; | 358 | // TODO (Morph): Remove this when InputInterpreter no longer relies on the HID backend |
| 359 | if (system.IsPoweredOn()) { | ||
| 360 | input_interpreter = std::make_unique<InputInterpreter>(system); | ||
| 29 | } | 361 | } |
| 30 | if (parameters.disable_percent && input.contains(QLatin1Char{'%'})) { | 362 | } |
| 31 | return Invalid; | 363 | |
| 364 | QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() { | ||
| 365 | StopInputThread(); | ||
| 366 | } | ||
| 367 | |||
| 368 | void QtSoftwareKeyboardDialog::ShowNormalKeyboard(QPoint pos, QSize size) { | ||
| 369 | if (isVisible()) { | ||
| 370 | return; | ||
| 32 | } | 371 | } |
| 33 | if (parameters.disable_slash && | 372 | |
| 34 | (input.contains(QLatin1Char{'/'}) || input.contains(QLatin1Char{'\\'}))) { | 373 | MoveAndResizeWindow(pos, size); |
| 35 | return Invalid; | 374 | |
| 375 | SetKeyboardType(); | ||
| 376 | SetPasswordMode(); | ||
| 377 | SetControllerImage(); | ||
| 378 | DisableKeyboardButtons(); | ||
| 379 | SetBackspaceOkEnabled(); | ||
| 380 | |||
| 381 | open(); | ||
| 382 | } | ||
| 383 | |||
| 384 | void QtSoftwareKeyboardDialog::ShowTextCheckDialog( | ||
| 385 | Service::AM::Applets::SwkbdTextCheckResult text_check_result, | ||
| 386 | std::u16string text_check_message) { | ||
| 387 | switch (text_check_result) { | ||
| 388 | case SwkbdTextCheckResult::Success: | ||
| 389 | case SwkbdTextCheckResult::Silent: | ||
| 390 | default: | ||
| 391 | break; | ||
| 392 | case SwkbdTextCheckResult::Failure: { | ||
| 393 | StopInputThread(); | ||
| 394 | |||
| 395 | OverlayDialog dialog(this, system, QString{}, QString::fromStdU16String(text_check_message), | ||
| 396 | QString{}, tr("OK"), Qt::AlignCenter); | ||
| 397 | dialog.exec(); | ||
| 398 | |||
| 399 | StartInputThread(); | ||
| 400 | break; | ||
| 36 | } | 401 | } |
| 37 | if (parameters.disable_number && | 402 | case SwkbdTextCheckResult::Confirm: { |
| 38 | std::any_of(input.begin(), input.end(), [](QChar c) { return c.isDigit(); })) { | 403 | StopInputThread(); |
| 39 | return Invalid; | 404 | |
| 405 | OverlayDialog dialog(this, system, QString{}, QString::fromStdU16String(text_check_message), | ||
| 406 | tr("Cancel"), tr("OK"), Qt::AlignCenter); | ||
| 407 | if (dialog.exec() == QDialog::Accepted) { | ||
| 408 | emit SubmitNormalText(SwkbdResult::Ok, current_text); | ||
| 409 | break; | ||
| 410 | } | ||
| 411 | |||
| 412 | StartInputThread(); | ||
| 413 | break; | ||
| 40 | } | 414 | } |
| 415 | } | ||
| 416 | } | ||
| 417 | |||
| 418 | void QtSoftwareKeyboardDialog::ShowInlineKeyboard( | ||
| 419 | Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos, QSize size) { | ||
| 420 | MoveAndResizeWindow(pos, size); | ||
| 421 | |||
| 422 | ui->topOSK->setStyleSheet(QStringLiteral("background: rgba(0, 0, 0, 0);")); | ||
| 423 | |||
| 424 | ui->headerOSK->hide(); | ||
| 425 | ui->subOSK->hide(); | ||
| 426 | ui->inputOSK->hide(); | ||
| 427 | ui->charactersOSK->hide(); | ||
| 428 | ui->inputBoxOSK->hide(); | ||
| 429 | ui->charactersBoxOSK->hide(); | ||
| 430 | |||
| 431 | initialize_parameters.max_text_length = appear_parameters.max_text_length; | ||
| 432 | initialize_parameters.min_text_length = appear_parameters.min_text_length; | ||
| 433 | initialize_parameters.type = appear_parameters.type; | ||
| 434 | initialize_parameters.key_disable_flags = appear_parameters.key_disable_flags; | ||
| 435 | initialize_parameters.enable_backspace_button = appear_parameters.enable_backspace_button; | ||
| 436 | initialize_parameters.enable_return_button = appear_parameters.enable_return_button; | ||
| 437 | initialize_parameters.disable_cancel_button = initialize_parameters.disable_cancel_button; | ||
| 41 | 438 | ||
| 42 | if (parameters.disable_download_code && std::any_of(input.begin(), input.end(), [](QChar c) { | 439 | SetKeyboardType(); |
| 43 | return c == QLatin1Char{'O'} || c == QLatin1Char{'I'}; | 440 | SetControllerImage(); |
| 44 | })) { | 441 | DisableKeyboardButtons(); |
| 45 | return Invalid; | 442 | SetBackspaceOkEnabled(); |
| 443 | |||
| 444 | open(); | ||
| 445 | } | ||
| 446 | |||
| 447 | void QtSoftwareKeyboardDialog::HideInlineKeyboard() { | ||
| 448 | StopInputThread(); | ||
| 449 | QDialog::hide(); | ||
| 450 | } | ||
| 451 | |||
| 452 | void QtSoftwareKeyboardDialog::InlineTextChanged( | ||
| 453 | Core::Frontend::InlineTextParameters text_parameters) { | ||
| 454 | current_text = text_parameters.input_text; | ||
| 455 | cursor_position = text_parameters.cursor_position; | ||
| 456 | |||
| 457 | SetBackspaceOkEnabled(); | ||
| 458 | } | ||
| 459 | |||
| 460 | void QtSoftwareKeyboardDialog::ExitKeyboard() { | ||
| 461 | StopInputThread(); | ||
| 462 | QDialog::done(QDialog::Accepted); | ||
| 463 | } | ||
| 464 | |||
| 465 | void QtSoftwareKeyboardDialog::open() { | ||
| 466 | QDialog::open(); | ||
| 467 | |||
| 468 | row = 0; | ||
| 469 | column = 0; | ||
| 470 | |||
| 471 | const auto* const curr_button = | ||
| 472 | keyboard_buttons[static_cast<int>(bottom_osk_index)][row][column]; | ||
| 473 | |||
| 474 | // This is a workaround for setFocus() randomly not showing focus in the UI | ||
| 475 | QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center())); | ||
| 476 | |||
| 477 | StartInputThread(); | ||
| 478 | } | ||
| 479 | |||
| 480 | void QtSoftwareKeyboardDialog::reject() { | ||
| 481 | // Pressing the ESC key in a dialog calls QDialog::reject(). | ||
| 482 | // We will override this behavior to the "Cancel" action on the software keyboard. | ||
| 483 | if (is_inline) { | ||
| 484 | emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position); | ||
| 485 | } else { | ||
| 486 | emit SubmitNormalText(SwkbdResult::Cancel, current_text); | ||
| 46 | } | 487 | } |
| 488 | } | ||
| 489 | |||
| 490 | void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) { | ||
| 491 | if (!is_inline) { | ||
| 492 | QDialog::keyPressEvent(event); | ||
| 493 | return; | ||
| 494 | } | ||
| 495 | |||
| 496 | const auto entered_key = event->key(); | ||
| 47 | 497 | ||
| 48 | return Acceptable; | 498 | switch (entered_key) { |
| 499 | case Qt::Key_Escape: | ||
| 500 | QDialog::keyPressEvent(event); | ||
| 501 | return; | ||
| 502 | case Qt::Key_Backspace: | ||
| 503 | switch (bottom_osk_index) { | ||
| 504 | case BottomOSKIndex::LowerCase: | ||
| 505 | ui->button_backspace->click(); | ||
| 506 | break; | ||
| 507 | case BottomOSKIndex::UpperCase: | ||
| 508 | ui->button_backspace_shift->click(); | ||
| 509 | break; | ||
| 510 | case BottomOSKIndex::NumberPad: | ||
| 511 | ui->button_backspace_num->click(); | ||
| 512 | break; | ||
| 513 | default: | ||
| 514 | break; | ||
| 515 | } | ||
| 516 | return; | ||
| 517 | case Qt::Key_Return: | ||
| 518 | switch (bottom_osk_index) { | ||
| 519 | case BottomOSKIndex::LowerCase: | ||
| 520 | ui->button_ok->click(); | ||
| 521 | break; | ||
| 522 | case BottomOSKIndex::UpperCase: | ||
| 523 | ui->button_ok_shift->click(); | ||
| 524 | break; | ||
| 525 | case BottomOSKIndex::NumberPad: | ||
| 526 | ui->button_ok_num->click(); | ||
| 527 | break; | ||
| 528 | default: | ||
| 529 | break; | ||
| 530 | } | ||
| 531 | return; | ||
| 532 | case Qt::Key_Left: | ||
| 533 | MoveTextCursorDirection(Direction::Left); | ||
| 534 | return; | ||
| 535 | case Qt::Key_Right: | ||
| 536 | MoveTextCursorDirection(Direction::Right); | ||
| 537 | return; | ||
| 538 | default: | ||
| 539 | break; | ||
| 540 | } | ||
| 541 | |||
| 542 | const auto entered_text = event->text(); | ||
| 543 | |||
| 544 | if (entered_text.isEmpty()) { | ||
| 545 | return; | ||
| 546 | } | ||
| 547 | |||
| 548 | InlineTextInsertString(entered_text.toStdU16String()); | ||
| 49 | } | 549 | } |
| 50 | 550 | ||
| 51 | QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog( | 551 | void QtSoftwareKeyboardDialog::MoveAndResizeWindow(QPoint pos, QSize size) { |
| 52 | QWidget* parent, Core::Frontend::SoftwareKeyboardParameters parameters_) | 552 | QDialog::move(pos); |
| 53 | : QDialog(parent), parameters(std::move(parameters_)) { | 553 | QDialog::resize(size); |
| 54 | layout = new QVBoxLayout; | 554 | |
| 55 | 555 | // High DPI | |
| 56 | header_label = new QLabel(QString::fromStdU16String(parameters.header_text)); | 556 | const float dpi_scale = qApp->screenAt(pos)->logicalDotsPerInch() / 96.0f; |
| 57 | header_label->setFont({header_label->font().family(), 11, QFont::Bold}); | 557 | |
| 58 | if (header_label->text().isEmpty()) | 558 | RescaleKeyboardElements(size.width(), size.height(), dpi_scale); |
| 59 | header_label->setText(tr("Enter text:")); | 559 | } |
| 60 | 560 | ||
| 61 | sub_label = new QLabel(QString::fromStdU16String(parameters.sub_text)); | 561 | void QtSoftwareKeyboardDialog::RescaleKeyboardElements(float width, float height, float dpi_scale) { |
| 62 | sub_label->setFont({sub_label->font().family(), sub_label->font().pointSize(), | 562 | const auto header_font_size = BASE_HEADER_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale; |
| 63 | sub_label->font().weight(), true}); | 563 | const auto sub_font_size = BASE_SUB_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale; |
| 64 | sub_label->setHidden(parameters.sub_text.empty()); | 564 | const auto editor_font_size = BASE_EDITOR_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale; |
| 65 | 565 | const auto char_button_font_size = | |
| 66 | guide_label = new QLabel(QString::fromStdU16String(parameters.guide_text)); | 566 | BASE_CHAR_BUTTON_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale; |
| 67 | guide_label->setHidden(parameters.guide_text.empty()); | 567 | const auto label_button_font_size = |
| 68 | 568 | BASE_LABEL_BUTTON_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale; | |
| 69 | length_label = new QLabel(QStringLiteral("0/%1").arg(parameters.max_length)); | 569 | |
| 70 | length_label->setAlignment(Qt::AlignRight); | 570 | QFont header_font(QStringLiteral("MS Shell Dlg 2"), header_font_size, QFont::Normal); |
| 71 | length_label->setFont({length_label->font().family(), 8}); | 571 | QFont sub_font(QStringLiteral("MS Shell Dlg 2"), sub_font_size, QFont::Normal); |
| 72 | 572 | QFont editor_font(QStringLiteral("MS Shell Dlg 2"), editor_font_size, QFont::Normal); | |
| 73 | line_edit = new QLineEdit; | 573 | QFont char_button_font(QStringLiteral("MS Shell Dlg 2"), char_button_font_size, QFont::Normal); |
| 74 | line_edit->setValidator(new QtSoftwareKeyboardValidator(parameters)); | 574 | QFont label_button_font(QStringLiteral("MS Shell Dlg 2"), label_button_font_size, |
| 75 | line_edit->setMaxLength(static_cast<int>(parameters.max_length)); | 575 | QFont::Normal); |
| 76 | line_edit->setText(QString::fromStdU16String(parameters.initial_text)); | 576 | |
| 77 | line_edit->setCursorPosition( | 577 | ui->label_header->setFont(header_font); |
| 78 | parameters.cursor_at_beginning ? 0 : static_cast<int>(parameters.initial_text.size())); | 578 | ui->label_sub->setFont(sub_font); |
| 79 | line_edit->setEchoMode(parameters.password ? QLineEdit::Password : QLineEdit::Normal); | 579 | ui->line_edit_osk->setFont(editor_font); |
| 80 | 580 | ui->text_edit_osk->setFont(editor_font); | |
| 81 | connect(line_edit, &QLineEdit::textChanged, this, [this](const QString& text) { | 581 | ui->label_characters->setFont(sub_font); |
| 82 | length_label->setText(QStringLiteral("%1/%2").arg(text.size()).arg(parameters.max_length)); | 582 | ui->label_characters_box->setFont(sub_font); |
| 83 | }); | 583 | |
| 84 | 584 | ui->label_shift->setFont(label_button_font); | |
| 85 | buttons = new QDialogButtonBox(QDialogButtonBox::Cancel); | 585 | ui->label_shift_shift->setFont(label_button_font); |
| 86 | if (parameters.submit_text.empty()) { | 586 | ui->label_cancel->setFont(label_button_font); |
| 87 | buttons->addButton(QDialogButtonBox::Ok); | 587 | ui->label_cancel_shift->setFont(label_button_font); |
| 588 | ui->label_cancel_num->setFont(label_button_font); | ||
| 589 | ui->label_enter->setFont(label_button_font); | ||
| 590 | ui->label_enter_shift->setFont(label_button_font); | ||
| 591 | ui->label_enter_num->setFont(label_button_font); | ||
| 592 | |||
| 593 | for (auto* button : all_buttons) { | ||
| 594 | if (button == ui->button_return || button == ui->button_return_shift) { | ||
| 595 | button->setFont(label_button_font); | ||
| 596 | continue; | ||
| 597 | } | ||
| 598 | |||
| 599 | if (button == ui->button_space || button == ui->button_space_shift) { | ||
| 600 | button->setFont(label_button_font); | ||
| 601 | continue; | ||
| 602 | } | ||
| 603 | |||
| 604 | if (button == ui->button_shift || button == ui->button_shift_shift) { | ||
| 605 | button->setFont(label_button_font); | ||
| 606 | button->setIconSize(QSize(BASE_ICON_BUTTON_SIZE, BASE_ICON_BUTTON_SIZE) * | ||
| 607 | (height / BASE_HEIGHT)); | ||
| 608 | continue; | ||
| 609 | } | ||
| 610 | |||
| 611 | if (button == ui->button_backspace || button == ui->button_backspace_shift || | ||
| 612 | button == ui->button_backspace_num) { | ||
| 613 | button->setFont(label_button_font); | ||
| 614 | button->setIconSize(QSize(BASE_ICON_BUTTON_SIZE, BASE_ICON_BUTTON_SIZE) * | ||
| 615 | (height / BASE_HEIGHT)); | ||
| 616 | continue; | ||
| 617 | } | ||
| 618 | |||
| 619 | if (button == ui->button_ok || button == ui->button_ok_shift || | ||
| 620 | button == ui->button_ok_num) { | ||
| 621 | button->setFont(label_button_font); | ||
| 622 | continue; | ||
| 623 | } | ||
| 624 | |||
| 625 | button->setFont(char_button_font); | ||
| 626 | } | ||
| 627 | } | ||
| 628 | |||
| 629 | void QtSoftwareKeyboardDialog::SetKeyboardType() { | ||
| 630 | switch (initialize_parameters.type) { | ||
| 631 | case SwkbdType::Normal: | ||
| 632 | case SwkbdType::Qwerty: | ||
| 633 | case SwkbdType::Unknown3: | ||
| 634 | case SwkbdType::Latin: | ||
| 635 | case SwkbdType::SimplifiedChinese: | ||
| 636 | case SwkbdType::TraditionalChinese: | ||
| 637 | case SwkbdType::Korean: | ||
| 638 | default: { | ||
| 639 | bottom_osk_index = BottomOSKIndex::LowerCase; | ||
| 640 | ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index)); | ||
| 641 | |||
| 642 | ui->verticalLayout_2->setStretch(0, 320); | ||
| 643 | ui->verticalLayout_2->setStretch(1, 400); | ||
| 644 | |||
| 645 | ui->gridLineOSK->setRowStretch(5, 94); | ||
| 646 | ui->gridBoxOSK->setRowStretch(2, 81); | ||
| 647 | break; | ||
| 648 | } | ||
| 649 | case SwkbdType::NumberPad: { | ||
| 650 | bottom_osk_index = BottomOSKIndex::NumberPad; | ||
| 651 | ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index)); | ||
| 652 | |||
| 653 | ui->verticalLayout_2->setStretch(0, 370); | ||
| 654 | ui->verticalLayout_2->setStretch(1, 350); | ||
| 655 | |||
| 656 | ui->gridLineOSK->setRowStretch(5, 144); | ||
| 657 | ui->gridBoxOSK->setRowStretch(2, 131); | ||
| 658 | break; | ||
| 659 | } | ||
| 660 | } | ||
| 661 | } | ||
| 662 | |||
| 663 | void QtSoftwareKeyboardDialog::SetPasswordMode() { | ||
| 664 | switch (initialize_parameters.password_mode) { | ||
| 665 | case SwkbdPasswordMode::Disabled: | ||
| 666 | default: | ||
| 667 | ui->line_edit_osk->setEchoMode(QLineEdit::Normal); | ||
| 668 | break; | ||
| 669 | case SwkbdPasswordMode::Enabled: | ||
| 670 | ui->line_edit_osk->setEchoMode(QLineEdit::Password); | ||
| 671 | break; | ||
| 672 | } | ||
| 673 | } | ||
| 674 | |||
| 675 | void QtSoftwareKeyboardDialog::SetTextDrawType() { | ||
| 676 | switch (initialize_parameters.text_draw_type) { | ||
| 677 | case SwkbdTextDrawType::Line: | ||
| 678 | case SwkbdTextDrawType::DownloadCode: { | ||
| 679 | ui->topOSK->setCurrentIndex(0); | ||
| 680 | |||
| 681 | if (initialize_parameters.max_text_length <= 10) { | ||
| 682 | ui->gridLineOSK->setColumnStretch(0, 390); | ||
| 683 | ui->gridLineOSK->setColumnStretch(1, 500); | ||
| 684 | ui->gridLineOSK->setColumnStretch(2, 390); | ||
| 685 | } else { | ||
| 686 | ui->gridLineOSK->setColumnStretch(0, 130); | ||
| 687 | ui->gridLineOSK->setColumnStretch(1, 1020); | ||
| 688 | ui->gridLineOSK->setColumnStretch(2, 130); | ||
| 689 | } | ||
| 690 | |||
| 691 | if (is_inline) { | ||
| 692 | return; | ||
| 693 | } | ||
| 694 | |||
| 695 | connect(ui->line_edit_osk, &QLineEdit::textChanged, [this](const QString& changed_string) { | ||
| 696 | const auto is_valid = ValidateInputText(changed_string); | ||
| 697 | |||
| 698 | const auto text_length = static_cast<u32>(changed_string.length()); | ||
| 699 | |||
| 700 | ui->label_characters->setText(QStringLiteral("%1/%2") | ||
| 701 | .arg(text_length) | ||
| 702 | .arg(initialize_parameters.max_text_length)); | ||
| 703 | |||
| 704 | ui->button_ok->setEnabled(is_valid); | ||
| 705 | ui->button_ok_shift->setEnabled(is_valid); | ||
| 706 | ui->button_ok_num->setEnabled(is_valid); | ||
| 707 | |||
| 708 | ui->line_edit_osk->setFocus(); | ||
| 709 | }); | ||
| 710 | |||
| 711 | connect(ui->line_edit_osk, &QLineEdit::cursorPositionChanged, | ||
| 712 | [this](int old_cursor_position, int new_cursor_position) { | ||
| 713 | ui->button_backspace->setEnabled( | ||
| 714 | initialize_parameters.enable_backspace_button && new_cursor_position > 0); | ||
| 715 | ui->button_backspace_shift->setEnabled( | ||
| 716 | initialize_parameters.enable_backspace_button && new_cursor_position > 0); | ||
| 717 | ui->button_backspace_num->setEnabled( | ||
| 718 | initialize_parameters.enable_backspace_button && new_cursor_position > 0); | ||
| 719 | |||
| 720 | ui->line_edit_osk->setFocus(); | ||
| 721 | }); | ||
| 722 | |||
| 723 | connect(ui->line_edit_osk, &QLineEdit::returnPressed, [this] { | ||
| 724 | switch (bottom_osk_index) { | ||
| 725 | case BottomOSKIndex::LowerCase: | ||
| 726 | ui->button_ok->click(); | ||
| 727 | break; | ||
| 728 | case BottomOSKIndex::UpperCase: | ||
| 729 | ui->button_ok_shift->click(); | ||
| 730 | break; | ||
| 731 | case BottomOSKIndex::NumberPad: | ||
| 732 | ui->button_ok_num->click(); | ||
| 733 | break; | ||
| 734 | default: | ||
| 735 | break; | ||
| 736 | } | ||
| 737 | }); | ||
| 738 | |||
| 739 | ui->line_edit_osk->setPlaceholderText( | ||
| 740 | QString::fromStdU16String(initialize_parameters.guide_text)); | ||
| 741 | ui->line_edit_osk->setText(QString::fromStdU16String(initialize_parameters.initial_text)); | ||
| 742 | ui->line_edit_osk->setMaxLength(initialize_parameters.max_text_length); | ||
| 743 | ui->line_edit_osk->setCursorPosition(initialize_parameters.initial_cursor_position); | ||
| 744 | |||
| 745 | ui->label_characters->setText(QStringLiteral("%1/%2") | ||
| 746 | .arg(initialize_parameters.initial_text.size()) | ||
| 747 | .arg(initialize_parameters.max_text_length)); | ||
| 748 | break; | ||
| 749 | } | ||
| 750 | case SwkbdTextDrawType::Box: | ||
| 751 | default: { | ||
| 752 | ui->topOSK->setCurrentIndex(1); | ||
| 753 | |||
| 754 | if (is_inline) { | ||
| 755 | return; | ||
| 756 | } | ||
| 757 | |||
| 758 | connect(ui->text_edit_osk, &QTextEdit::textChanged, [this] { | ||
| 759 | if (static_cast<u32>(ui->text_edit_osk->toPlainText().length()) > | ||
| 760 | initialize_parameters.max_text_length) { | ||
| 761 | auto text_cursor = ui->text_edit_osk->textCursor(); | ||
| 762 | ui->text_edit_osk->setTextCursor(text_cursor); | ||
| 763 | text_cursor.deletePreviousChar(); | ||
| 764 | } | ||
| 765 | |||
| 766 | const auto is_valid = ValidateInputText(ui->text_edit_osk->toPlainText()); | ||
| 767 | |||
| 768 | const auto text_length = static_cast<u32>(ui->text_edit_osk->toPlainText().length()); | ||
| 769 | |||
| 770 | ui->label_characters_box->setText(QStringLiteral("%1/%2") | ||
| 771 | .arg(text_length) | ||
| 772 | .arg(initialize_parameters.max_text_length)); | ||
| 773 | |||
| 774 | ui->button_ok->setEnabled(is_valid); | ||
| 775 | ui->button_ok_shift->setEnabled(is_valid); | ||
| 776 | ui->button_ok_num->setEnabled(is_valid); | ||
| 777 | |||
| 778 | ui->text_edit_osk->setFocus(); | ||
| 779 | }); | ||
| 780 | |||
| 781 | connect(ui->text_edit_osk, &QTextEdit::cursorPositionChanged, [this] { | ||
| 782 | const auto new_cursor_position = ui->text_edit_osk->textCursor().position(); | ||
| 783 | |||
| 784 | ui->button_backspace->setEnabled(initialize_parameters.enable_backspace_button && | ||
| 785 | new_cursor_position > 0); | ||
| 786 | ui->button_backspace_shift->setEnabled(initialize_parameters.enable_backspace_button && | ||
| 787 | new_cursor_position > 0); | ||
| 788 | ui->button_backspace_num->setEnabled(initialize_parameters.enable_backspace_button && | ||
| 789 | new_cursor_position > 0); | ||
| 790 | |||
| 791 | ui->text_edit_osk->setFocus(); | ||
| 792 | }); | ||
| 793 | |||
| 794 | ui->text_edit_osk->setPlaceholderText( | ||
| 795 | QString::fromStdU16String(initialize_parameters.guide_text)); | ||
| 796 | ui->text_edit_osk->setText(QString::fromStdU16String(initialize_parameters.initial_text)); | ||
| 797 | ui->text_edit_osk->moveCursor(initialize_parameters.initial_cursor_position == 0 | ||
| 798 | ? QTextCursor::Start | ||
| 799 | : QTextCursor::End); | ||
| 800 | |||
| 801 | ui->label_characters_box->setText(QStringLiteral("%1/%2") | ||
| 802 | .arg(initialize_parameters.initial_text.size()) | ||
| 803 | .arg(initialize_parameters.max_text_length)); | ||
| 804 | break; | ||
| 805 | } | ||
| 806 | } | ||
| 807 | } | ||
| 808 | |||
| 809 | void QtSoftwareKeyboardDialog::SetControllerImage() { | ||
| 810 | const auto controller_type = Settings::values.players.GetValue()[8].connected | ||
| 811 | ? Settings::values.players.GetValue()[8].controller_type | ||
| 812 | : Settings::values.players.GetValue()[0].controller_type; | ||
| 813 | |||
| 814 | const QString theme = [] { | ||
| 815 | if (QIcon::themeName().contains(QStringLiteral("dark")) || | ||
| 816 | QIcon::themeName().contains(QStringLiteral("midnight"))) { | ||
| 817 | return QStringLiteral("_dark"); | ||
| 818 | } else { | ||
| 819 | return QString{}; | ||
| 820 | } | ||
| 821 | }(); | ||
| 822 | |||
| 823 | switch (controller_type) { | ||
| 824 | case Settings::ControllerType::ProController: | ||
| 825 | case Settings::ControllerType::GameCube: | ||
| 826 | ui->icon_controller->setStyleSheet( | ||
| 827 | QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); | ||
| 828 | ui->icon_controller_shift->setStyleSheet( | ||
| 829 | QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); | ||
| 830 | ui->icon_controller_num->setStyleSheet( | ||
| 831 | QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); | ||
| 832 | break; | ||
| 833 | case Settings::ControllerType::DualJoyconDetached: | ||
| 834 | ui->icon_controller->setStyleSheet( | ||
| 835 | QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); | ||
| 836 | ui->icon_controller_shift->setStyleSheet( | ||
| 837 | QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); | ||
| 838 | ui->icon_controller_num->setStyleSheet( | ||
| 839 | QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); | ||
| 840 | break; | ||
| 841 | case Settings::ControllerType::LeftJoycon: | ||
| 842 | ui->icon_controller->setStyleSheet( | ||
| 843 | QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") | ||
| 844 | .arg(theme)); | ||
| 845 | ui->icon_controller_shift->setStyleSheet( | ||
| 846 | QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") | ||
| 847 | .arg(theme)); | ||
| 848 | ui->icon_controller_num->setStyleSheet( | ||
| 849 | QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") | ||
| 850 | .arg(theme)); | ||
| 851 | break; | ||
| 852 | case Settings::ControllerType::RightJoycon: | ||
| 853 | ui->icon_controller->setStyleSheet( | ||
| 854 | QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") | ||
| 855 | .arg(theme)); | ||
| 856 | ui->icon_controller_shift->setStyleSheet( | ||
| 857 | QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") | ||
| 858 | .arg(theme)); | ||
| 859 | ui->icon_controller_num->setStyleSheet( | ||
| 860 | QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") | ||
| 861 | .arg(theme)); | ||
| 862 | break; | ||
| 863 | case Settings::ControllerType::Handheld: | ||
| 864 | ui->icon_controller->setStyleSheet( | ||
| 865 | QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme)); | ||
| 866 | ui->icon_controller_shift->setStyleSheet( | ||
| 867 | QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme)); | ||
| 868 | ui->icon_controller_num->setStyleSheet( | ||
| 869 | QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme)); | ||
| 870 | break; | ||
| 871 | default: | ||
| 872 | break; | ||
| 873 | } | ||
| 874 | } | ||
| 875 | |||
| 876 | void QtSoftwareKeyboardDialog::DisableKeyboardButtons() { | ||
| 877 | switch (bottom_osk_index) { | ||
| 878 | case BottomOSKIndex::LowerCase: | ||
| 879 | case BottomOSKIndex::UpperCase: | ||
| 880 | default: { | ||
| 881 | for (const auto& keys : keyboard_buttons) { | ||
| 882 | for (const auto& rows : keys) { | ||
| 883 | for (auto* button : rows) { | ||
| 884 | if (!button) { | ||
| 885 | continue; | ||
| 886 | } | ||
| 887 | |||
| 888 | button->setEnabled(true); | ||
| 889 | } | ||
| 890 | } | ||
| 891 | } | ||
| 892 | |||
| 893 | const auto& key_disable_flags = initialize_parameters.key_disable_flags; | ||
| 894 | |||
| 895 | ui->button_space->setDisabled(key_disable_flags.space); | ||
| 896 | ui->button_space_shift->setDisabled(key_disable_flags.space); | ||
| 897 | |||
| 898 | ui->button_at->setDisabled(key_disable_flags.at || key_disable_flags.username); | ||
| 899 | |||
| 900 | ui->button_percent->setDisabled(key_disable_flags.percent || key_disable_flags.username); | ||
| 901 | |||
| 902 | ui->button_slash->setDisabled(key_disable_flags.slash); | ||
| 903 | |||
| 904 | ui->button_1->setDisabled(key_disable_flags.numbers); | ||
| 905 | ui->button_2->setDisabled(key_disable_flags.numbers); | ||
| 906 | ui->button_3->setDisabled(key_disable_flags.numbers); | ||
| 907 | ui->button_4->setDisabled(key_disable_flags.numbers); | ||
| 908 | ui->button_5->setDisabled(key_disable_flags.numbers); | ||
| 909 | ui->button_6->setDisabled(key_disable_flags.numbers); | ||
| 910 | ui->button_7->setDisabled(key_disable_flags.numbers); | ||
| 911 | ui->button_8->setDisabled(key_disable_flags.numbers); | ||
| 912 | ui->button_9->setDisabled(key_disable_flags.numbers); | ||
| 913 | ui->button_0->setDisabled(key_disable_flags.numbers); | ||
| 914 | |||
| 915 | ui->button_return->setEnabled(initialize_parameters.enable_return_button); | ||
| 916 | ui->button_return_shift->setEnabled(initialize_parameters.enable_return_button); | ||
| 917 | break; | ||
| 918 | } | ||
| 919 | case BottomOSKIndex::NumberPad: { | ||
| 920 | for (const auto& rows : numberpad_buttons) { | ||
| 921 | for (auto* button : rows) { | ||
| 922 | if (!button) { | ||
| 923 | continue; | ||
| 924 | } | ||
| 925 | |||
| 926 | button->setEnabled(true); | ||
| 927 | } | ||
| 928 | } | ||
| 929 | break; | ||
| 930 | } | ||
| 931 | } | ||
| 932 | } | ||
| 933 | |||
| 934 | void QtSoftwareKeyboardDialog::SetBackspaceOkEnabled() { | ||
| 935 | if (is_inline) { | ||
| 936 | ui->button_ok->setEnabled(current_text.size() >= initialize_parameters.min_text_length); | ||
| 937 | ui->button_ok_shift->setEnabled(current_text.size() >= | ||
| 938 | initialize_parameters.min_text_length); | ||
| 939 | ui->button_ok_num->setEnabled(current_text.size() >= initialize_parameters.min_text_length); | ||
| 940 | |||
| 941 | ui->button_backspace->setEnabled(initialize_parameters.enable_backspace_button && | ||
| 942 | cursor_position > 0); | ||
| 943 | ui->button_backspace_shift->setEnabled(initialize_parameters.enable_backspace_button && | ||
| 944 | cursor_position > 0); | ||
| 945 | ui->button_backspace_num->setEnabled(initialize_parameters.enable_backspace_button && | ||
| 946 | cursor_position > 0); | ||
| 88 | } else { | 947 | } else { |
| 89 | buttons->addButton(QString::fromStdU16String(parameters.submit_text), | 948 | const auto text_length = [this] { |
| 90 | QDialogButtonBox::AcceptRole); | 949 | if (ui->topOSK->currentIndex() == 1) { |
| 950 | return static_cast<u32>(ui->text_edit_osk->toPlainText().length()); | ||
| 951 | } else { | ||
| 952 | return static_cast<u32>(ui->line_edit_osk->text().length()); | ||
| 953 | } | ||
| 954 | }(); | ||
| 955 | |||
| 956 | const auto normal_cursor_position = [this] { | ||
| 957 | if (ui->topOSK->currentIndex() == 1) { | ||
| 958 | return ui->text_edit_osk->textCursor().position(); | ||
| 959 | } else { | ||
| 960 | return ui->line_edit_osk->cursorPosition(); | ||
| 961 | } | ||
| 962 | }(); | ||
| 963 | |||
| 964 | ui->button_ok->setEnabled(text_length >= initialize_parameters.min_text_length); | ||
| 965 | ui->button_ok_shift->setEnabled(text_length >= initialize_parameters.min_text_length); | ||
| 966 | ui->button_ok_num->setEnabled(text_length >= initialize_parameters.min_text_length); | ||
| 967 | |||
| 968 | ui->button_backspace->setEnabled(initialize_parameters.enable_backspace_button && | ||
| 969 | normal_cursor_position > 0); | ||
| 970 | ui->button_backspace_shift->setEnabled(initialize_parameters.enable_backspace_button && | ||
| 971 | normal_cursor_position > 0); | ||
| 972 | ui->button_backspace_num->setEnabled(initialize_parameters.enable_backspace_button && | ||
| 973 | normal_cursor_position > 0); | ||
| 91 | } | 974 | } |
| 92 | connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::accept); | ||
| 93 | connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::reject); | ||
| 94 | layout->addWidget(header_label); | ||
| 95 | layout->addWidget(sub_label); | ||
| 96 | layout->addWidget(guide_label); | ||
| 97 | layout->addWidget(length_label); | ||
| 98 | layout->addWidget(line_edit); | ||
| 99 | layout->addWidget(buttons); | ||
| 100 | setLayout(layout); | ||
| 101 | setWindowTitle(tr("Software Keyboard")); | ||
| 102 | } | 975 | } |
| 103 | 976 | ||
| 104 | QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default; | 977 | bool QtSoftwareKeyboardDialog::ValidateInputText(const QString& input_text) { |
| 978 | const auto& key_disable_flags = initialize_parameters.key_disable_flags; | ||
| 979 | |||
| 980 | const auto input_text_length = static_cast<u32>(input_text.length()); | ||
| 981 | |||
| 982 | if (input_text_length < initialize_parameters.min_text_length || | ||
| 983 | input_text_length > initialize_parameters.max_text_length) { | ||
| 984 | return false; | ||
| 985 | } | ||
| 986 | |||
| 987 | if (key_disable_flags.space && input_text.contains(QLatin1Char{' '})) { | ||
| 988 | return false; | ||
| 989 | } | ||
| 990 | |||
| 991 | if ((key_disable_flags.at || key_disable_flags.username) && | ||
| 992 | input_text.contains(QLatin1Char{'@'})) { | ||
| 993 | return false; | ||
| 994 | } | ||
| 995 | |||
| 996 | if ((key_disable_flags.percent || key_disable_flags.username) && | ||
| 997 | input_text.contains(QLatin1Char{'%'})) { | ||
| 998 | return false; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | if (key_disable_flags.slash && input_text.contains(QLatin1Char{'/'})) { | ||
| 1002 | return false; | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | if ((key_disable_flags.backslash || key_disable_flags.username) && | ||
| 1006 | input_text.contains(QLatin1Char('\\'))) { | ||
| 1007 | return false; | ||
| 1008 | } | ||
| 105 | 1009 | ||
| 106 | void QtSoftwareKeyboardDialog::accept() { | 1010 | if (key_disable_flags.numbers && |
| 107 | text = line_edit->text().toStdU16String(); | 1011 | std::any_of(input_text.begin(), input_text.end(), [](QChar c) { return c.isDigit(); })) { |
| 108 | QDialog::accept(); | 1012 | return false; |
| 1013 | } | ||
| 1014 | |||
| 1015 | if (bottom_osk_index == BottomOSKIndex::NumberPad && | ||
| 1016 | std::any_of(input_text.begin(), input_text.end(), [](QChar c) { return !c.isDigit(); })) { | ||
| 1017 | return false; | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | return true; | ||
| 109 | } | 1021 | } |
| 110 | 1022 | ||
| 111 | void QtSoftwareKeyboardDialog::reject() { | 1023 | void QtSoftwareKeyboardDialog::ChangeBottomOSKIndex() { |
| 112 | text.clear(); | 1024 | switch (bottom_osk_index) { |
| 113 | QDialog::reject(); | 1025 | case BottomOSKIndex::LowerCase: |
| 1026 | bottom_osk_index = BottomOSKIndex::UpperCase; | ||
| 1027 | ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index)); | ||
| 1028 | |||
| 1029 | ui->button_shift_shift->setStyleSheet( | ||
| 1030 | QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_off.png);" | ||
| 1031 | "\nbackground-position: left top;" | ||
| 1032 | "\nbackground-repeat: no-repeat;" | ||
| 1033 | "\nbackground-origin: content;")); | ||
| 1034 | |||
| 1035 | ui->button_shift_shift->setIconSize(ui->button_shift->iconSize()); | ||
| 1036 | ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize()); | ||
| 1037 | break; | ||
| 1038 | case BottomOSKIndex::UpperCase: | ||
| 1039 | if (caps_lock_enabled) { | ||
| 1040 | caps_lock_enabled = false; | ||
| 1041 | |||
| 1042 | ui->button_shift_shift->setStyleSheet( | ||
| 1043 | QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_off.png);" | ||
| 1044 | "\nbackground-position: left top;" | ||
| 1045 | "\nbackground-repeat: no-repeat;" | ||
| 1046 | "\nbackground-origin: content;")); | ||
| 1047 | |||
| 1048 | ui->button_shift_shift->setIconSize(ui->button_shift->iconSize()); | ||
| 1049 | ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize()); | ||
| 1050 | |||
| 1051 | ui->label_shift_shift->setText(QStringLiteral("Caps Lock")); | ||
| 1052 | |||
| 1053 | bottom_osk_index = BottomOSKIndex::LowerCase; | ||
| 1054 | ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index)); | ||
| 1055 | } else { | ||
| 1056 | caps_lock_enabled = true; | ||
| 1057 | |||
| 1058 | ui->button_shift_shift->setStyleSheet( | ||
| 1059 | QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_on.png);" | ||
| 1060 | "\nbackground-position: left top;" | ||
| 1061 | "\nbackground-repeat: no-repeat;" | ||
| 1062 | "\nbackground-origin: content;")); | ||
| 1063 | |||
| 1064 | ui->button_shift_shift->setIconSize(ui->button_shift->iconSize()); | ||
| 1065 | ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize()); | ||
| 1066 | |||
| 1067 | ui->label_shift_shift->setText(QStringLiteral("Caps Lock Off")); | ||
| 1068 | } | ||
| 1069 | break; | ||
| 1070 | case BottomOSKIndex::NumberPad: | ||
| 1071 | default: | ||
| 1072 | break; | ||
| 1073 | } | ||
| 114 | } | 1074 | } |
| 115 | 1075 | ||
| 116 | std::u16string QtSoftwareKeyboardDialog::GetText() const { | 1076 | void QtSoftwareKeyboardDialog::NormalKeyboardButtonClicked(QPushButton* button) { |
| 117 | return text; | 1077 | if (button == ui->button_ampersand) { |
| 1078 | if (ui->topOSK->currentIndex() == 1) { | ||
| 1079 | ui->text_edit_osk->insertPlainText(QStringLiteral("&")); | ||
| 1080 | } else { | ||
| 1081 | ui->line_edit_osk->insert(QStringLiteral("&")); | ||
| 1082 | } | ||
| 1083 | return; | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | if (button == ui->button_return || button == ui->button_return_shift) { | ||
| 1087 | if (ui->topOSK->currentIndex() == 1) { | ||
| 1088 | ui->text_edit_osk->insertPlainText(QStringLiteral("\n")); | ||
| 1089 | } else { | ||
| 1090 | ui->line_edit_osk->insert(QStringLiteral("\n")); | ||
| 1091 | } | ||
| 1092 | return; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | if (button == ui->button_space || button == ui->button_space_shift) { | ||
| 1096 | if (ui->topOSK->currentIndex() == 1) { | ||
| 1097 | ui->text_edit_osk->insertPlainText(QStringLiteral(" ")); | ||
| 1098 | } else { | ||
| 1099 | ui->line_edit_osk->insert(QStringLiteral(" ")); | ||
| 1100 | } | ||
| 1101 | return; | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | if (button == ui->button_shift || button == ui->button_shift_shift) { | ||
| 1105 | ChangeBottomOSKIndex(); | ||
| 1106 | return; | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | if (button == ui->button_backspace || button == ui->button_backspace_shift || | ||
| 1110 | button == ui->button_backspace_num) { | ||
| 1111 | if (ui->topOSK->currentIndex() == 1) { | ||
| 1112 | auto text_cursor = ui->text_edit_osk->textCursor(); | ||
| 1113 | ui->text_edit_osk->setTextCursor(text_cursor); | ||
| 1114 | text_cursor.deletePreviousChar(); | ||
| 1115 | } else { | ||
| 1116 | ui->line_edit_osk->backspace(); | ||
| 1117 | } | ||
| 1118 | return; | ||
| 1119 | } | ||
| 1120 | |||
| 1121 | if (button == ui->button_ok || button == ui->button_ok_shift || button == ui->button_ok_num) { | ||
| 1122 | if (ui->topOSK->currentIndex() == 1) { | ||
| 1123 | emit SubmitNormalText(SwkbdResult::Ok, | ||
| 1124 | ui->text_edit_osk->toPlainText().toStdU16String()); | ||
| 1125 | } else { | ||
| 1126 | emit SubmitNormalText(SwkbdResult::Ok, ui->line_edit_osk->text().toStdU16String()); | ||
| 1127 | } | ||
| 1128 | return; | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | if (ui->topOSK->currentIndex() == 1) { | ||
| 1132 | ui->text_edit_osk->insertPlainText(button->text()); | ||
| 1133 | } else { | ||
| 1134 | ui->line_edit_osk->insert(button->text()); | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | // Revert the keyboard to lowercase if the shift key is active. | ||
| 1138 | if (bottom_osk_index == BottomOSKIndex::UpperCase && !caps_lock_enabled) { | ||
| 1139 | // This is set to true since ChangeBottomOSKIndex will change bottom_osk_index to LowerCase | ||
| 1140 | // if bottom_osk_index is UpperCase and caps_lock_enabled is true. | ||
| 1141 | caps_lock_enabled = true; | ||
| 1142 | ChangeBottomOSKIndex(); | ||
| 1143 | } | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | void QtSoftwareKeyboardDialog::InlineKeyboardButtonClicked(QPushButton* button) { | ||
| 1147 | if (!button->isEnabled()) { | ||
| 1148 | return; | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | if (button == ui->button_ampersand) { | ||
| 1152 | InlineTextInsertString(u"&"); | ||
| 1153 | return; | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | if (button == ui->button_return || button == ui->button_return_shift) { | ||
| 1157 | InlineTextInsertString(u"\n"); | ||
| 1158 | return; | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | if (button == ui->button_space || button == ui->button_space_shift) { | ||
| 1162 | InlineTextInsertString(u" "); | ||
| 1163 | return; | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | if (button == ui->button_shift || button == ui->button_shift_shift) { | ||
| 1167 | ChangeBottomOSKIndex(); | ||
| 1168 | return; | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | if (button == ui->button_backspace || button == ui->button_backspace_shift || | ||
| 1172 | button == ui->button_backspace_num) { | ||
| 1173 | if (cursor_position <= 0 || current_text.empty()) { | ||
| 1174 | cursor_position = 0; | ||
| 1175 | return; | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | --cursor_position; | ||
| 1179 | |||
| 1180 | current_text.erase(cursor_position, 1); | ||
| 1181 | |||
| 1182 | SetBackspaceOkEnabled(); | ||
| 1183 | |||
| 1184 | emit SubmitInlineText(SwkbdReplyType::ChangedString, current_text, cursor_position); | ||
| 1185 | return; | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | if (button == ui->button_ok || button == ui->button_ok_shift || button == ui->button_ok_num) { | ||
| 1189 | emit SubmitInlineText(SwkbdReplyType::DecidedEnter, current_text, cursor_position); | ||
| 1190 | return; | ||
| 1191 | } | ||
| 1192 | |||
| 1193 | InlineTextInsertString(button->text().toStdU16String()); | ||
| 1194 | |||
| 1195 | // Revert the keyboard to lowercase if the shift key is active. | ||
| 1196 | if (bottom_osk_index == BottomOSKIndex::UpperCase && !caps_lock_enabled) { | ||
| 1197 | // This is set to true since ChangeBottomOSKIndex will change bottom_osk_index to LowerCase | ||
| 1198 | // if bottom_osk_index is UpperCase and caps_lock_enabled is true. | ||
| 1199 | caps_lock_enabled = true; | ||
| 1200 | ChangeBottomOSKIndex(); | ||
| 1201 | } | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | void QtSoftwareKeyboardDialog::InlineTextInsertString(std::u16string_view string) { | ||
| 1205 | if ((current_text.size() + string.size()) > initialize_parameters.max_text_length) { | ||
| 1206 | return; | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | current_text.insert(cursor_position, string); | ||
| 1210 | |||
| 1211 | cursor_position += static_cast<s32>(string.size()); | ||
| 1212 | |||
| 1213 | SetBackspaceOkEnabled(); | ||
| 1214 | |||
| 1215 | emit SubmitInlineText(SwkbdReplyType::ChangedString, current_text, cursor_position); | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | void QtSoftwareKeyboardDialog::SetupMouseHover() { | ||
| 1219 | // setFocus() has a bug where continuously changing focus will cause the focus UI to | ||
| 1220 | // mysteriously disappear. A workaround we have found is using the mouse to hover over | ||
| 1221 | // the buttons to act in place of the button focus. As a result, we will have to set | ||
| 1222 | // a blank cursor when hovering over all the buttons and set a no focus policy so the | ||
| 1223 | // buttons do not stay in focus in addition to the mouse hover. | ||
| 1224 | for (auto* button : all_buttons) { | ||
| 1225 | button->setCursor(QCursor(Qt::BlankCursor)); | ||
| 1226 | button->setFocusPolicy(Qt::NoFocus); | ||
| 1227 | } | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | template <HIDButton... T> | ||
| 1231 | void QtSoftwareKeyboardDialog::HandleButtonPressedOnce() { | ||
| 1232 | const auto f = [this](HIDButton button) { | ||
| 1233 | if (input_interpreter->IsButtonPressedOnce(button)) { | ||
| 1234 | TranslateButtonPress(button); | ||
| 1235 | } | ||
| 1236 | }; | ||
| 1237 | |||
| 1238 | (f(T), ...); | ||
| 1239 | } | ||
| 1240 | |||
| 1241 | template <HIDButton... T> | ||
| 1242 | void QtSoftwareKeyboardDialog::HandleButtonHold() { | ||
| 1243 | const auto f = [this](HIDButton button) { | ||
| 1244 | if (input_interpreter->IsButtonHeld(button)) { | ||
| 1245 | TranslateButtonPress(button); | ||
| 1246 | } | ||
| 1247 | }; | ||
| 1248 | |||
| 1249 | (f(T), ...); | ||
| 1250 | } | ||
| 1251 | |||
| 1252 | void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) { | ||
| 1253 | switch (button) { | ||
| 1254 | case HIDButton::A: | ||
| 1255 | switch (bottom_osk_index) { | ||
| 1256 | case BottomOSKIndex::LowerCase: | ||
| 1257 | case BottomOSKIndex::UpperCase: | ||
| 1258 | keyboard_buttons[static_cast<std::size_t>(bottom_osk_index)][row][column]->click(); | ||
| 1259 | break; | ||
| 1260 | case BottomOSKIndex::NumberPad: | ||
| 1261 | numberpad_buttons[row][column]->click(); | ||
| 1262 | break; | ||
| 1263 | default: | ||
| 1264 | break; | ||
| 1265 | } | ||
| 1266 | break; | ||
| 1267 | case HIDButton::B: | ||
| 1268 | switch (bottom_osk_index) { | ||
| 1269 | case BottomOSKIndex::LowerCase: | ||
| 1270 | ui->button_backspace->click(); | ||
| 1271 | break; | ||
| 1272 | case BottomOSKIndex::UpperCase: | ||
| 1273 | ui->button_backspace_shift->click(); | ||
| 1274 | break; | ||
| 1275 | case BottomOSKIndex::NumberPad: | ||
| 1276 | ui->button_backspace_num->click(); | ||
| 1277 | break; | ||
| 1278 | default: | ||
| 1279 | break; | ||
| 1280 | } | ||
| 1281 | break; | ||
| 1282 | case HIDButton::X: | ||
| 1283 | if (is_inline) { | ||
| 1284 | emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position); | ||
| 1285 | } else { | ||
| 1286 | if (ui->topOSK->currentIndex() == 1) { | ||
| 1287 | emit SubmitNormalText(SwkbdResult::Cancel, | ||
| 1288 | ui->text_edit_osk->toPlainText().toStdU16String()); | ||
| 1289 | } else { | ||
| 1290 | emit SubmitNormalText(SwkbdResult::Cancel, | ||
| 1291 | ui->line_edit_osk->text().toStdU16String()); | ||
| 1292 | } | ||
| 1293 | } | ||
| 1294 | break; | ||
| 1295 | case HIDButton::Y: | ||
| 1296 | switch (bottom_osk_index) { | ||
| 1297 | case BottomOSKIndex::LowerCase: | ||
| 1298 | ui->button_space->click(); | ||
| 1299 | break; | ||
| 1300 | case BottomOSKIndex::UpperCase: | ||
| 1301 | ui->button_space_shift->click(); | ||
| 1302 | break; | ||
| 1303 | case BottomOSKIndex::NumberPad: | ||
| 1304 | default: | ||
| 1305 | break; | ||
| 1306 | } | ||
| 1307 | break; | ||
| 1308 | case HIDButton::LStick: | ||
| 1309 | case HIDButton::RStick: | ||
| 1310 | switch (bottom_osk_index) { | ||
| 1311 | case BottomOSKIndex::LowerCase: | ||
| 1312 | ui->button_shift->click(); | ||
| 1313 | break; | ||
| 1314 | case BottomOSKIndex::UpperCase: | ||
| 1315 | ui->button_shift_shift->click(); | ||
| 1316 | break; | ||
| 1317 | case BottomOSKIndex::NumberPad: | ||
| 1318 | default: | ||
| 1319 | break; | ||
| 1320 | } | ||
| 1321 | break; | ||
| 1322 | case HIDButton::L: | ||
| 1323 | MoveTextCursorDirection(Direction::Left); | ||
| 1324 | break; | ||
| 1325 | case HIDButton::R: | ||
| 1326 | MoveTextCursorDirection(Direction::Right); | ||
| 1327 | break; | ||
| 1328 | case HIDButton::Plus: | ||
| 1329 | switch (bottom_osk_index) { | ||
| 1330 | case BottomOSKIndex::LowerCase: | ||
| 1331 | ui->button_ok->click(); | ||
| 1332 | break; | ||
| 1333 | case BottomOSKIndex::UpperCase: | ||
| 1334 | ui->button_ok_shift->click(); | ||
| 1335 | break; | ||
| 1336 | case BottomOSKIndex::NumberPad: | ||
| 1337 | ui->button_ok_num->click(); | ||
| 1338 | break; | ||
| 1339 | default: | ||
| 1340 | break; | ||
| 1341 | } | ||
| 1342 | break; | ||
| 1343 | case HIDButton::DLeft: | ||
| 1344 | case HIDButton::LStickLeft: | ||
| 1345 | case HIDButton::RStickLeft: | ||
| 1346 | MoveButtonDirection(Direction::Left); | ||
| 1347 | break; | ||
| 1348 | case HIDButton::DUp: | ||
| 1349 | case HIDButton::LStickUp: | ||
| 1350 | case HIDButton::RStickUp: | ||
| 1351 | MoveButtonDirection(Direction::Up); | ||
| 1352 | break; | ||
| 1353 | case HIDButton::DRight: | ||
| 1354 | case HIDButton::LStickRight: | ||
| 1355 | case HIDButton::RStickRight: | ||
| 1356 | MoveButtonDirection(Direction::Right); | ||
| 1357 | break; | ||
| 1358 | case HIDButton::DDown: | ||
| 1359 | case HIDButton::LStickDown: | ||
| 1360 | case HIDButton::RStickDown: | ||
| 1361 | MoveButtonDirection(Direction::Down); | ||
| 1362 | break; | ||
| 1363 | default: | ||
| 1364 | break; | ||
| 1365 | } | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | void QtSoftwareKeyboardDialog::MoveButtonDirection(Direction direction) { | ||
| 1369 | // Changes the row or column index depending on the direction. | ||
| 1370 | auto move_direction = [this, direction](std::size_t max_rows, std::size_t max_columns) { | ||
| 1371 | switch (direction) { | ||
| 1372 | case Direction::Left: | ||
| 1373 | column = (column + max_columns - 1) % max_columns; | ||
| 1374 | break; | ||
| 1375 | case Direction::Up: | ||
| 1376 | row = (row + max_rows - 1) % max_rows; | ||
| 1377 | break; | ||
| 1378 | case Direction::Right: | ||
| 1379 | column = (column + 1) % max_columns; | ||
| 1380 | break; | ||
| 1381 | case Direction::Down: | ||
| 1382 | row = (row + 1) % max_rows; | ||
| 1383 | break; | ||
| 1384 | default: | ||
| 1385 | break; | ||
| 1386 | } | ||
| 1387 | }; | ||
| 1388 | |||
| 1389 | switch (bottom_osk_index) { | ||
| 1390 | case BottomOSKIndex::LowerCase: | ||
| 1391 | case BottomOSKIndex::UpperCase: { | ||
| 1392 | const auto index = static_cast<std::size_t>(bottom_osk_index); | ||
| 1393 | |||
| 1394 | const auto* const prev_button = keyboard_buttons[index][row][column]; | ||
| 1395 | move_direction(NUM_ROWS_NORMAL, NUM_COLUMNS_NORMAL); | ||
| 1396 | auto* curr_button = keyboard_buttons[index][row][column]; | ||
| 1397 | |||
| 1398 | while (!curr_button || !curr_button->isEnabled() || curr_button == prev_button) { | ||
| 1399 | move_direction(NUM_ROWS_NORMAL, NUM_COLUMNS_NORMAL); | ||
| 1400 | curr_button = keyboard_buttons[index][row][column]; | ||
| 1401 | } | ||
| 1402 | |||
| 1403 | // This is a workaround for setFocus() randomly not showing focus in the UI | ||
| 1404 | QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center())); | ||
| 1405 | break; | ||
| 1406 | } | ||
| 1407 | case BottomOSKIndex::NumberPad: { | ||
| 1408 | const auto* const prev_button = numberpad_buttons[row][column]; | ||
| 1409 | move_direction(NUM_ROWS_NUMPAD, NUM_COLUMNS_NUMPAD); | ||
| 1410 | auto* curr_button = numberpad_buttons[row][column]; | ||
| 1411 | |||
| 1412 | while (!curr_button || !curr_button->isEnabled() || curr_button == prev_button) { | ||
| 1413 | move_direction(NUM_ROWS_NUMPAD, NUM_COLUMNS_NUMPAD); | ||
| 1414 | curr_button = numberpad_buttons[row][column]; | ||
| 1415 | } | ||
| 1416 | |||
| 1417 | // This is a workaround for setFocus() randomly not showing focus in the UI | ||
| 1418 | QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center())); | ||
| 1419 | break; | ||
| 1420 | } | ||
| 1421 | default: | ||
| 1422 | break; | ||
| 1423 | } | ||
| 1424 | } | ||
| 1425 | |||
| 1426 | void QtSoftwareKeyboardDialog::MoveTextCursorDirection(Direction direction) { | ||
| 1427 | switch (direction) { | ||
| 1428 | case Direction::Left: | ||
| 1429 | if (is_inline) { | ||
| 1430 | if (cursor_position <= 0) { | ||
| 1431 | cursor_position = 0; | ||
| 1432 | } else { | ||
| 1433 | --cursor_position; | ||
| 1434 | emit SubmitInlineText(SwkbdReplyType::MovedCursor, current_text, cursor_position); | ||
| 1435 | } | ||
| 1436 | } else { | ||
| 1437 | if (ui->topOSK->currentIndex() == 1) { | ||
| 1438 | ui->text_edit_osk->moveCursor(QTextCursor::Left); | ||
| 1439 | } else { | ||
| 1440 | ui->line_edit_osk->setCursorPosition(ui->line_edit_osk->cursorPosition() - 1); | ||
| 1441 | } | ||
| 1442 | } | ||
| 1443 | break; | ||
| 1444 | case Direction::Right: | ||
| 1445 | if (is_inline) { | ||
| 1446 | if (cursor_position >= static_cast<s32>(current_text.size())) { | ||
| 1447 | cursor_position = static_cast<s32>(current_text.size()); | ||
| 1448 | } else { | ||
| 1449 | ++cursor_position; | ||
| 1450 | emit SubmitInlineText(SwkbdReplyType::MovedCursor, current_text, cursor_position); | ||
| 1451 | } | ||
| 1452 | } else { | ||
| 1453 | if (ui->topOSK->currentIndex() == 1) { | ||
| 1454 | ui->text_edit_osk->moveCursor(QTextCursor::Right); | ||
| 1455 | } else { | ||
| 1456 | ui->line_edit_osk->setCursorPosition(ui->line_edit_osk->cursorPosition() + 1); | ||
| 1457 | } | ||
| 1458 | } | ||
| 1459 | break; | ||
| 1460 | default: | ||
| 1461 | break; | ||
| 1462 | } | ||
| 1463 | } | ||
| 1464 | |||
| 1465 | void QtSoftwareKeyboardDialog::StartInputThread() { | ||
| 1466 | if (input_thread_running) { | ||
| 1467 | return; | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | input_thread_running = true; | ||
| 1471 | |||
| 1472 | input_thread = std::thread(&QtSoftwareKeyboardDialog::InputThread, this); | ||
| 1473 | } | ||
| 1474 | |||
| 1475 | void QtSoftwareKeyboardDialog::StopInputThread() { | ||
| 1476 | input_thread_running = false; | ||
| 1477 | |||
| 1478 | if (input_thread.joinable()) { | ||
| 1479 | input_thread.join(); | ||
| 1480 | } | ||
| 1481 | |||
| 1482 | if (input_interpreter) { | ||
| 1483 | input_interpreter->ResetButtonStates(); | ||
| 1484 | } | ||
| 1485 | } | ||
| 1486 | |||
| 1487 | void QtSoftwareKeyboardDialog::InputThread() { | ||
| 1488 | while (input_thread_running) { | ||
| 1489 | input_interpreter->PollInput(); | ||
| 1490 | |||
| 1491 | HandleButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::X, HIDButton::Y, | ||
| 1492 | HIDButton::LStick, HIDButton::RStick, HIDButton::L, HIDButton::R, | ||
| 1493 | HIDButton::Plus, HIDButton::DLeft, HIDButton::DUp, | ||
| 1494 | HIDButton::DRight, HIDButton::DDown, HIDButton::LStickLeft, | ||
| 1495 | HIDButton::LStickUp, HIDButton::LStickRight, HIDButton::LStickDown, | ||
| 1496 | HIDButton::RStickLeft, HIDButton::RStickUp, HIDButton::RStickRight, | ||
| 1497 | HIDButton::RStickDown>(); | ||
| 1498 | |||
| 1499 | HandleButtonHold<HIDButton::B, HIDButton::L, HIDButton::R, HIDButton::DLeft, HIDButton::DUp, | ||
| 1500 | HIDButton::DRight, HIDButton::DDown, HIDButton::LStickLeft, | ||
| 1501 | HIDButton::LStickUp, HIDButton::LStickRight, HIDButton::LStickDown, | ||
| 1502 | HIDButton::RStickLeft, HIDButton::RStickUp, HIDButton::RStickRight, | ||
| 1503 | HIDButton::RStickDown>(); | ||
| 1504 | |||
| 1505 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); | ||
| 1506 | } | ||
| 118 | } | 1507 | } |
| 119 | 1508 | ||
| 120 | QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& main_window) { | 1509 | QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& main_window) { |
| 121 | connect(this, &QtSoftwareKeyboard::MainWindowGetText, &main_window, | 1510 | connect(this, &QtSoftwareKeyboard::MainWindowInitializeKeyboard, &main_window, |
| 122 | &GMainWindow::SoftwareKeyboardGetText, Qt::QueuedConnection); | 1511 | &GMainWindow::SoftwareKeyboardInitialize, Qt::QueuedConnection); |
| 123 | connect(this, &QtSoftwareKeyboard::MainWindowTextCheckDialog, &main_window, | 1512 | connect(this, &QtSoftwareKeyboard::MainWindowShowNormalKeyboard, &main_window, |
| 124 | &GMainWindow::SoftwareKeyboardInvokeCheckDialog, Qt::BlockingQueuedConnection); | 1513 | &GMainWindow::SoftwareKeyboardShowNormal, Qt::QueuedConnection); |
| 125 | connect(&main_window, &GMainWindow::SoftwareKeyboardFinishedText, this, | 1514 | connect(this, &QtSoftwareKeyboard::MainWindowShowTextCheckDialog, &main_window, |
| 126 | &QtSoftwareKeyboard::MainWindowFinishedText, Qt::QueuedConnection); | 1515 | &GMainWindow::SoftwareKeyboardShowTextCheck, Qt::QueuedConnection); |
| 1516 | connect(this, &QtSoftwareKeyboard::MainWindowShowInlineKeyboard, &main_window, | ||
| 1517 | &GMainWindow::SoftwareKeyboardShowInline, Qt::QueuedConnection); | ||
| 1518 | connect(this, &QtSoftwareKeyboard::MainWindowHideInlineKeyboard, &main_window, | ||
| 1519 | &GMainWindow::SoftwareKeyboardHideInline, Qt::QueuedConnection); | ||
| 1520 | connect(this, &QtSoftwareKeyboard::MainWindowInlineTextChanged, &main_window, | ||
| 1521 | &GMainWindow::SoftwareKeyboardInlineTextChanged, Qt::QueuedConnection); | ||
| 1522 | connect(this, &QtSoftwareKeyboard::MainWindowExitKeyboard, &main_window, | ||
| 1523 | &GMainWindow::SoftwareKeyboardExit, Qt::QueuedConnection); | ||
| 1524 | connect(&main_window, &GMainWindow::SoftwareKeyboardSubmitNormalText, this, | ||
| 1525 | &QtSoftwareKeyboard::SubmitNormalText, Qt::QueuedConnection); | ||
| 1526 | connect(&main_window, &GMainWindow::SoftwareKeyboardSubmitInlineText, this, | ||
| 1527 | &QtSoftwareKeyboard::SubmitInlineText, Qt::QueuedConnection); | ||
| 127 | } | 1528 | } |
| 128 | 1529 | ||
| 129 | QtSoftwareKeyboard::~QtSoftwareKeyboard() = default; | 1530 | QtSoftwareKeyboard::~QtSoftwareKeyboard() = default; |
| 130 | 1531 | ||
| 131 | void QtSoftwareKeyboard::RequestText(std::function<void(std::optional<std::u16string>)> out, | 1532 | void QtSoftwareKeyboard::InitializeKeyboard( |
| 132 | Core::Frontend::SoftwareKeyboardParameters parameters) const { | 1533 | bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters, |
| 133 | text_output = std::move(out); | 1534 | std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> submit_normal_callback_, |
| 134 | emit MainWindowGetText(parameters); | 1535 | std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> |
| 1536 | submit_inline_callback_) { | ||
| 1537 | if (is_inline) { | ||
| 1538 | submit_inline_callback = std::move(submit_inline_callback_); | ||
| 1539 | } else { | ||
| 1540 | submit_normal_callback = std::move(submit_normal_callback_); | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | LOG_INFO(Service_AM, | ||
| 1544 | "\nKeyboardInitializeParameters:" | ||
| 1545 | "\nok_text={}" | ||
| 1546 | "\nheader_text={}" | ||
| 1547 | "\nsub_text={}" | ||
| 1548 | "\nguide_text={}" | ||
| 1549 | "\ninitial_text={}" | ||
| 1550 | "\nmax_text_length={}" | ||
| 1551 | "\nmin_text_length={}" | ||
| 1552 | "\ninitial_cursor_position={}" | ||
| 1553 | "\ntype={}" | ||
| 1554 | "\npassword_mode={}" | ||
| 1555 | "\ntext_draw_type={}" | ||
| 1556 | "\nkey_disable_flags={}" | ||
| 1557 | "\nuse_blur_background={}" | ||
| 1558 | "\nenable_backspace_button={}" | ||
| 1559 | "\nenable_return_button={}" | ||
| 1560 | "\ndisable_cancel_button={}", | ||
| 1561 | Common::UTF16ToUTF8(initialize_parameters.ok_text), | ||
| 1562 | Common::UTF16ToUTF8(initialize_parameters.header_text), | ||
| 1563 | Common::UTF16ToUTF8(initialize_parameters.sub_text), | ||
| 1564 | Common::UTF16ToUTF8(initialize_parameters.guide_text), | ||
| 1565 | Common::UTF16ToUTF8(initialize_parameters.initial_text), | ||
| 1566 | initialize_parameters.max_text_length, initialize_parameters.min_text_length, | ||
| 1567 | initialize_parameters.initial_cursor_position, initialize_parameters.type, | ||
| 1568 | initialize_parameters.password_mode, initialize_parameters.text_draw_type, | ||
| 1569 | initialize_parameters.key_disable_flags.raw, initialize_parameters.use_blur_background, | ||
| 1570 | initialize_parameters.enable_backspace_button, | ||
| 1571 | initialize_parameters.enable_return_button, | ||
| 1572 | initialize_parameters.disable_cancel_button); | ||
| 1573 | |||
| 1574 | emit MainWindowInitializeKeyboard(is_inline, std::move(initialize_parameters)); | ||
| 1575 | } | ||
| 1576 | |||
| 1577 | void QtSoftwareKeyboard::ShowNormalKeyboard() const { | ||
| 1578 | emit MainWindowShowNormalKeyboard(); | ||
| 1579 | } | ||
| 1580 | |||
| 1581 | void QtSoftwareKeyboard::ShowTextCheckDialog( | ||
| 1582 | Service::AM::Applets::SwkbdTextCheckResult text_check_result, | ||
| 1583 | std::u16string text_check_message) const { | ||
| 1584 | emit MainWindowShowTextCheckDialog(text_check_result, text_check_message); | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | void QtSoftwareKeyboard::ShowInlineKeyboard( | ||
| 1588 | Core::Frontend::InlineAppearParameters appear_parameters) const { | ||
| 1589 | LOG_INFO(Service_AM, | ||
| 1590 | "\nInlineAppearParameters:" | ||
| 1591 | "\nmax_text_length={}" | ||
| 1592 | "\nmin_text_length={}" | ||
| 1593 | "\nkey_top_scale_x={}" | ||
| 1594 | "\nkey_top_scale_y={}" | ||
| 1595 | "\nkey_top_translate_x={}" | ||
| 1596 | "\nkey_top_translate_y={}" | ||
| 1597 | "\ntype={}" | ||
| 1598 | "\nkey_disable_flags={}" | ||
| 1599 | "\nkey_top_as_floating={}" | ||
| 1600 | "\nenable_backspace_button={}" | ||
| 1601 | "\nenable_return_button={}" | ||
| 1602 | "\ndisable_cancel_button={}", | ||
| 1603 | appear_parameters.max_text_length, appear_parameters.min_text_length, | ||
| 1604 | appear_parameters.key_top_scale_x, appear_parameters.key_top_scale_y, | ||
| 1605 | appear_parameters.key_top_translate_x, appear_parameters.key_top_translate_y, | ||
| 1606 | appear_parameters.type, appear_parameters.key_disable_flags.raw, | ||
| 1607 | appear_parameters.key_top_as_floating, appear_parameters.enable_backspace_button, | ||
| 1608 | appear_parameters.enable_return_button, appear_parameters.disable_cancel_button); | ||
| 1609 | |||
| 1610 | emit MainWindowShowInlineKeyboard(std::move(appear_parameters)); | ||
| 1611 | } | ||
| 1612 | |||
| 1613 | void QtSoftwareKeyboard::HideInlineKeyboard() const { | ||
| 1614 | emit MainWindowHideInlineKeyboard(); | ||
| 1615 | } | ||
| 1616 | |||
| 1617 | void QtSoftwareKeyboard::InlineTextChanged( | ||
| 1618 | Core::Frontend::InlineTextParameters text_parameters) const { | ||
| 1619 | LOG_INFO(Service_AM, | ||
| 1620 | "\nInlineTextParameters:" | ||
| 1621 | "\ninput_text={}" | ||
| 1622 | "\ncursor_position={}", | ||
| 1623 | Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position); | ||
| 1624 | |||
| 1625 | emit MainWindowInlineTextChanged(std::move(text_parameters)); | ||
| 135 | } | 1626 | } |
| 136 | 1627 | ||
| 137 | void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message, | 1628 | void QtSoftwareKeyboard::ExitKeyboard() const { |
| 138 | std::function<void()> finished_check_) const { | 1629 | emit MainWindowExitKeyboard(); |
| 139 | finished_check = std::move(finished_check_); | ||
| 140 | emit MainWindowTextCheckDialog(error_message); | ||
| 141 | } | 1630 | } |
| 142 | 1631 | ||
| 143 | void QtSoftwareKeyboard::MainWindowFinishedText(std::optional<std::u16string> text) { | 1632 | void QtSoftwareKeyboard::SubmitNormalText(Service::AM::Applets::SwkbdResult result, |
| 144 | // Acquire the HLE mutex | 1633 | std::u16string submitted_text) const { |
| 145 | std::lock_guard lock{HLE::g_hle_lock}; | 1634 | submit_normal_callback(result, submitted_text); |
| 146 | text_output(std::move(text)); | ||
| 147 | } | 1635 | } |
| 148 | 1636 | ||
| 149 | void QtSoftwareKeyboard::MainWindowFinishedCheckDialog() { | 1637 | void QtSoftwareKeyboard::SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, |
| 150 | // Acquire the HLE mutex | 1638 | std::u16string submitted_text, |
| 151 | std::lock_guard lock{HLE::g_hle_lock}; | 1639 | s32 cursor_position) const { |
| 152 | finished_check(); | 1640 | submit_inline_callback(reply_type, submitted_text, cursor_position); |
| 153 | } | 1641 | } |
diff --git a/src/yuzu/applets/software_keyboard.h b/src/yuzu/applets/software_keyboard.h index 9e1094cce..1a03c098c 100644 --- a/src/yuzu/applets/software_keyboard.h +++ b/src/yuzu/applets/software_keyboard.h | |||
| @@ -1,54 +1,228 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | 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 <atomic> | ||
| 9 | #include <memory> | ||
| 10 | #include <thread> | ||
| 11 | |||
| 7 | #include <QDialog> | 12 | #include <QDialog> |
| 8 | #include <QValidator> | 13 | #include <QValidator> |
| 14 | |||
| 9 | #include "core/frontend/applets/software_keyboard.h" | 15 | #include "core/frontend/applets/software_keyboard.h" |
| 10 | 16 | ||
| 11 | class GMainWindow; | 17 | enum class HIDButton : u8; |
| 12 | class QDialogButtonBox; | ||
| 13 | class QLabel; | ||
| 14 | class QLineEdit; | ||
| 15 | class QVBoxLayout; | ||
| 16 | class QtSoftwareKeyboard; | ||
| 17 | 18 | ||
| 18 | class QtSoftwareKeyboardValidator final : public QValidator { | 19 | class InputInterpreter; |
| 19 | public: | ||
| 20 | explicit QtSoftwareKeyboardValidator(Core::Frontend::SoftwareKeyboardParameters parameters); | ||
| 21 | State validate(QString& input, int& pos) const override; | ||
| 22 | 20 | ||
| 23 | private: | 21 | namespace Core { |
| 24 | Core::Frontend::SoftwareKeyboardParameters parameters; | 22 | class System; |
| 25 | }; | 23 | } |
| 24 | |||
| 25 | namespace Ui { | ||
| 26 | class QtSoftwareKeyboardDialog; | ||
| 27 | } | ||
| 28 | |||
| 29 | class GMainWindow; | ||
| 26 | 30 | ||
| 27 | class QtSoftwareKeyboardDialog final : public QDialog { | 31 | class QtSoftwareKeyboardDialog final : public QDialog { |
| 28 | Q_OBJECT | 32 | Q_OBJECT |
| 29 | 33 | ||
| 30 | public: | 34 | public: |
| 31 | QtSoftwareKeyboardDialog(QWidget* parent, | 35 | QtSoftwareKeyboardDialog(QWidget* parent, Core::System& system_, bool is_inline_, |
| 32 | Core::Frontend::SoftwareKeyboardParameters parameters); | 36 | Core::Frontend::KeyboardInitializeParameters initialize_parameters_); |
| 33 | ~QtSoftwareKeyboardDialog() override; | 37 | ~QtSoftwareKeyboardDialog() override; |
| 34 | 38 | ||
| 35 | void accept() override; | 39 | void ShowNormalKeyboard(QPoint pos, QSize size); |
| 40 | |||
| 41 | void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, | ||
| 42 | std::u16string text_check_message); | ||
| 43 | |||
| 44 | void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos, | ||
| 45 | QSize size); | ||
| 46 | |||
| 47 | void HideInlineKeyboard(); | ||
| 48 | |||
| 49 | void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters); | ||
| 50 | |||
| 51 | void ExitKeyboard(); | ||
| 52 | |||
| 53 | signals: | ||
| 54 | void SubmitNormalText(Service::AM::Applets::SwkbdResult result, | ||
| 55 | std::u16string submitted_text) const; | ||
| 56 | |||
| 57 | void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, | ||
| 58 | std::u16string submitted_text, s32 cursor_position) const; | ||
| 59 | |||
| 60 | public slots: | ||
| 61 | void open() override; | ||
| 36 | void reject() override; | 62 | void reject() override; |
| 37 | 63 | ||
| 38 | std::u16string GetText() const; | 64 | protected: |
| 65 | /// We override the keyPressEvent for inputting text into the inline software keyboard. | ||
| 66 | void keyPressEvent(QKeyEvent* event) override; | ||
| 39 | 67 | ||
| 40 | private: | 68 | private: |
| 41 | std::u16string text; | 69 | enum class Direction { |
| 70 | Left, | ||
| 71 | Up, | ||
| 72 | Right, | ||
| 73 | Down, | ||
| 74 | }; | ||
| 75 | |||
| 76 | enum class BottomOSKIndex { | ||
| 77 | LowerCase, | ||
| 78 | UpperCase, | ||
| 79 | NumberPad, | ||
| 80 | }; | ||
| 81 | |||
| 82 | /** | ||
| 83 | * Moves and resizes the window to a specified position and size. | ||
| 84 | * | ||
| 85 | * @param pos Top-left window position | ||
| 86 | * @param size Window size | ||
| 87 | */ | ||
| 88 | void MoveAndResizeWindow(QPoint pos, QSize size); | ||
| 89 | |||
| 90 | /** | ||
| 91 | * Rescales all keyboard elements to account for High DPI displays. | ||
| 92 | * | ||
| 93 | * @param width Window width | ||
| 94 | * @param height Window height | ||
| 95 | * @param dpi_scale Display scaling factor | ||
| 96 | */ | ||
| 97 | void RescaleKeyboardElements(float width, float height, float dpi_scale); | ||
| 98 | |||
| 99 | /// Sets the keyboard type based on initialize_parameters. | ||
| 100 | void SetKeyboardType(); | ||
| 101 | |||
| 102 | /// Sets the password mode based on initialize_parameters. | ||
| 103 | void SetPasswordMode(); | ||
| 104 | |||
| 105 | /// Sets the text draw type based on initialize_parameters. | ||
| 106 | void SetTextDrawType(); | ||
| 107 | |||
| 108 | /// Sets the controller image at the bottom left of the software keyboard. | ||
| 109 | void SetControllerImage(); | ||
| 110 | |||
| 111 | /// Disables buttons based on initialize_parameters. | ||
| 112 | void DisableKeyboardButtons(); | ||
| 113 | |||
| 114 | /// Changes whether the backspace or/and ok buttons should be enabled or disabled. | ||
| 115 | void SetBackspaceOkEnabled(); | ||
| 116 | |||
| 117 | /** | ||
| 118 | * Validates the input text sent in based on the parameters in initialize_parameters. | ||
| 119 | * | ||
| 120 | * @param input_text Input text | ||
| 121 | * | ||
| 122 | * @returns True if the input text is valid, false otherwise. | ||
| 123 | */ | ||
| 124 | bool ValidateInputText(const QString& input_text); | ||
| 125 | |||
| 126 | /// Switches between LowerCase and UpperCase (Shift and Caps Lock) | ||
| 127 | void ChangeBottomOSKIndex(); | ||
| 128 | |||
| 129 | /// Processes a keyboard button click from the UI as normal keyboard input. | ||
| 130 | void NormalKeyboardButtonClicked(QPushButton* button); | ||
| 131 | |||
| 132 | /// Processes a keyboard button click from the UI as inline keyboard input. | ||
| 133 | void InlineKeyboardButtonClicked(QPushButton* button); | ||
| 134 | |||
| 135 | /** | ||
| 136 | * Inserts a string of arbitrary length into the current_text at the current cursor position. | ||
| 137 | * This is only used for the inline software keyboard. | ||
| 138 | */ | ||
| 139 | void InlineTextInsertString(std::u16string_view string); | ||
| 42 | 140 | ||
| 43 | QDialogButtonBox* buttons; | 141 | /// Setup the mouse hover workaround for "focusing" buttons. This should only be called once. |
| 44 | QLabel* header_label; | 142 | void SetupMouseHover(); |
| 45 | QLabel* sub_label; | ||
| 46 | QLabel* guide_label; | ||
| 47 | QLabel* length_label; | ||
| 48 | QLineEdit* line_edit; | ||
| 49 | QVBoxLayout* layout; | ||
| 50 | 143 | ||
| 51 | Core::Frontend::SoftwareKeyboardParameters parameters; | 144 | /** |
| 145 | * Handles button presses and converts them into keyboard input. | ||
| 146 | * | ||
| 147 | * @tparam HIDButton The list of buttons that can be converted into keyboard input. | ||
| 148 | */ | ||
| 149 | template <HIDButton... T> | ||
| 150 | void HandleButtonPressedOnce(); | ||
| 151 | |||
| 152 | /** | ||
| 153 | * Handles button holds and converts them into keyboard input. | ||
| 154 | * | ||
| 155 | * @tparam HIDButton The list of buttons that can be converted into keyboard input. | ||
| 156 | */ | ||
| 157 | template <HIDButton... T> | ||
| 158 | void HandleButtonHold(); | ||
| 159 | |||
| 160 | /** | ||
| 161 | * Translates a button press to focus or click a keyboard button. | ||
| 162 | * | ||
| 163 | * @param button The button press to process. | ||
| 164 | */ | ||
| 165 | void TranslateButtonPress(HIDButton button); | ||
| 166 | |||
| 167 | /** | ||
| 168 | * Moves the focus of a button in a certain direction. | ||
| 169 | * | ||
| 170 | * @param direction The direction to move. | ||
| 171 | */ | ||
| 172 | void MoveButtonDirection(Direction direction); | ||
| 173 | |||
| 174 | /** | ||
| 175 | * Moves the text cursor in a certain direction. | ||
| 176 | * | ||
| 177 | * @param direction The direction to move. | ||
| 178 | */ | ||
| 179 | void MoveTextCursorDirection(Direction direction); | ||
| 180 | |||
| 181 | void StartInputThread(); | ||
| 182 | void StopInputThread(); | ||
| 183 | |||
| 184 | /// The thread where input is being polled and processed. | ||
| 185 | void InputThread(); | ||
| 186 | |||
| 187 | std::unique_ptr<Ui::QtSoftwareKeyboardDialog> ui; | ||
| 188 | |||
| 189 | Core::System& system; | ||
| 190 | |||
| 191 | // True if it is the inline software keyboard. | ||
| 192 | bool is_inline; | ||
| 193 | |||
| 194 | // Common software keyboard initialize parameters. | ||
| 195 | Core::Frontend::KeyboardInitializeParameters initialize_parameters; | ||
| 196 | |||
| 197 | // Used only by the inline software keyboard since the QLineEdit or QTextEdit is hidden. | ||
| 198 | std::u16string current_text; | ||
| 199 | s32 cursor_position{0}; | ||
| 200 | |||
| 201 | static constexpr std::size_t NUM_ROWS_NORMAL = 5; | ||
| 202 | static constexpr std::size_t NUM_COLUMNS_NORMAL = 12; | ||
| 203 | static constexpr std::size_t NUM_ROWS_NUMPAD = 4; | ||
| 204 | static constexpr std::size_t NUM_COLUMNS_NUMPAD = 4; | ||
| 205 | |||
| 206 | // Stores the normal keyboard layout. | ||
| 207 | std::array<std::array<std::array<QPushButton*, NUM_COLUMNS_NORMAL>, NUM_ROWS_NORMAL>, 2> | ||
| 208 | keyboard_buttons; | ||
| 209 | // Stores the numberpad keyboard layout. | ||
| 210 | std::array<std::array<QPushButton*, NUM_COLUMNS_NUMPAD>, NUM_ROWS_NUMPAD> numberpad_buttons; | ||
| 211 | |||
| 212 | // Contains a set of all buttons used in keyboard_buttons and numberpad_buttons. | ||
| 213 | std::array<QPushButton*, 110> all_buttons; | ||
| 214 | |||
| 215 | std::size_t row{0}; | ||
| 216 | std::size_t column{0}; | ||
| 217 | |||
| 218 | BottomOSKIndex bottom_osk_index{BottomOSKIndex::LowerCase}; | ||
| 219 | std::atomic<bool> caps_lock_enabled{false}; | ||
| 220 | |||
| 221 | std::unique_ptr<InputInterpreter> input_interpreter; | ||
| 222 | |||
| 223 | std::thread input_thread; | ||
| 224 | |||
| 225 | std::atomic<bool> input_thread_running{}; | ||
| 52 | }; | 226 | }; |
| 53 | 227 | ||
| 54 | class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet { | 228 | class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet { |
| @@ -58,19 +232,54 @@ public: | |||
| 58 | explicit QtSoftwareKeyboard(GMainWindow& parent); | 232 | explicit QtSoftwareKeyboard(GMainWindow& parent); |
| 59 | ~QtSoftwareKeyboard() override; | 233 | ~QtSoftwareKeyboard() override; |
| 60 | 234 | ||
| 61 | void RequestText(std::function<void(std::optional<std::u16string>)> out, | 235 | void InitializeKeyboard( |
| 62 | Core::Frontend::SoftwareKeyboardParameters parameters) const override; | 236 | bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters, |
| 63 | void SendTextCheckDialog(std::u16string error_message, | 237 | std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> |
| 64 | std::function<void()> finished_check_) const override; | 238 | submit_normal_callback_, |
| 239 | std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> | ||
| 240 | submit_inline_callback_) override; | ||
| 241 | |||
| 242 | void ShowNormalKeyboard() const override; | ||
| 243 | |||
| 244 | void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, | ||
| 245 | std::u16string text_check_message) const override; | ||
| 246 | |||
| 247 | void ShowInlineKeyboard( | ||
| 248 | Core::Frontend::InlineAppearParameters appear_parameters) const override; | ||
| 249 | |||
| 250 | void HideInlineKeyboard() const override; | ||
| 251 | |||
| 252 | void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const override; | ||
| 253 | |||
| 254 | void ExitKeyboard() const override; | ||
| 65 | 255 | ||
| 66 | signals: | 256 | signals: |
| 67 | void MainWindowGetText(Core::Frontend::SoftwareKeyboardParameters parameters) const; | 257 | void MainWindowInitializeKeyboard( |
| 68 | void MainWindowTextCheckDialog(std::u16string error_message) const; | 258 | bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) const; |
| 259 | |||
| 260 | void MainWindowShowNormalKeyboard() const; | ||
| 261 | |||
| 262 | void MainWindowShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, | ||
| 263 | std::u16string text_check_message) const; | ||
| 264 | |||
| 265 | void MainWindowShowInlineKeyboard( | ||
| 266 | Core::Frontend::InlineAppearParameters appear_parameters) const; | ||
| 267 | |||
| 268 | void MainWindowHideInlineKeyboard() const; | ||
| 269 | |||
| 270 | void MainWindowInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const; | ||
| 271 | |||
| 272 | void MainWindowExitKeyboard() const; | ||
| 69 | 273 | ||
| 70 | private: | 274 | private: |
| 71 | void MainWindowFinishedText(std::optional<std::u16string> text); | 275 | void SubmitNormalText(Service::AM::Applets::SwkbdResult result, |
| 72 | void MainWindowFinishedCheckDialog(); | 276 | std::u16string submitted_text) const; |
| 277 | |||
| 278 | void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, | ||
| 279 | std::u16string submitted_text, s32 cursor_position) const; | ||
| 73 | 280 | ||
| 74 | mutable std::function<void(std::optional<std::u16string>)> text_output; | 281 | mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> |
| 75 | mutable std::function<void()> finished_check; | 282 | submit_normal_callback; |
| 283 | mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> | ||
| 284 | submit_inline_callback; | ||
| 76 | }; | 285 | }; |
diff --git a/src/yuzu/applets/software_keyboard.ui b/src/yuzu/applets/software_keyboard.ui new file mode 100644 index 000000000..b0a1fcde9 --- /dev/null +++ b/src/yuzu/applets/software_keyboard.ui | |||
| @@ -0,0 +1,3503 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>QtSoftwareKeyboardDialog</class> | ||
| 4 | <widget class="QDialog" name="QtSoftwareKeyboardDialog"> | ||
| 5 | <property name="geometry"> | ||
| 6 | <rect> | ||
| 7 | <x>0</x> | ||
| 8 | <y>0</y> | ||
| 9 | <width>1280</width> | ||
| 10 | <height>720</height> | ||
| 11 | </rect> | ||
| 12 | </property> | ||
| 13 | <property name="windowTitle"> | ||
| 14 | <string>Software Keyboard</string> | ||
| 15 | </property> | ||
| 16 | <property name="styleSheet"> | ||
| 17 | <string notr="true"/> | ||
| 18 | </property> | ||
| 19 | <layout class="QVBoxLayout" name="verticalLayout"> | ||
| 20 | <property name="spacing"> | ||
| 21 | <number>0</number> | ||
| 22 | </property> | ||
| 23 | <property name="leftMargin"> | ||
| 24 | <number>0</number> | ||
| 25 | </property> | ||
| 26 | <property name="topMargin"> | ||
| 27 | <number>0</number> | ||
| 28 | </property> | ||
| 29 | <property name="rightMargin"> | ||
| 30 | <number>0</number> | ||
| 31 | </property> | ||
| 32 | <property name="bottomMargin"> | ||
| 33 | <number>0</number> | ||
| 34 | </property> | ||
| 35 | <item> | ||
| 36 | <widget class="QWidget" name="mainOSK" native="true"> | ||
| 37 | <layout class="QVBoxLayout" name="verticalLayout_2" stretch="320,400"> | ||
| 38 | <property name="spacing"> | ||
| 39 | <number>0</number> | ||
| 40 | </property> | ||
| 41 | <property name="leftMargin"> | ||
| 42 | <number>0</number> | ||
| 43 | </property> | ||
| 44 | <property name="topMargin"> | ||
| 45 | <number>0</number> | ||
| 46 | </property> | ||
| 47 | <property name="rightMargin"> | ||
| 48 | <number>0</number> | ||
| 49 | </property> | ||
| 50 | <property name="bottomMargin"> | ||
| 51 | <number>0</number> | ||
| 52 | </property> | ||
| 53 | <item> | ||
| 54 | <widget class="QStackedWidget" name="topOSK"> | ||
| 55 | <property name="currentIndex"> | ||
| 56 | <number>0</number> | ||
| 57 | </property> | ||
| 58 | <widget class="QWidget" name="lineOSK"> | ||
| 59 | <property name="minimumSize"> | ||
| 60 | <size> | ||
| 61 | <width>0</width> | ||
| 62 | <height>100</height> | ||
| 63 | </size> | ||
| 64 | </property> | ||
| 65 | <layout class="QVBoxLayout" name="lineOSKVerticalLayout"> | ||
| 66 | <property name="spacing"> | ||
| 67 | <number>0</number> | ||
| 68 | </property> | ||
| 69 | <property name="leftMargin"> | ||
| 70 | <number>0</number> | ||
| 71 | </property> | ||
| 72 | <property name="topMargin"> | ||
| 73 | <number>0</number> | ||
| 74 | </property> | ||
| 75 | <property name="rightMargin"> | ||
| 76 | <number>0</number> | ||
| 77 | </property> | ||
| 78 | <property name="bottomMargin"> | ||
| 79 | <number>0</number> | ||
| 80 | </property> | ||
| 81 | <item> | ||
| 82 | <layout class="QGridLayout" name="gridLineOSK" rowstretch="40,50,23,48,65,94" columnstretch="130,1020,130"> | ||
| 83 | <property name="topMargin"> | ||
| 84 | <number>0</number> | ||
| 85 | </property> | ||
| 86 | <property name="spacing"> | ||
| 87 | <number>0</number> | ||
| 88 | </property> | ||
| 89 | <item row="4" column="2"> | ||
| 90 | <spacer name="horizontalSpacer_3"> | ||
| 91 | <property name="orientation"> | ||
| 92 | <enum>Qt::Horizontal</enum> | ||
| 93 | </property> | ||
| 94 | <property name="sizeHint" stdset="0"> | ||
| 95 | <size> | ||
| 96 | <width>40</width> | ||
| 97 | <height>20</height> | ||
| 98 | </size> | ||
| 99 | </property> | ||
| 100 | </spacer> | ||
| 101 | </item> | ||
| 102 | <item row="4" column="0"> | ||
| 103 | <spacer name="horizontalSpacer_4"> | ||
| 104 | <property name="orientation"> | ||
| 105 | <enum>Qt::Horizontal</enum> | ||
| 106 | </property> | ||
| 107 | <property name="sizeHint" stdset="0"> | ||
| 108 | <size> | ||
| 109 | <width>40</width> | ||
| 110 | <height>20</height> | ||
| 111 | </size> | ||
| 112 | </property> | ||
| 113 | </spacer> | ||
| 114 | </item> | ||
| 115 | <item row="5" column="1"> | ||
| 116 | <widget class="QWidget" name="charactersOSK" native="true"> | ||
| 117 | <layout class="QVBoxLayout" name="verticalLayout_5"> | ||
| 118 | <property name="spacing"> | ||
| 119 | <number>0</number> | ||
| 120 | </property> | ||
| 121 | <property name="leftMargin"> | ||
| 122 | <number>0</number> | ||
| 123 | </property> | ||
| 124 | <property name="topMargin"> | ||
| 125 | <number>0</number> | ||
| 126 | </property> | ||
| 127 | <property name="rightMargin"> | ||
| 128 | <number>0</number> | ||
| 129 | </property> | ||
| 130 | <property name="bottomMargin"> | ||
| 131 | <number>0</number> | ||
| 132 | </property> | ||
| 133 | <item alignment="Qt::AlignRight|Qt::AlignTop"> | ||
| 134 | <widget class="QLabel" name="label_characters"> | ||
| 135 | <property name="font"> | ||
| 136 | <font> | ||
| 137 | <pointsize>17</pointsize> | ||
| 138 | </font> | ||
| 139 | </property> | ||
| 140 | <property name="text"> | ||
| 141 | <string notr="true">0/32</string> | ||
| 142 | </property> | ||
| 143 | <property name="alignment"> | ||
| 144 | <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> | ||
| 145 | </property> | ||
| 146 | </widget> | ||
| 147 | </item> | ||
| 148 | </layout> | ||
| 149 | </widget> | ||
| 150 | </item> | ||
| 151 | <item row="3" column="1"> | ||
| 152 | <spacer name="verticalSpacer_2"> | ||
| 153 | <property name="orientation"> | ||
| 154 | <enum>Qt::Vertical</enum> | ||
| 155 | </property> | ||
| 156 | <property name="sizeHint" stdset="0"> | ||
| 157 | <size> | ||
| 158 | <width>20</width> | ||
| 159 | <height>40</height> | ||
| 160 | </size> | ||
| 161 | </property> | ||
| 162 | </spacer> | ||
| 163 | </item> | ||
| 164 | <item row="5" column="0"> | ||
| 165 | <spacer name="verticalSpacer_3"> | ||
| 166 | <property name="orientation"> | ||
| 167 | <enum>Qt::Vertical</enum> | ||
| 168 | </property> | ||
| 169 | <property name="sizeHint" stdset="0"> | ||
| 170 | <size> | ||
| 171 | <width>20</width> | ||
| 172 | <height>40</height> | ||
| 173 | </size> | ||
| 174 | </property> | ||
| 175 | </spacer> | ||
| 176 | </item> | ||
| 177 | <item row="4" column="1"> | ||
| 178 | <widget class="QWidget" name="inputOSK" native="true"> | ||
| 179 | <layout class="QVBoxLayout" name="verticalLayout_3"> | ||
| 180 | <item> | ||
| 181 | <widget class="QLineEdit" name="line_edit_osk"> | ||
| 182 | <property name="font"> | ||
| 183 | <font> | ||
| 184 | <pointsize>26</pointsize> | ||
| 185 | <weight>50</weight> | ||
| 186 | <bold>false</bold> | ||
| 187 | </font> | ||
| 188 | </property> | ||
| 189 | <property name="focusPolicy"> | ||
| 190 | <enum>Qt::StrongFocus</enum> | ||
| 191 | </property> | ||
| 192 | <property name="text"> | ||
| 193 | <string/> | ||
| 194 | </property> | ||
| 195 | <property name="maxLength"> | ||
| 196 | <number>32</number> | ||
| 197 | </property> | ||
| 198 | <property name="placeholderText"> | ||
| 199 | <string>Enter Text</string> | ||
| 200 | </property> | ||
| 201 | </widget> | ||
| 202 | </item> | ||
| 203 | </layout> | ||
| 204 | </widget> | ||
| 205 | </item> | ||
| 206 | <item row="0" column="1"> | ||
| 207 | <spacer name="verticalSpacer_4"> | ||
| 208 | <property name="orientation"> | ||
| 209 | <enum>Qt::Vertical</enum> | ||
| 210 | </property> | ||
| 211 | <property name="sizeHint" stdset="0"> | ||
| 212 | <size> | ||
| 213 | <width>20</width> | ||
| 214 | <height>40</height> | ||
| 215 | </size> | ||
| 216 | </property> | ||
| 217 | </spacer> | ||
| 218 | </item> | ||
| 219 | <item row="1" column="0" colspan="3"> | ||
| 220 | <widget class="QWidget" name="headerOSK" native="true"> | ||
| 221 | <layout class="QHBoxLayout" name="horizontalLayout_4" stretch="130,1020,130"> | ||
| 222 | <property name="spacing"> | ||
| 223 | <number>0</number> | ||
| 224 | </property> | ||
| 225 | <property name="leftMargin"> | ||
| 226 | <number>0</number> | ||
| 227 | </property> | ||
| 228 | <property name="topMargin"> | ||
| 229 | <number>0</number> | ||
| 230 | </property> | ||
| 231 | <property name="rightMargin"> | ||
| 232 | <number>0</number> | ||
| 233 | </property> | ||
| 234 | <property name="bottomMargin"> | ||
| 235 | <number>0</number> | ||
| 236 | </property> | ||
| 237 | <item> | ||
| 238 | <spacer name="horizontalSpacer_18"> | ||
| 239 | <property name="orientation"> | ||
| 240 | <enum>Qt::Horizontal</enum> | ||
| 241 | </property> | ||
| 242 | <property name="sizeHint" stdset="0"> | ||
| 243 | <size> | ||
| 244 | <width>127</width> | ||
| 245 | <height>20</height> | ||
| 246 | </size> | ||
| 247 | </property> | ||
| 248 | </spacer> | ||
| 249 | </item> | ||
| 250 | <item> | ||
| 251 | <widget class="QLabel" name="label_header"> | ||
| 252 | <property name="font"> | ||
| 253 | <font> | ||
| 254 | <pointsize>23</pointsize> | ||
| 255 | </font> | ||
| 256 | </property> | ||
| 257 | <property name="text"> | ||
| 258 | <string/> | ||
| 259 | </property> | ||
| 260 | </widget> | ||
| 261 | </item> | ||
| 262 | <item> | ||
| 263 | <spacer name="horizontalSpacer_19"> | ||
| 264 | <property name="orientation"> | ||
| 265 | <enum>Qt::Horizontal</enum> | ||
| 266 | </property> | ||
| 267 | <property name="sizeHint" stdset="0"> | ||
| 268 | <size> | ||
| 269 | <width>127</width> | ||
| 270 | <height>20</height> | ||
| 271 | </size> | ||
| 272 | </property> | ||
| 273 | </spacer> | ||
| 274 | </item> | ||
| 275 | </layout> | ||
| 276 | </widget> | ||
| 277 | </item> | ||
| 278 | <item row="2" column="0" colspan="3"> | ||
| 279 | <widget class="QWidget" name="subOSK" native="true"> | ||
| 280 | <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="130,1020,130"> | ||
| 281 | <property name="spacing"> | ||
| 282 | <number>0</number> | ||
| 283 | </property> | ||
| 284 | <property name="leftMargin"> | ||
| 285 | <number>0</number> | ||
| 286 | </property> | ||
| 287 | <property name="topMargin"> | ||
| 288 | <number>0</number> | ||
| 289 | </property> | ||
| 290 | <property name="rightMargin"> | ||
| 291 | <number>0</number> | ||
| 292 | </property> | ||
| 293 | <property name="bottomMargin"> | ||
| 294 | <number>0</number> | ||
| 295 | </property> | ||
| 296 | <item> | ||
| 297 | <spacer name="horizontalSpacer_16"> | ||
| 298 | <property name="orientation"> | ||
| 299 | <enum>Qt::Horizontal</enum> | ||
| 300 | </property> | ||
| 301 | <property name="sizeHint" stdset="0"> | ||
| 302 | <size> | ||
| 303 | <width>127</width> | ||
| 304 | <height>20</height> | ||
| 305 | </size> | ||
| 306 | </property> | ||
| 307 | </spacer> | ||
| 308 | </item> | ||
| 309 | <item> | ||
| 310 | <widget class="QLabel" name="label_sub"> | ||
| 311 | <property name="font"> | ||
| 312 | <font> | ||
| 313 | <pointsize>17</pointsize> | ||
| 314 | </font> | ||
| 315 | </property> | ||
| 316 | <property name="text"> | ||
| 317 | <string/> | ||
| 318 | </property> | ||
| 319 | </widget> | ||
| 320 | </item> | ||
| 321 | <item> | ||
| 322 | <spacer name="horizontalSpacer_17"> | ||
| 323 | <property name="orientation"> | ||
| 324 | <enum>Qt::Horizontal</enum> | ||
| 325 | </property> | ||
| 326 | <property name="sizeHint" stdset="0"> | ||
| 327 | <size> | ||
| 328 | <width>127</width> | ||
| 329 | <height>20</height> | ||
| 330 | </size> | ||
| 331 | </property> | ||
| 332 | </spacer> | ||
| 333 | </item> | ||
| 334 | </layout> | ||
| 335 | </widget> | ||
| 336 | </item> | ||
| 337 | </layout> | ||
| 338 | </item> | ||
| 339 | </layout> | ||
| 340 | </widget> | ||
| 341 | <widget class="QWidget" name="boxOSK"> | ||
| 342 | <layout class="QVBoxLayout" name="boxOSKVerticalLayout"> | ||
| 343 | <property name="spacing"> | ||
| 344 | <number>0</number> | ||
| 345 | </property> | ||
| 346 | <property name="leftMargin"> | ||
| 347 | <number>0</number> | ||
| 348 | </property> | ||
| 349 | <property name="topMargin"> | ||
| 350 | <number>0</number> | ||
| 351 | </property> | ||
| 352 | <property name="rightMargin"> | ||
| 353 | <number>0</number> | ||
| 354 | </property> | ||
| 355 | <property name="bottomMargin"> | ||
| 356 | <number>0</number> | ||
| 357 | </property> | ||
| 358 | <item> | ||
| 359 | <layout class="QGridLayout" name="gridBoxOSK" rowstretch="61,178,81" columnstretch="120,1040,120"> | ||
| 360 | <property name="leftMargin"> | ||
| 361 | <number>0</number> | ||
| 362 | </property> | ||
| 363 | <property name="topMargin"> | ||
| 364 | <number>0</number> | ||
| 365 | </property> | ||
| 366 | <property name="rightMargin"> | ||
| 367 | <number>0</number> | ||
| 368 | </property> | ||
| 369 | <property name="bottomMargin"> | ||
| 370 | <number>0</number> | ||
| 371 | </property> | ||
| 372 | <property name="spacing"> | ||
| 373 | <number>0</number> | ||
| 374 | </property> | ||
| 375 | <item row="0" column="1"> | ||
| 376 | <spacer name="verticalSpacer_5"> | ||
| 377 | <property name="orientation"> | ||
| 378 | <enum>Qt::Vertical</enum> | ||
| 379 | </property> | ||
| 380 | <property name="sizeHint" stdset="0"> | ||
| 381 | <size> | ||
| 382 | <width>20</width> | ||
| 383 | <height>40</height> | ||
| 384 | </size> | ||
| 385 | </property> | ||
| 386 | </spacer> | ||
| 387 | </item> | ||
| 388 | <item row="1" column="0"> | ||
| 389 | <spacer name="horizontalSpacer_20"> | ||
| 390 | <property name="orientation"> | ||
| 391 | <enum>Qt::Horizontal</enum> | ||
| 392 | </property> | ||
| 393 | <property name="sizeHint" stdset="0"> | ||
| 394 | <size> | ||
| 395 | <width>40</width> | ||
| 396 | <height>20</height> | ||
| 397 | </size> | ||
| 398 | </property> | ||
| 399 | </spacer> | ||
| 400 | </item> | ||
| 401 | <item row="1" column="2"> | ||
| 402 | <spacer name="horizontalSpacer_21"> | ||
| 403 | <property name="orientation"> | ||
| 404 | <enum>Qt::Horizontal</enum> | ||
| 405 | </property> | ||
| 406 | <property name="sizeHint" stdset="0"> | ||
| 407 | <size> | ||
| 408 | <width>40</width> | ||
| 409 | <height>20</height> | ||
| 410 | </size> | ||
| 411 | </property> | ||
| 412 | </spacer> | ||
| 413 | </item> | ||
| 414 | <item row="2" column="1" alignment="Qt::AlignRight|Qt::AlignTop"> | ||
| 415 | <widget class="QWidget" name="charactersBoxOSK" native="true"> | ||
| 416 | <layout class="QVBoxLayout" name="verticalLayout_4"> | ||
| 417 | <property name="spacing"> | ||
| 418 | <number>0</number> | ||
| 419 | </property> | ||
| 420 | <property name="leftMargin"> | ||
| 421 | <number>0</number> | ||
| 422 | </property> | ||
| 423 | <property name="topMargin"> | ||
| 424 | <number>0</number> | ||
| 425 | </property> | ||
| 426 | <property name="rightMargin"> | ||
| 427 | <number>0</number> | ||
| 428 | </property> | ||
| 429 | <property name="bottomMargin"> | ||
| 430 | <number>0</number> | ||
| 431 | </property> | ||
| 432 | <item> | ||
| 433 | <widget class="QLabel" name="label_characters_box"> | ||
| 434 | <property name="enabled"> | ||
| 435 | <bool>true</bool> | ||
| 436 | </property> | ||
| 437 | <property name="font"> | ||
| 438 | <font> | ||
| 439 | <pointsize>17</pointsize> | ||
| 440 | </font> | ||
| 441 | </property> | ||
| 442 | <property name="text"> | ||
| 443 | <string notr="true">0/500</string> | ||
| 444 | </property> | ||
| 445 | </widget> | ||
| 446 | </item> | ||
| 447 | </layout> | ||
| 448 | </widget> | ||
| 449 | </item> | ||
| 450 | <item row="1" column="1"> | ||
| 451 | <widget class="QWidget" name="inputBoxOSK" native="true"> | ||
| 452 | <layout class="QVBoxLayout" name="verticalLayout_6"> | ||
| 453 | <property name="spacing"> | ||
| 454 | <number>0</number> | ||
| 455 | </property> | ||
| 456 | <property name="leftMargin"> | ||
| 457 | <number>14</number> | ||
| 458 | </property> | ||
| 459 | <property name="topMargin"> | ||
| 460 | <number>9</number> | ||
| 461 | </property> | ||
| 462 | <property name="rightMargin"> | ||
| 463 | <number>14</number> | ||
| 464 | </property> | ||
| 465 | <property name="bottomMargin"> | ||
| 466 | <number>9</number> | ||
| 467 | </property> | ||
| 468 | <item> | ||
| 469 | <widget class="QTextEdit" name="text_edit_osk"> | ||
| 470 | <property name="font"> | ||
| 471 | <font> | ||
| 472 | <pointsize>26</pointsize> | ||
| 473 | </font> | ||
| 474 | </property> | ||
| 475 | <property name="focusPolicy"> | ||
| 476 | <enum>Qt::StrongFocus</enum> | ||
| 477 | </property> | ||
| 478 | <property name="html"> | ||
| 479 | <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> | ||
| 480 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> | ||
| 481 | p, li { white-space: pre-wrap; } | ||
| 482 | </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:26pt; font-weight:400; font-style:normal;"> | ||
| 483 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string> | ||
| 484 | </property> | ||
| 485 | </widget> | ||
| 486 | </item> | ||
| 487 | </layout> | ||
| 488 | </widget> | ||
| 489 | </item> | ||
| 490 | </layout> | ||
| 491 | </item> | ||
| 492 | </layout> | ||
| 493 | </widget> | ||
| 494 | </widget> | ||
| 495 | </item> | ||
| 496 | <item> | ||
| 497 | <widget class="QStackedWidget" name="bottomOSK"> | ||
| 498 | <property name="currentIndex"> | ||
| 499 | <number>0</number> | ||
| 500 | </property> | ||
| 501 | <widget class="QWidget" name="normalOSK"> | ||
| 502 | <layout class="QVBoxLayout" name="normalPageVerticalLayout"> | ||
| 503 | <property name="leftMargin"> | ||
| 504 | <number>0</number> | ||
| 505 | </property> | ||
| 506 | <property name="topMargin"> | ||
| 507 | <number>0</number> | ||
| 508 | </property> | ||
| 509 | <property name="rightMargin"> | ||
| 510 | <number>0</number> | ||
| 511 | </property> | ||
| 512 | <property name="bottomMargin"> | ||
| 513 | <number>0</number> | ||
| 514 | </property> | ||
| 515 | <item> | ||
| 516 | <layout class="QGridLayout" name="kbOSKnormal" rowstretch="15,63,63,63,63,63,70" columnstretch="54,96,96,96,96,96,96,96,96,96,96,96,116,54"> | ||
| 517 | <property name="spacing"> | ||
| 518 | <number>0</number> | ||
| 519 | </property> | ||
| 520 | <item row="6" column="1" colspan="12"> | ||
| 521 | <widget class="QWidget" name="legendOSK" native="true"> | ||
| 522 | <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="70,525,25,12,22,41,25,12,22,41,25,12,47,37,29,12,69,37,29,12,56,8"> | ||
| 523 | <property name="spacing"> | ||
| 524 | <number>0</number> | ||
| 525 | </property> | ||
| 526 | <property name="leftMargin"> | ||
| 527 | <number>2</number> | ||
| 528 | </property> | ||
| 529 | <property name="topMargin"> | ||
| 530 | <number>0</number> | ||
| 531 | </property> | ||
| 532 | <property name="rightMargin"> | ||
| 533 | <number>0</number> | ||
| 534 | </property> | ||
| 535 | <property name="bottomMargin"> | ||
| 536 | <number>0</number> | ||
| 537 | </property> | ||
| 538 | <item> | ||
| 539 | <widget class="QWidget" name="icon_controller" native="true"> | ||
| 540 | <property name="styleSheet"> | ||
| 541 | <string notr="true"/> | ||
| 542 | </property> | ||
| 543 | </widget> | ||
| 544 | </item> | ||
| 545 | <item> | ||
| 546 | <spacer name="horizontalSpacer_5"> | ||
| 547 | <property name="orientation"> | ||
| 548 | <enum>Qt::Horizontal</enum> | ||
| 549 | </property> | ||
| 550 | <property name="sizeHint" stdset="0"> | ||
| 551 | <size> | ||
| 552 | <width>0</width> | ||
| 553 | <height>20</height> | ||
| 554 | </size> | ||
| 555 | </property> | ||
| 556 | </spacer> | ||
| 557 | </item> | ||
| 558 | <item> | ||
| 559 | <widget class="QWidget" name="button_L" native="true"/> | ||
| 560 | </item> | ||
| 561 | <item> | ||
| 562 | <spacer name="horizontalSpacer_14"> | ||
| 563 | <property name="orientation"> | ||
| 564 | <enum>Qt::Horizontal</enum> | ||
| 565 | </property> | ||
| 566 | <property name="sizeHint" stdset="0"> | ||
| 567 | <size> | ||
| 568 | <width>0</width> | ||
| 569 | <height>20</height> | ||
| 570 | </size> | ||
| 571 | </property> | ||
| 572 | </spacer> | ||
| 573 | </item> | ||
| 574 | <item> | ||
| 575 | <widget class="QWidget" name="arrow_left" native="true"/> | ||
| 576 | </item> | ||
| 577 | <item> | ||
| 578 | <spacer name="horizontalSpacer_13"> | ||
| 579 | <property name="orientation"> | ||
| 580 | <enum>Qt::Horizontal</enum> | ||
| 581 | </property> | ||
| 582 | <property name="sizeHint" stdset="0"> | ||
| 583 | <size> | ||
| 584 | <width>0</width> | ||
| 585 | <height>20</height> | ||
| 586 | </size> | ||
| 587 | </property> | ||
| 588 | </spacer> | ||
| 589 | </item> | ||
| 590 | <item> | ||
| 591 | <widget class="QWidget" name="button_R" native="true"/> | ||
| 592 | </item> | ||
| 593 | <item> | ||
| 594 | <spacer name="horizontalSpacer_12"> | ||
| 595 | <property name="orientation"> | ||
| 596 | <enum>Qt::Horizontal</enum> | ||
| 597 | </property> | ||
| 598 | <property name="sizeHint" stdset="0"> | ||
| 599 | <size> | ||
| 600 | <width>0</width> | ||
| 601 | <height>20</height> | ||
| 602 | </size> | ||
| 603 | </property> | ||
| 604 | </spacer> | ||
| 605 | </item> | ||
| 606 | <item> | ||
| 607 | <widget class="QWidget" name="arrow_right" native="true"/> | ||
| 608 | </item> | ||
| 609 | <item> | ||
| 610 | <spacer name="horizontalSpacer_11"> | ||
| 611 | <property name="orientation"> | ||
| 612 | <enum>Qt::Horizontal</enum> | ||
| 613 | </property> | ||
| 614 | <property name="sizeHint" stdset="0"> | ||
| 615 | <size> | ||
| 616 | <width>0</width> | ||
| 617 | <height>20</height> | ||
| 618 | </size> | ||
| 619 | </property> | ||
| 620 | </spacer> | ||
| 621 | </item> | ||
| 622 | <item> | ||
| 623 | <widget class="QWidget" name="button_press_stick" native="true"/> | ||
| 624 | </item> | ||
| 625 | <item> | ||
| 626 | <spacer name="horizontalSpacer_10"> | ||
| 627 | <property name="orientation"> | ||
| 628 | <enum>Qt::Horizontal</enum> | ||
| 629 | </property> | ||
| 630 | <property name="sizeHint" stdset="0"> | ||
| 631 | <size> | ||
| 632 | <width>0</width> | ||
| 633 | <height>20</height> | ||
| 634 | </size> | ||
| 635 | </property> | ||
| 636 | </spacer> | ||
| 637 | </item> | ||
| 638 | <item> | ||
| 639 | <widget class="QLabel" name="label_shift"> | ||
| 640 | <property name="font"> | ||
| 641 | <font> | ||
| 642 | <pointsize>18</pointsize> | ||
| 643 | </font> | ||
| 644 | </property> | ||
| 645 | <property name="text"> | ||
| 646 | <string notr="true">Shift</string> | ||
| 647 | </property> | ||
| 648 | </widget> | ||
| 649 | </item> | ||
| 650 | <item> | ||
| 651 | <spacer name="horizontalSpacer_15"> | ||
| 652 | <property name="orientation"> | ||
| 653 | <enum>Qt::Horizontal</enum> | ||
| 654 | </property> | ||
| 655 | <property name="sizeHint" stdset="0"> | ||
| 656 | <size> | ||
| 657 | <width>0</width> | ||
| 658 | <height>20</height> | ||
| 659 | </size> | ||
| 660 | </property> | ||
| 661 | </spacer> | ||
| 662 | </item> | ||
| 663 | <item> | ||
| 664 | <widget class="QWidget" name="button_X" native="true"/> | ||
| 665 | </item> | ||
| 666 | <item> | ||
| 667 | <spacer name="horizontalSpacer_9"> | ||
| 668 | <property name="orientation"> | ||
| 669 | <enum>Qt::Horizontal</enum> | ||
| 670 | </property> | ||
| 671 | <property name="sizeHint" stdset="0"> | ||
| 672 | <size> | ||
| 673 | <width>0</width> | ||
| 674 | <height>20</height> | ||
| 675 | </size> | ||
| 676 | </property> | ||
| 677 | </spacer> | ||
| 678 | </item> | ||
| 679 | <item> | ||
| 680 | <widget class="QLabel" name="label_cancel"> | ||
| 681 | <property name="font"> | ||
| 682 | <font> | ||
| 683 | <pointsize>18</pointsize> | ||
| 684 | </font> | ||
| 685 | </property> | ||
| 686 | <property name="text"> | ||
| 687 | <string notr="true">Cancel</string> | ||
| 688 | </property> | ||
| 689 | </widget> | ||
| 690 | </item> | ||
| 691 | <item> | ||
| 692 | <spacer name="horizontalSpacer_8"> | ||
| 693 | <property name="orientation"> | ||
| 694 | <enum>Qt::Horizontal</enum> | ||
| 695 | </property> | ||
| 696 | <property name="sizeHint" stdset="0"> | ||
| 697 | <size> | ||
| 698 | <width>0</width> | ||
| 699 | <height>20</height> | ||
| 700 | </size> | ||
| 701 | </property> | ||
| 702 | </spacer> | ||
| 703 | </item> | ||
| 704 | <item> | ||
| 705 | <widget class="QWidget" name="button_A" native="true"/> | ||
| 706 | </item> | ||
| 707 | <item> | ||
| 708 | <spacer name="horizontalSpacer_7"> | ||
| 709 | <property name="orientation"> | ||
| 710 | <enum>Qt::Horizontal</enum> | ||
| 711 | </property> | ||
| 712 | <property name="sizeHint" stdset="0"> | ||
| 713 | <size> | ||
| 714 | <width>0</width> | ||
| 715 | <height>20</height> | ||
| 716 | </size> | ||
| 717 | </property> | ||
| 718 | </spacer> | ||
| 719 | </item> | ||
| 720 | <item> | ||
| 721 | <widget class="QLabel" name="label_enter"> | ||
| 722 | <property name="font"> | ||
| 723 | <font> | ||
| 724 | <pointsize>18</pointsize> | ||
| 725 | </font> | ||
| 726 | </property> | ||
| 727 | <property name="text"> | ||
| 728 | <string notr="true">Enter</string> | ||
| 729 | </property> | ||
| 730 | </widget> | ||
| 731 | </item> | ||
| 732 | <item> | ||
| 733 | <spacer name="horizontalSpacer_6"> | ||
| 734 | <property name="orientation"> | ||
| 735 | <enum>Qt::Horizontal</enum> | ||
| 736 | </property> | ||
| 737 | <property name="sizeHint" stdset="0"> | ||
| 738 | <size> | ||
| 739 | <width>0</width> | ||
| 740 | <height>20</height> | ||
| 741 | </size> | ||
| 742 | </property> | ||
| 743 | </spacer> | ||
| 744 | </item> | ||
| 745 | </layout> | ||
| 746 | </widget> | ||
| 747 | </item> | ||
| 748 | <item row="1" column="11"> | ||
| 749 | <widget class="QPushButton" name="button_minus"> | ||
| 750 | <property name="sizePolicy"> | ||
| 751 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 752 | <horstretch>1</horstretch> | ||
| 753 | <verstretch>1</verstretch> | ||
| 754 | </sizepolicy> | ||
| 755 | </property> | ||
| 756 | <property name="font"> | ||
| 757 | <font> | ||
| 758 | <pointsize>28</pointsize> | ||
| 759 | </font> | ||
| 760 | </property> | ||
| 761 | <property name="text"> | ||
| 762 | <string notr="true">-</string> | ||
| 763 | </property> | ||
| 764 | </widget> | ||
| 765 | </item> | ||
| 766 | <item row="3" column="11"> | ||
| 767 | <widget class="QPushButton" name="button_apostrophe"> | ||
| 768 | <property name="sizePolicy"> | ||
| 769 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 770 | <horstretch>1</horstretch> | ||
| 771 | <verstretch>1</verstretch> | ||
| 772 | </sizepolicy> | ||
| 773 | </property> | ||
| 774 | <property name="font"> | ||
| 775 | <font> | ||
| 776 | <pointsize>28</pointsize> | ||
| 777 | </font> | ||
| 778 | </property> | ||
| 779 | <property name="text"> | ||
| 780 | <string notr="true">'</string> | ||
| 781 | </property> | ||
| 782 | </widget> | ||
| 783 | </item> | ||
| 784 | <item row="2" column="11"> | ||
| 785 | <widget class="QPushButton" name="button_slash"> | ||
| 786 | <property name="sizePolicy"> | ||
| 787 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 788 | <horstretch>1</horstretch> | ||
| 789 | <verstretch>1</verstretch> | ||
| 790 | </sizepolicy> | ||
| 791 | </property> | ||
| 792 | <property name="font"> | ||
| 793 | <font> | ||
| 794 | <pointsize>28</pointsize> | ||
| 795 | </font> | ||
| 796 | </property> | ||
| 797 | <property name="text"> | ||
| 798 | <string notr="true">/</string> | ||
| 799 | </property> | ||
| 800 | </widget> | ||
| 801 | </item> | ||
| 802 | <item row="4" column="11"> | ||
| 803 | <widget class="QPushButton" name="button_exclamation"> | ||
| 804 | <property name="sizePolicy"> | ||
| 805 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 806 | <horstretch>1</horstretch> | ||
| 807 | <verstretch>1</verstretch> | ||
| 808 | </sizepolicy> | ||
| 809 | </property> | ||
| 810 | <property name="font"> | ||
| 811 | <font> | ||
| 812 | <pointsize>28</pointsize> | ||
| 813 | </font> | ||
| 814 | </property> | ||
| 815 | <property name="text"> | ||
| 816 | <string notr="true">!</string> | ||
| 817 | </property> | ||
| 818 | </widget> | ||
| 819 | </item> | ||
| 820 | <item row="1" column="7"> | ||
| 821 | <widget class="QPushButton" name="button_7"> | ||
| 822 | <property name="sizePolicy"> | ||
| 823 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 824 | <horstretch>1</horstretch> | ||
| 825 | <verstretch>1</verstretch> | ||
| 826 | </sizepolicy> | ||
| 827 | </property> | ||
| 828 | <property name="font"> | ||
| 829 | <font> | ||
| 830 | <pointsize>28</pointsize> | ||
| 831 | </font> | ||
| 832 | </property> | ||
| 833 | <property name="text"> | ||
| 834 | <string notr="true">7</string> | ||
| 835 | </property> | ||
| 836 | </widget> | ||
| 837 | </item> | ||
| 838 | <item row="1" column="8"> | ||
| 839 | <widget class="QPushButton" name="button_8"> | ||
| 840 | <property name="sizePolicy"> | ||
| 841 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 842 | <horstretch>1</horstretch> | ||
| 843 | <verstretch>1</verstretch> | ||
| 844 | </sizepolicy> | ||
| 845 | </property> | ||
| 846 | <property name="font"> | ||
| 847 | <font> | ||
| 848 | <pointsize>28</pointsize> | ||
| 849 | </font> | ||
| 850 | </property> | ||
| 851 | <property name="text"> | ||
| 852 | <string notr="true">8</string> | ||
| 853 | </property> | ||
| 854 | </widget> | ||
| 855 | </item> | ||
| 856 | <item row="1" column="10"> | ||
| 857 | <widget class="QPushButton" name="button_0"> | ||
| 858 | <property name="sizePolicy"> | ||
| 859 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 860 | <horstretch>1</horstretch> | ||
| 861 | <verstretch>1</verstretch> | ||
| 862 | </sizepolicy> | ||
| 863 | </property> | ||
| 864 | <property name="font"> | ||
| 865 | <font> | ||
| 866 | <pointsize>28</pointsize> | ||
| 867 | </font> | ||
| 868 | </property> | ||
| 869 | <property name="text"> | ||
| 870 | <string notr="true">0</string> | ||
| 871 | </property> | ||
| 872 | </widget> | ||
| 873 | </item> | ||
| 874 | <item row="1" column="9"> | ||
| 875 | <widget class="QPushButton" name="button_9"> | ||
| 876 | <property name="sizePolicy"> | ||
| 877 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 878 | <horstretch>1</horstretch> | ||
| 879 | <verstretch>1</verstretch> | ||
| 880 | </sizepolicy> | ||
| 881 | </property> | ||
| 882 | <property name="font"> | ||
| 883 | <font> | ||
| 884 | <pointsize>28</pointsize> | ||
| 885 | </font> | ||
| 886 | </property> | ||
| 887 | <property name="text"> | ||
| 888 | <string notr="true">9</string> | ||
| 889 | </property> | ||
| 890 | </widget> | ||
| 891 | </item> | ||
| 892 | <item row="2" column="2"> | ||
| 893 | <widget class="QPushButton" name="button_w"> | ||
| 894 | <property name="sizePolicy"> | ||
| 895 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 896 | <horstretch>1</horstretch> | ||
| 897 | <verstretch>1</verstretch> | ||
| 898 | </sizepolicy> | ||
| 899 | </property> | ||
| 900 | <property name="font"> | ||
| 901 | <font> | ||
| 902 | <pointsize>28</pointsize> | ||
| 903 | </font> | ||
| 904 | </property> | ||
| 905 | <property name="text"> | ||
| 906 | <string notr="true">w</string> | ||
| 907 | </property> | ||
| 908 | </widget> | ||
| 909 | </item> | ||
| 910 | <item row="2" column="4"> | ||
| 911 | <widget class="QPushButton" name="button_r"> | ||
| 912 | <property name="sizePolicy"> | ||
| 913 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 914 | <horstretch>1</horstretch> | ||
| 915 | <verstretch>1</verstretch> | ||
| 916 | </sizepolicy> | ||
| 917 | </property> | ||
| 918 | <property name="font"> | ||
| 919 | <font> | ||
| 920 | <pointsize>28</pointsize> | ||
| 921 | </font> | ||
| 922 | </property> | ||
| 923 | <property name="text"> | ||
| 924 | <string notr="true">r</string> | ||
| 925 | </property> | ||
| 926 | </widget> | ||
| 927 | </item> | ||
| 928 | <item row="2" column="3"> | ||
| 929 | <widget class="QPushButton" name="button_e"> | ||
| 930 | <property name="sizePolicy"> | ||
| 931 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 932 | <horstretch>1</horstretch> | ||
| 933 | <verstretch>1</verstretch> | ||
| 934 | </sizepolicy> | ||
| 935 | </property> | ||
| 936 | <property name="font"> | ||
| 937 | <font> | ||
| 938 | <pointsize>28</pointsize> | ||
| 939 | </font> | ||
| 940 | </property> | ||
| 941 | <property name="text"> | ||
| 942 | <string notr="true">e</string> | ||
| 943 | </property> | ||
| 944 | </widget> | ||
| 945 | </item> | ||
| 946 | <item row="2" column="1"> | ||
| 947 | <widget class="QPushButton" name="button_q"> | ||
| 948 | <property name="sizePolicy"> | ||
| 949 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 950 | <horstretch>1</horstretch> | ||
| 951 | <verstretch>1</verstretch> | ||
| 952 | </sizepolicy> | ||
| 953 | </property> | ||
| 954 | <property name="font"> | ||
| 955 | <font> | ||
| 956 | <pointsize>28</pointsize> | ||
| 957 | </font> | ||
| 958 | </property> | ||
| 959 | <property name="text"> | ||
| 960 | <string notr="true">q</string> | ||
| 961 | </property> | ||
| 962 | </widget> | ||
| 963 | </item> | ||
| 964 | <item row="2" column="7"> | ||
| 965 | <widget class="QPushButton" name="button_u"> | ||
| 966 | <property name="sizePolicy"> | ||
| 967 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 968 | <horstretch>1</horstretch> | ||
| 969 | <verstretch>1</verstretch> | ||
| 970 | </sizepolicy> | ||
| 971 | </property> | ||
| 972 | <property name="font"> | ||
| 973 | <font> | ||
| 974 | <pointsize>28</pointsize> | ||
| 975 | </font> | ||
| 976 | </property> | ||
| 977 | <property name="text"> | ||
| 978 | <string notr="true">u</string> | ||
| 979 | </property> | ||
| 980 | </widget> | ||
| 981 | </item> | ||
| 982 | <item row="2" column="6"> | ||
| 983 | <widget class="QPushButton" name="button_y"> | ||
| 984 | <property name="sizePolicy"> | ||
| 985 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 986 | <horstretch>1</horstretch> | ||
| 987 | <verstretch>1</verstretch> | ||
| 988 | </sizepolicy> | ||
| 989 | </property> | ||
| 990 | <property name="font"> | ||
| 991 | <font> | ||
| 992 | <pointsize>28</pointsize> | ||
| 993 | </font> | ||
| 994 | </property> | ||
| 995 | <property name="text"> | ||
| 996 | <string notr="true">y</string> | ||
| 997 | </property> | ||
| 998 | </widget> | ||
| 999 | </item> | ||
| 1000 | <item row="2" column="5"> | ||
| 1001 | <widget class="QPushButton" name="button_t"> | ||
| 1002 | <property name="sizePolicy"> | ||
| 1003 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1004 | <horstretch>1</horstretch> | ||
| 1005 | <verstretch>1</verstretch> | ||
| 1006 | </sizepolicy> | ||
| 1007 | </property> | ||
| 1008 | <property name="font"> | ||
| 1009 | <font> | ||
| 1010 | <pointsize>28</pointsize> | ||
| 1011 | </font> | ||
| 1012 | </property> | ||
| 1013 | <property name="text"> | ||
| 1014 | <string notr="true">t</string> | ||
| 1015 | </property> | ||
| 1016 | </widget> | ||
| 1017 | </item> | ||
| 1018 | <item row="2" column="9"> | ||
| 1019 | <widget class="QPushButton" name="button_o"> | ||
| 1020 | <property name="sizePolicy"> | ||
| 1021 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1022 | <horstretch>1</horstretch> | ||
| 1023 | <verstretch>1</verstretch> | ||
| 1024 | </sizepolicy> | ||
| 1025 | </property> | ||
| 1026 | <property name="font"> | ||
| 1027 | <font> | ||
| 1028 | <pointsize>28</pointsize> | ||
| 1029 | </font> | ||
| 1030 | </property> | ||
| 1031 | <property name="text"> | ||
| 1032 | <string notr="true">o</string> | ||
| 1033 | </property> | ||
| 1034 | </widget> | ||
| 1035 | </item> | ||
| 1036 | <item row="2" column="10"> | ||
| 1037 | <widget class="QPushButton" name="button_p"> | ||
| 1038 | <property name="sizePolicy"> | ||
| 1039 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1040 | <horstretch>1</horstretch> | ||
| 1041 | <verstretch>1</verstretch> | ||
| 1042 | </sizepolicy> | ||
| 1043 | </property> | ||
| 1044 | <property name="font"> | ||
| 1045 | <font> | ||
| 1046 | <pointsize>28</pointsize> | ||
| 1047 | </font> | ||
| 1048 | </property> | ||
| 1049 | <property name="text"> | ||
| 1050 | <string notr="true">p</string> | ||
| 1051 | </property> | ||
| 1052 | </widget> | ||
| 1053 | </item> | ||
| 1054 | <item row="2" column="8"> | ||
| 1055 | <widget class="QPushButton" name="button_i"> | ||
| 1056 | <property name="sizePolicy"> | ||
| 1057 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1058 | <horstretch>1</horstretch> | ||
| 1059 | <verstretch>1</verstretch> | ||
| 1060 | </sizepolicy> | ||
| 1061 | </property> | ||
| 1062 | <property name="font"> | ||
| 1063 | <font> | ||
| 1064 | <pointsize>28</pointsize> | ||
| 1065 | </font> | ||
| 1066 | </property> | ||
| 1067 | <property name="text"> | ||
| 1068 | <string notr="true">i</string> | ||
| 1069 | </property> | ||
| 1070 | </widget> | ||
| 1071 | </item> | ||
| 1072 | <item row="3" column="1"> | ||
| 1073 | <widget class="QPushButton" name="button_a"> | ||
| 1074 | <property name="sizePolicy"> | ||
| 1075 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1076 | <horstretch>1</horstretch> | ||
| 1077 | <verstretch>1</verstretch> | ||
| 1078 | </sizepolicy> | ||
| 1079 | </property> | ||
| 1080 | <property name="font"> | ||
| 1081 | <font> | ||
| 1082 | <pointsize>28</pointsize> | ||
| 1083 | </font> | ||
| 1084 | </property> | ||
| 1085 | <property name="text"> | ||
| 1086 | <string notr="true">a</string> | ||
| 1087 | </property> | ||
| 1088 | </widget> | ||
| 1089 | </item> | ||
| 1090 | <item row="3" column="2"> | ||
| 1091 | <widget class="QPushButton" name="button_s"> | ||
| 1092 | <property name="sizePolicy"> | ||
| 1093 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1094 | <horstretch>1</horstretch> | ||
| 1095 | <verstretch>1</verstretch> | ||
| 1096 | </sizepolicy> | ||
| 1097 | </property> | ||
| 1098 | <property name="font"> | ||
| 1099 | <font> | ||
| 1100 | <pointsize>28</pointsize> | ||
| 1101 | </font> | ||
| 1102 | </property> | ||
| 1103 | <property name="text"> | ||
| 1104 | <string notr="true">s</string> | ||
| 1105 | </property> | ||
| 1106 | </widget> | ||
| 1107 | </item> | ||
| 1108 | <item row="3" column="3"> | ||
| 1109 | <widget class="QPushButton" name="button_d"> | ||
| 1110 | <property name="sizePolicy"> | ||
| 1111 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1112 | <horstretch>1</horstretch> | ||
| 1113 | <verstretch>1</verstretch> | ||
| 1114 | </sizepolicy> | ||
| 1115 | </property> | ||
| 1116 | <property name="font"> | ||
| 1117 | <font> | ||
| 1118 | <pointsize>28</pointsize> | ||
| 1119 | </font> | ||
| 1120 | </property> | ||
| 1121 | <property name="text"> | ||
| 1122 | <string notr="true">d</string> | ||
| 1123 | </property> | ||
| 1124 | </widget> | ||
| 1125 | </item> | ||
| 1126 | <item row="3" column="4"> | ||
| 1127 | <widget class="QPushButton" name="button_f"> | ||
| 1128 | <property name="sizePolicy"> | ||
| 1129 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1130 | <horstretch>1</horstretch> | ||
| 1131 | <verstretch>1</verstretch> | ||
| 1132 | </sizepolicy> | ||
| 1133 | </property> | ||
| 1134 | <property name="font"> | ||
| 1135 | <font> | ||
| 1136 | <pointsize>28</pointsize> | ||
| 1137 | </font> | ||
| 1138 | </property> | ||
| 1139 | <property name="text"> | ||
| 1140 | <string notr="true">f</string> | ||
| 1141 | </property> | ||
| 1142 | </widget> | ||
| 1143 | </item> | ||
| 1144 | <item row="3" column="6"> | ||
| 1145 | <widget class="QPushButton" name="button_h"> | ||
| 1146 | <property name="sizePolicy"> | ||
| 1147 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1148 | <horstretch>1</horstretch> | ||
| 1149 | <verstretch>1</verstretch> | ||
| 1150 | </sizepolicy> | ||
| 1151 | </property> | ||
| 1152 | <property name="font"> | ||
| 1153 | <font> | ||
| 1154 | <pointsize>28</pointsize> | ||
| 1155 | </font> | ||
| 1156 | </property> | ||
| 1157 | <property name="text"> | ||
| 1158 | <string notr="true">h</string> | ||
| 1159 | </property> | ||
| 1160 | </widget> | ||
| 1161 | </item> | ||
| 1162 | <item row="3" column="7"> | ||
| 1163 | <widget class="QPushButton" name="button_j"> | ||
| 1164 | <property name="sizePolicy"> | ||
| 1165 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1166 | <horstretch>1</horstretch> | ||
| 1167 | <verstretch>1</verstretch> | ||
| 1168 | </sizepolicy> | ||
| 1169 | </property> | ||
| 1170 | <property name="font"> | ||
| 1171 | <font> | ||
| 1172 | <pointsize>28</pointsize> | ||
| 1173 | </font> | ||
| 1174 | </property> | ||
| 1175 | <property name="text"> | ||
| 1176 | <string notr="true">j</string> | ||
| 1177 | </property> | ||
| 1178 | </widget> | ||
| 1179 | </item> | ||
| 1180 | <item row="3" column="5"> | ||
| 1181 | <widget class="QPushButton" name="button_g"> | ||
| 1182 | <property name="sizePolicy"> | ||
| 1183 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1184 | <horstretch>1</horstretch> | ||
| 1185 | <verstretch>1</verstretch> | ||
| 1186 | </sizepolicy> | ||
| 1187 | </property> | ||
| 1188 | <property name="font"> | ||
| 1189 | <font> | ||
| 1190 | <pointsize>28</pointsize> | ||
| 1191 | </font> | ||
| 1192 | </property> | ||
| 1193 | <property name="text"> | ||
| 1194 | <string notr="true">g</string> | ||
| 1195 | </property> | ||
| 1196 | </widget> | ||
| 1197 | </item> | ||
| 1198 | <item row="3" column="8"> | ||
| 1199 | <widget class="QPushButton" name="button_k"> | ||
| 1200 | <property name="sizePolicy"> | ||
| 1201 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1202 | <horstretch>1</horstretch> | ||
| 1203 | <verstretch>1</verstretch> | ||
| 1204 | </sizepolicy> | ||
| 1205 | </property> | ||
| 1206 | <property name="font"> | ||
| 1207 | <font> | ||
| 1208 | <pointsize>28</pointsize> | ||
| 1209 | </font> | ||
| 1210 | </property> | ||
| 1211 | <property name="text"> | ||
| 1212 | <string notr="true">k</string> | ||
| 1213 | </property> | ||
| 1214 | </widget> | ||
| 1215 | </item> | ||
| 1216 | <item row="3" column="9"> | ||
| 1217 | <widget class="QPushButton" name="button_l"> | ||
| 1218 | <property name="sizePolicy"> | ||
| 1219 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1220 | <horstretch>1</horstretch> | ||
| 1221 | <verstretch>1</verstretch> | ||
| 1222 | </sizepolicy> | ||
| 1223 | </property> | ||
| 1224 | <property name="font"> | ||
| 1225 | <font> | ||
| 1226 | <pointsize>28</pointsize> | ||
| 1227 | </font> | ||
| 1228 | </property> | ||
| 1229 | <property name="text"> | ||
| 1230 | <string notr="true">l</string> | ||
| 1231 | </property> | ||
| 1232 | </widget> | ||
| 1233 | </item> | ||
| 1234 | <item row="3" column="10"> | ||
| 1235 | <widget class="QPushButton" name="button_colon"> | ||
| 1236 | <property name="sizePolicy"> | ||
| 1237 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1238 | <horstretch>1</horstretch> | ||
| 1239 | <verstretch>1</verstretch> | ||
| 1240 | </sizepolicy> | ||
| 1241 | </property> | ||
| 1242 | <property name="font"> | ||
| 1243 | <font> | ||
| 1244 | <pointsize>28</pointsize> | ||
| 1245 | </font> | ||
| 1246 | </property> | ||
| 1247 | <property name="text"> | ||
| 1248 | <string notr="true">:</string> | ||
| 1249 | </property> | ||
| 1250 | </widget> | ||
| 1251 | </item> | ||
| 1252 | <item row="2" column="12" rowspan="2"> | ||
| 1253 | <widget class="QPushButton" name="button_return"> | ||
| 1254 | <property name="sizePolicy"> | ||
| 1255 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1256 | <horstretch>1</horstretch> | ||
| 1257 | <verstretch>1</verstretch> | ||
| 1258 | </sizepolicy> | ||
| 1259 | </property> | ||
| 1260 | <property name="font"> | ||
| 1261 | <font> | ||
| 1262 | <pointsize>18</pointsize> | ||
| 1263 | </font> | ||
| 1264 | </property> | ||
| 1265 | <property name="text"> | ||
| 1266 | <string notr="true">Return</string> | ||
| 1267 | </property> | ||
| 1268 | </widget> | ||
| 1269 | </item> | ||
| 1270 | <item row="4" column="12" rowspan="2"> | ||
| 1271 | <widget class="QPushButton" name="button_ok"> | ||
| 1272 | <property name="sizePolicy"> | ||
| 1273 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1274 | <horstretch>1</horstretch> | ||
| 1275 | <verstretch>1</verstretch> | ||
| 1276 | </sizepolicy> | ||
| 1277 | </property> | ||
| 1278 | <property name="font"> | ||
| 1279 | <font> | ||
| 1280 | <pointsize>18</pointsize> | ||
| 1281 | </font> | ||
| 1282 | </property> | ||
| 1283 | <property name="text"> | ||
| 1284 | <string notr="true">OK</string> | ||
| 1285 | </property> | ||
| 1286 | </widget> | ||
| 1287 | </item> | ||
| 1288 | <item row="4" column="1"> | ||
| 1289 | <widget class="QPushButton" name="button_z"> | ||
| 1290 | <property name="sizePolicy"> | ||
| 1291 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1292 | <horstretch>1</horstretch> | ||
| 1293 | <verstretch>1</verstretch> | ||
| 1294 | </sizepolicy> | ||
| 1295 | </property> | ||
| 1296 | <property name="font"> | ||
| 1297 | <font> | ||
| 1298 | <pointsize>28</pointsize> | ||
| 1299 | </font> | ||
| 1300 | </property> | ||
| 1301 | <property name="text"> | ||
| 1302 | <string notr="true">z</string> | ||
| 1303 | </property> | ||
| 1304 | </widget> | ||
| 1305 | </item> | ||
| 1306 | <item row="4" column="3"> | ||
| 1307 | <widget class="QPushButton" name="button_c"> | ||
| 1308 | <property name="sizePolicy"> | ||
| 1309 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1310 | <horstretch>1</horstretch> | ||
| 1311 | <verstretch>1</verstretch> | ||
| 1312 | </sizepolicy> | ||
| 1313 | </property> | ||
| 1314 | <property name="font"> | ||
| 1315 | <font> | ||
| 1316 | <pointsize>28</pointsize> | ||
| 1317 | </font> | ||
| 1318 | </property> | ||
| 1319 | <property name="text"> | ||
| 1320 | <string notr="true">c</string> | ||
| 1321 | </property> | ||
| 1322 | </widget> | ||
| 1323 | </item> | ||
| 1324 | <item row="4" column="2"> | ||
| 1325 | <widget class="QPushButton" name="button_x"> | ||
| 1326 | <property name="sizePolicy"> | ||
| 1327 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1328 | <horstretch>1</horstretch> | ||
| 1329 | <verstretch>1</verstretch> | ||
| 1330 | </sizepolicy> | ||
| 1331 | </property> | ||
| 1332 | <property name="font"> | ||
| 1333 | <font> | ||
| 1334 | <pointsize>28</pointsize> | ||
| 1335 | </font> | ||
| 1336 | </property> | ||
| 1337 | <property name="text"> | ||
| 1338 | <string notr="true">x</string> | ||
| 1339 | </property> | ||
| 1340 | </widget> | ||
| 1341 | </item> | ||
| 1342 | <item row="4" column="4"> | ||
| 1343 | <widget class="QPushButton" name="button_v"> | ||
| 1344 | <property name="sizePolicy"> | ||
| 1345 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1346 | <horstretch>1</horstretch> | ||
| 1347 | <verstretch>1</verstretch> | ||
| 1348 | </sizepolicy> | ||
| 1349 | </property> | ||
| 1350 | <property name="font"> | ||
| 1351 | <font> | ||
| 1352 | <pointsize>28</pointsize> | ||
| 1353 | </font> | ||
| 1354 | </property> | ||
| 1355 | <property name="text"> | ||
| 1356 | <string notr="true">v</string> | ||
| 1357 | </property> | ||
| 1358 | </widget> | ||
| 1359 | </item> | ||
| 1360 | <item row="4" column="7"> | ||
| 1361 | <widget class="QPushButton" name="button_m"> | ||
| 1362 | <property name="sizePolicy"> | ||
| 1363 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1364 | <horstretch>1</horstretch> | ||
| 1365 | <verstretch>1</verstretch> | ||
| 1366 | </sizepolicy> | ||
| 1367 | </property> | ||
| 1368 | <property name="font"> | ||
| 1369 | <font> | ||
| 1370 | <pointsize>28</pointsize> | ||
| 1371 | </font> | ||
| 1372 | </property> | ||
| 1373 | <property name="text"> | ||
| 1374 | <string notr="true">m</string> | ||
| 1375 | </property> | ||
| 1376 | </widget> | ||
| 1377 | </item> | ||
| 1378 | <item row="4" column="8"> | ||
| 1379 | <widget class="QPushButton" name="button_comma"> | ||
| 1380 | <property name="sizePolicy"> | ||
| 1381 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1382 | <horstretch>1</horstretch> | ||
| 1383 | <verstretch>1</verstretch> | ||
| 1384 | </sizepolicy> | ||
| 1385 | </property> | ||
| 1386 | <property name="font"> | ||
| 1387 | <font> | ||
| 1388 | <pointsize>28</pointsize> | ||
| 1389 | </font> | ||
| 1390 | </property> | ||
| 1391 | <property name="text"> | ||
| 1392 | <string notr="true">,</string> | ||
| 1393 | </property> | ||
| 1394 | </widget> | ||
| 1395 | </item> | ||
| 1396 | <item row="4" column="6"> | ||
| 1397 | <widget class="QPushButton" name="button_n"> | ||
| 1398 | <property name="sizePolicy"> | ||
| 1399 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1400 | <horstretch>1</horstretch> | ||
| 1401 | <verstretch>1</verstretch> | ||
| 1402 | </sizepolicy> | ||
| 1403 | </property> | ||
| 1404 | <property name="font"> | ||
| 1405 | <font> | ||
| 1406 | <pointsize>28</pointsize> | ||
| 1407 | </font> | ||
| 1408 | </property> | ||
| 1409 | <property name="text"> | ||
| 1410 | <string notr="true">n</string> | ||
| 1411 | </property> | ||
| 1412 | </widget> | ||
| 1413 | </item> | ||
| 1414 | <item row="4" column="5"> | ||
| 1415 | <widget class="QPushButton" name="button_b"> | ||
| 1416 | <property name="sizePolicy"> | ||
| 1417 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1418 | <horstretch>1</horstretch> | ||
| 1419 | <verstretch>1</verstretch> | ||
| 1420 | </sizepolicy> | ||
| 1421 | </property> | ||
| 1422 | <property name="font"> | ||
| 1423 | <font> | ||
| 1424 | <pointsize>28</pointsize> | ||
| 1425 | </font> | ||
| 1426 | </property> | ||
| 1427 | <property name="text"> | ||
| 1428 | <string notr="true">b</string> | ||
| 1429 | </property> | ||
| 1430 | </widget> | ||
| 1431 | </item> | ||
| 1432 | <item row="5" column="1" colspan="2"> | ||
| 1433 | <widget class="QPushButton" name="button_shift"> | ||
| 1434 | <property name="sizePolicy"> | ||
| 1435 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1436 | <horstretch>1</horstretch> | ||
| 1437 | <verstretch>1</verstretch> | ||
| 1438 | </sizepolicy> | ||
| 1439 | </property> | ||
| 1440 | <property name="font"> | ||
| 1441 | <font> | ||
| 1442 | <pointsize>18</pointsize> | ||
| 1443 | </font> | ||
| 1444 | </property> | ||
| 1445 | <property name="text"> | ||
| 1446 | <string notr="true"/> | ||
| 1447 | </property> | ||
| 1448 | <property name="checkable"> | ||
| 1449 | <bool>true</bool> | ||
| 1450 | </property> | ||
| 1451 | <property name="checked"> | ||
| 1452 | <bool>false</bool> | ||
| 1453 | </property> | ||
| 1454 | </widget> | ||
| 1455 | </item> | ||
| 1456 | <item row="4" column="10"> | ||
| 1457 | <widget class="QPushButton" name="button_question"> | ||
| 1458 | <property name="sizePolicy"> | ||
| 1459 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1460 | <horstretch>1</horstretch> | ||
| 1461 | <verstretch>1</verstretch> | ||
| 1462 | </sizepolicy> | ||
| 1463 | </property> | ||
| 1464 | <property name="font"> | ||
| 1465 | <font> | ||
| 1466 | <pointsize>28</pointsize> | ||
| 1467 | </font> | ||
| 1468 | </property> | ||
| 1469 | <property name="text"> | ||
| 1470 | <string notr="true">?</string> | ||
| 1471 | </property> | ||
| 1472 | </widget> | ||
| 1473 | </item> | ||
| 1474 | <item row="4" column="9"> | ||
| 1475 | <widget class="QPushButton" name="button_dot"> | ||
| 1476 | <property name="sizePolicy"> | ||
| 1477 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1478 | <horstretch>1</horstretch> | ||
| 1479 | <verstretch>1</verstretch> | ||
| 1480 | </sizepolicy> | ||
| 1481 | </property> | ||
| 1482 | <property name="font"> | ||
| 1483 | <font> | ||
| 1484 | <pointsize>28</pointsize> | ||
| 1485 | </font> | ||
| 1486 | </property> | ||
| 1487 | <property name="text"> | ||
| 1488 | <string notr="true">.</string> | ||
| 1489 | </property> | ||
| 1490 | </widget> | ||
| 1491 | </item> | ||
| 1492 | <item row="1" column="1"> | ||
| 1493 | <widget class="QPushButton" name="button_1"> | ||
| 1494 | <property name="sizePolicy"> | ||
| 1495 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1496 | <horstretch>1</horstretch> | ||
| 1497 | <verstretch>1</verstretch> | ||
| 1498 | </sizepolicy> | ||
| 1499 | </property> | ||
| 1500 | <property name="font"> | ||
| 1501 | <font> | ||
| 1502 | <pointsize>28</pointsize> | ||
| 1503 | </font> | ||
| 1504 | </property> | ||
| 1505 | <property name="text"> | ||
| 1506 | <string notr="true">1</string> | ||
| 1507 | </property> | ||
| 1508 | </widget> | ||
| 1509 | </item> | ||
| 1510 | <item row="1" column="3"> | ||
| 1511 | <widget class="QPushButton" name="button_3"> | ||
| 1512 | <property name="sizePolicy"> | ||
| 1513 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1514 | <horstretch>1</horstretch> | ||
| 1515 | <verstretch>1</verstretch> | ||
| 1516 | </sizepolicy> | ||
| 1517 | </property> | ||
| 1518 | <property name="font"> | ||
| 1519 | <font> | ||
| 1520 | <pointsize>28</pointsize> | ||
| 1521 | </font> | ||
| 1522 | </property> | ||
| 1523 | <property name="text"> | ||
| 1524 | <string notr="true">3</string> | ||
| 1525 | </property> | ||
| 1526 | </widget> | ||
| 1527 | </item> | ||
| 1528 | <item row="1" column="4"> | ||
| 1529 | <widget class="QPushButton" name="button_4"> | ||
| 1530 | <property name="sizePolicy"> | ||
| 1531 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1532 | <horstretch>1</horstretch> | ||
| 1533 | <verstretch>1</verstretch> | ||
| 1534 | </sizepolicy> | ||
| 1535 | </property> | ||
| 1536 | <property name="font"> | ||
| 1537 | <font> | ||
| 1538 | <pointsize>28</pointsize> | ||
| 1539 | </font> | ||
| 1540 | </property> | ||
| 1541 | <property name="text"> | ||
| 1542 | <string notr="true">4</string> | ||
| 1543 | </property> | ||
| 1544 | </widget> | ||
| 1545 | </item> | ||
| 1546 | <item row="1" column="2"> | ||
| 1547 | <widget class="QPushButton" name="button_2"> | ||
| 1548 | <property name="sizePolicy"> | ||
| 1549 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1550 | <horstretch>1</horstretch> | ||
| 1551 | <verstretch>1</verstretch> | ||
| 1552 | </sizepolicy> | ||
| 1553 | </property> | ||
| 1554 | <property name="font"> | ||
| 1555 | <font> | ||
| 1556 | <pointsize>28</pointsize> | ||
| 1557 | </font> | ||
| 1558 | </property> | ||
| 1559 | <property name="text"> | ||
| 1560 | <string notr="true">2</string> | ||
| 1561 | </property> | ||
| 1562 | </widget> | ||
| 1563 | </item> | ||
| 1564 | <item row="1" column="6"> | ||
| 1565 | <widget class="QPushButton" name="button_6"> | ||
| 1566 | <property name="sizePolicy"> | ||
| 1567 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1568 | <horstretch>1</horstretch> | ||
| 1569 | <verstretch>1</verstretch> | ||
| 1570 | </sizepolicy> | ||
| 1571 | </property> | ||
| 1572 | <property name="font"> | ||
| 1573 | <font> | ||
| 1574 | <pointsize>28</pointsize> | ||
| 1575 | </font> | ||
| 1576 | </property> | ||
| 1577 | <property name="text"> | ||
| 1578 | <string notr="true">6</string> | ||
| 1579 | </property> | ||
| 1580 | </widget> | ||
| 1581 | </item> | ||
| 1582 | <item row="1" column="5"> | ||
| 1583 | <widget class="QPushButton" name="button_5"> | ||
| 1584 | <property name="sizePolicy"> | ||
| 1585 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1586 | <horstretch>1</horstretch> | ||
| 1587 | <verstretch>1</verstretch> | ||
| 1588 | </sizepolicy> | ||
| 1589 | </property> | ||
| 1590 | <property name="font"> | ||
| 1591 | <font> | ||
| 1592 | <pointsize>28</pointsize> | ||
| 1593 | </font> | ||
| 1594 | </property> | ||
| 1595 | <property name="text"> | ||
| 1596 | <string notr="true">5</string> | ||
| 1597 | </property> | ||
| 1598 | </widget> | ||
| 1599 | </item> | ||
| 1600 | <item row="5" column="3" colspan="9"> | ||
| 1601 | <widget class="QPushButton" name="button_space"> | ||
| 1602 | <property name="sizePolicy"> | ||
| 1603 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1604 | <horstretch>1</horstretch> | ||
| 1605 | <verstretch>1</verstretch> | ||
| 1606 | </sizepolicy> | ||
| 1607 | </property> | ||
| 1608 | <property name="font"> | ||
| 1609 | <font> | ||
| 1610 | <pointsize>18</pointsize> | ||
| 1611 | </font> | ||
| 1612 | </property> | ||
| 1613 | <property name="text"> | ||
| 1614 | <string notr="true">Space</string> | ||
| 1615 | </property> | ||
| 1616 | </widget> | ||
| 1617 | </item> | ||
| 1618 | <item row="1" column="12"> | ||
| 1619 | <widget class="QPushButton" name="button_backspace"> | ||
| 1620 | <property name="sizePolicy"> | ||
| 1621 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1622 | <horstretch>1</horstretch> | ||
| 1623 | <verstretch>1</verstretch> | ||
| 1624 | </sizepolicy> | ||
| 1625 | </property> | ||
| 1626 | <property name="font"> | ||
| 1627 | <font> | ||
| 1628 | <pointsize>18</pointsize> | ||
| 1629 | </font> | ||
| 1630 | </property> | ||
| 1631 | <property name="text"> | ||
| 1632 | <string notr="true"/> | ||
| 1633 | </property> | ||
| 1634 | </widget> | ||
| 1635 | </item> | ||
| 1636 | <item row="1" column="0"> | ||
| 1637 | <spacer name="horizontalSpacer"> | ||
| 1638 | <property name="orientation"> | ||
| 1639 | <enum>Qt::Horizontal</enum> | ||
| 1640 | </property> | ||
| 1641 | <property name="sizeHint" stdset="0"> | ||
| 1642 | <size> | ||
| 1643 | <width>40</width> | ||
| 1644 | <height>20</height> | ||
| 1645 | </size> | ||
| 1646 | </property> | ||
| 1647 | </spacer> | ||
| 1648 | </item> | ||
| 1649 | <item row="0" column="1"> | ||
| 1650 | <spacer name="verticalSpacer"> | ||
| 1651 | <property name="orientation"> | ||
| 1652 | <enum>Qt::Vertical</enum> | ||
| 1653 | </property> | ||
| 1654 | <property name="sizeHint" stdset="0"> | ||
| 1655 | <size> | ||
| 1656 | <width>20</width> | ||
| 1657 | <height>0</height> | ||
| 1658 | </size> | ||
| 1659 | </property> | ||
| 1660 | </spacer> | ||
| 1661 | </item> | ||
| 1662 | <item row="1" column="13"> | ||
| 1663 | <spacer name="horizontalSpacer_2"> | ||
| 1664 | <property name="orientation"> | ||
| 1665 | <enum>Qt::Horizontal</enum> | ||
| 1666 | </property> | ||
| 1667 | <property name="sizeHint" stdset="0"> | ||
| 1668 | <size> | ||
| 1669 | <width>40</width> | ||
| 1670 | <height>20</height> | ||
| 1671 | </size> | ||
| 1672 | </property> | ||
| 1673 | </spacer> | ||
| 1674 | </item> | ||
| 1675 | </layout> | ||
| 1676 | </item> | ||
| 1677 | </layout> | ||
| 1678 | </widget> | ||
| 1679 | <widget class="QWidget" name="shiftOSK"> | ||
| 1680 | <layout class="QVBoxLayout" name="shiftPageVerticalLayout"> | ||
| 1681 | <property name="leftMargin"> | ||
| 1682 | <number>0</number> | ||
| 1683 | </property> | ||
| 1684 | <property name="topMargin"> | ||
| 1685 | <number>0</number> | ||
| 1686 | </property> | ||
| 1687 | <property name="rightMargin"> | ||
| 1688 | <number>0</number> | ||
| 1689 | </property> | ||
| 1690 | <property name="bottomMargin"> | ||
| 1691 | <number>0</number> | ||
| 1692 | </property> | ||
| 1693 | <item> | ||
| 1694 | <layout class="QGridLayout" name="kbOSKshift" rowstretch="15,63,63,63,63,63,70" columnstretch="54,96,96,96,96,96,96,96,96,96,96,96,116,54"> | ||
| 1695 | <property name="spacing"> | ||
| 1696 | <number>0</number> | ||
| 1697 | </property> | ||
| 1698 | <item row="6" column="1" colspan="12"> | ||
| 1699 | <widget class="QWidget" name="legendOSKshift" native="true"> | ||
| 1700 | <layout class="QHBoxLayout" name="horizontalLayout_5" stretch="70,464,25,12,22,41,25,12,22,41,25,12,95,37,29,12,69,37,29,12,56,8"> | ||
| 1701 | <property name="spacing"> | ||
| 1702 | <number>0</number> | ||
| 1703 | </property> | ||
| 1704 | <property name="leftMargin"> | ||
| 1705 | <number>2</number> | ||
| 1706 | </property> | ||
| 1707 | <property name="topMargin"> | ||
| 1708 | <number>0</number> | ||
| 1709 | </property> | ||
| 1710 | <property name="rightMargin"> | ||
| 1711 | <number>0</number> | ||
| 1712 | </property> | ||
| 1713 | <property name="bottomMargin"> | ||
| 1714 | <number>0</number> | ||
| 1715 | </property> | ||
| 1716 | <item> | ||
| 1717 | <widget class="QWidget" name="icon_controller_shift" native="true"> | ||
| 1718 | <property name="styleSheet"> | ||
| 1719 | <string notr="true"/> | ||
| 1720 | </property> | ||
| 1721 | </widget> | ||
| 1722 | </item> | ||
| 1723 | <item> | ||
| 1724 | <spacer name="horizontalSpacer_22"> | ||
| 1725 | <property name="orientation"> | ||
| 1726 | <enum>Qt::Horizontal</enum> | ||
| 1727 | </property> | ||
| 1728 | <property name="sizeHint" stdset="0"> | ||
| 1729 | <size> | ||
| 1730 | <width>0</width> | ||
| 1731 | <height>20</height> | ||
| 1732 | </size> | ||
| 1733 | </property> | ||
| 1734 | </spacer> | ||
| 1735 | </item> | ||
| 1736 | <item> | ||
| 1737 | <widget class="QWidget" name="button_L_shift" native="true"/> | ||
| 1738 | </item> | ||
| 1739 | <item> | ||
| 1740 | <spacer name="horizontalSpacer_23"> | ||
| 1741 | <property name="orientation"> | ||
| 1742 | <enum>Qt::Horizontal</enum> | ||
| 1743 | </property> | ||
| 1744 | <property name="sizeHint" stdset="0"> | ||
| 1745 | <size> | ||
| 1746 | <width>0</width> | ||
| 1747 | <height>20</height> | ||
| 1748 | </size> | ||
| 1749 | </property> | ||
| 1750 | </spacer> | ||
| 1751 | </item> | ||
| 1752 | <item> | ||
| 1753 | <widget class="QWidget" name="arrow_left_shift" native="true"/> | ||
| 1754 | </item> | ||
| 1755 | <item> | ||
| 1756 | <spacer name="horizontalSpacer_24"> | ||
| 1757 | <property name="orientation"> | ||
| 1758 | <enum>Qt::Horizontal</enum> | ||
| 1759 | </property> | ||
| 1760 | <property name="sizeHint" stdset="0"> | ||
| 1761 | <size> | ||
| 1762 | <width>0</width> | ||
| 1763 | <height>20</height> | ||
| 1764 | </size> | ||
| 1765 | </property> | ||
| 1766 | </spacer> | ||
| 1767 | </item> | ||
| 1768 | <item> | ||
| 1769 | <widget class="QWidget" name="button_R_shift" native="true"/> | ||
| 1770 | </item> | ||
| 1771 | <item> | ||
| 1772 | <spacer name="horizontalSpacer_25"> | ||
| 1773 | <property name="orientation"> | ||
| 1774 | <enum>Qt::Horizontal</enum> | ||
| 1775 | </property> | ||
| 1776 | <property name="sizeHint" stdset="0"> | ||
| 1777 | <size> | ||
| 1778 | <width>0</width> | ||
| 1779 | <height>20</height> | ||
| 1780 | </size> | ||
| 1781 | </property> | ||
| 1782 | </spacer> | ||
| 1783 | </item> | ||
| 1784 | <item> | ||
| 1785 | <widget class="QWidget" name="arrow_right_shift" native="true"/> | ||
| 1786 | </item> | ||
| 1787 | <item> | ||
| 1788 | <spacer name="horizontalSpacer_26"> | ||
| 1789 | <property name="orientation"> | ||
| 1790 | <enum>Qt::Horizontal</enum> | ||
| 1791 | </property> | ||
| 1792 | <property name="sizeHint" stdset="0"> | ||
| 1793 | <size> | ||
| 1794 | <width>0</width> | ||
| 1795 | <height>20</height> | ||
| 1796 | </size> | ||
| 1797 | </property> | ||
| 1798 | </spacer> | ||
| 1799 | </item> | ||
| 1800 | <item> | ||
| 1801 | <widget class="QWidget" name="button_press_stick_shift" native="true"/> | ||
| 1802 | </item> | ||
| 1803 | <item> | ||
| 1804 | <spacer name="horizontalSpacer_27"> | ||
| 1805 | <property name="orientation"> | ||
| 1806 | <enum>Qt::Horizontal</enum> | ||
| 1807 | </property> | ||
| 1808 | <property name="sizeHint" stdset="0"> | ||
| 1809 | <size> | ||
| 1810 | <width>0</width> | ||
| 1811 | <height>20</height> | ||
| 1812 | </size> | ||
| 1813 | </property> | ||
| 1814 | </spacer> | ||
| 1815 | </item> | ||
| 1816 | <item> | ||
| 1817 | <widget class="QLabel" name="label_shift_shift"> | ||
| 1818 | <property name="font"> | ||
| 1819 | <font> | ||
| 1820 | <pointsize>18</pointsize> | ||
| 1821 | </font> | ||
| 1822 | </property> | ||
| 1823 | <property name="text"> | ||
| 1824 | <string notr="true">Caps Lock</string> | ||
| 1825 | </property> | ||
| 1826 | </widget> | ||
| 1827 | </item> | ||
| 1828 | <item> | ||
| 1829 | <spacer name="horizontalSpacer_28"> | ||
| 1830 | <property name="orientation"> | ||
| 1831 | <enum>Qt::Horizontal</enum> | ||
| 1832 | </property> | ||
| 1833 | <property name="sizeHint" stdset="0"> | ||
| 1834 | <size> | ||
| 1835 | <width>0</width> | ||
| 1836 | <height>20</height> | ||
| 1837 | </size> | ||
| 1838 | </property> | ||
| 1839 | </spacer> | ||
| 1840 | </item> | ||
| 1841 | <item> | ||
| 1842 | <widget class="QWidget" name="button_X_shift" native="true"/> | ||
| 1843 | </item> | ||
| 1844 | <item> | ||
| 1845 | <spacer name="horizontalSpacer_29"> | ||
| 1846 | <property name="orientation"> | ||
| 1847 | <enum>Qt::Horizontal</enum> | ||
| 1848 | </property> | ||
| 1849 | <property name="sizeHint" stdset="0"> | ||
| 1850 | <size> | ||
| 1851 | <width>0</width> | ||
| 1852 | <height>20</height> | ||
| 1853 | </size> | ||
| 1854 | </property> | ||
| 1855 | </spacer> | ||
| 1856 | </item> | ||
| 1857 | <item> | ||
| 1858 | <widget class="QLabel" name="label_cancel_shift"> | ||
| 1859 | <property name="font"> | ||
| 1860 | <font> | ||
| 1861 | <pointsize>18</pointsize> | ||
| 1862 | </font> | ||
| 1863 | </property> | ||
| 1864 | <property name="text"> | ||
| 1865 | <string notr="true">Cancel</string> | ||
| 1866 | </property> | ||
| 1867 | </widget> | ||
| 1868 | </item> | ||
| 1869 | <item> | ||
| 1870 | <spacer name="horizontalSpacer_30"> | ||
| 1871 | <property name="orientation"> | ||
| 1872 | <enum>Qt::Horizontal</enum> | ||
| 1873 | </property> | ||
| 1874 | <property name="sizeHint" stdset="0"> | ||
| 1875 | <size> | ||
| 1876 | <width>0</width> | ||
| 1877 | <height>20</height> | ||
| 1878 | </size> | ||
| 1879 | </property> | ||
| 1880 | </spacer> | ||
| 1881 | </item> | ||
| 1882 | <item> | ||
| 1883 | <widget class="QWidget" name="button_A_shift" native="true"/> | ||
| 1884 | </item> | ||
| 1885 | <item> | ||
| 1886 | <spacer name="horizontalSpacer_31"> | ||
| 1887 | <property name="orientation"> | ||
| 1888 | <enum>Qt::Horizontal</enum> | ||
| 1889 | </property> | ||
| 1890 | <property name="sizeHint" stdset="0"> | ||
| 1891 | <size> | ||
| 1892 | <width>0</width> | ||
| 1893 | <height>20</height> | ||
| 1894 | </size> | ||
| 1895 | </property> | ||
| 1896 | </spacer> | ||
| 1897 | </item> | ||
| 1898 | <item> | ||
| 1899 | <widget class="QLabel" name="label_enter_shift"> | ||
| 1900 | <property name="font"> | ||
| 1901 | <font> | ||
| 1902 | <pointsize>18</pointsize> | ||
| 1903 | </font> | ||
| 1904 | </property> | ||
| 1905 | <property name="text"> | ||
| 1906 | <string notr="true">Enter</string> | ||
| 1907 | </property> | ||
| 1908 | </widget> | ||
| 1909 | </item> | ||
| 1910 | <item> | ||
| 1911 | <spacer name="horizontalSpacer_32"> | ||
| 1912 | <property name="orientation"> | ||
| 1913 | <enum>Qt::Horizontal</enum> | ||
| 1914 | </property> | ||
| 1915 | <property name="sizeHint" stdset="0"> | ||
| 1916 | <size> | ||
| 1917 | <width>0</width> | ||
| 1918 | <height>20</height> | ||
| 1919 | </size> | ||
| 1920 | </property> | ||
| 1921 | </spacer> | ||
| 1922 | </item> | ||
| 1923 | </layout> | ||
| 1924 | </widget> | ||
| 1925 | </item> | ||
| 1926 | <item row="1" column="11"> | ||
| 1927 | <widget class="QPushButton" name="button_underscore"> | ||
| 1928 | <property name="sizePolicy"> | ||
| 1929 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1930 | <horstretch>1</horstretch> | ||
| 1931 | <verstretch>1</verstretch> | ||
| 1932 | </sizepolicy> | ||
| 1933 | </property> | ||
| 1934 | <property name="font"> | ||
| 1935 | <font> | ||
| 1936 | <pointsize>28</pointsize> | ||
| 1937 | </font> | ||
| 1938 | </property> | ||
| 1939 | <property name="text"> | ||
| 1940 | <string notr="true">_</string> | ||
| 1941 | </property> | ||
| 1942 | </widget> | ||
| 1943 | </item> | ||
| 1944 | <item row="3" column="11"> | ||
| 1945 | <widget class="QPushButton" name="button_quotation"> | ||
| 1946 | <property name="sizePolicy"> | ||
| 1947 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1948 | <horstretch>1</horstretch> | ||
| 1949 | <verstretch>1</verstretch> | ||
| 1950 | </sizepolicy> | ||
| 1951 | </property> | ||
| 1952 | <property name="font"> | ||
| 1953 | <font> | ||
| 1954 | <pointsize>28</pointsize> | ||
| 1955 | </font> | ||
| 1956 | </property> | ||
| 1957 | <property name="text"> | ||
| 1958 | <string notr="true">"</string> | ||
| 1959 | </property> | ||
| 1960 | </widget> | ||
| 1961 | </item> | ||
| 1962 | <item row="2" column="11"> | ||
| 1963 | <widget class="QPushButton" name="button_at"> | ||
| 1964 | <property name="sizePolicy"> | ||
| 1965 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1966 | <horstretch>1</horstretch> | ||
| 1967 | <verstretch>1</verstretch> | ||
| 1968 | </sizepolicy> | ||
| 1969 | </property> | ||
| 1970 | <property name="font"> | ||
| 1971 | <font> | ||
| 1972 | <pointsize>28</pointsize> | ||
| 1973 | </font> | ||
| 1974 | </property> | ||
| 1975 | <property name="text"> | ||
| 1976 | <string notr="true">@</string> | ||
| 1977 | </property> | ||
| 1978 | </widget> | ||
| 1979 | </item> | ||
| 1980 | <item row="4" column="11"> | ||
| 1981 | <widget class="QPushButton" name="button_equal"> | ||
| 1982 | <property name="sizePolicy"> | ||
| 1983 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 1984 | <horstretch>1</horstretch> | ||
| 1985 | <verstretch>1</verstretch> | ||
| 1986 | </sizepolicy> | ||
| 1987 | </property> | ||
| 1988 | <property name="font"> | ||
| 1989 | <font> | ||
| 1990 | <pointsize>28</pointsize> | ||
| 1991 | </font> | ||
| 1992 | </property> | ||
| 1993 | <property name="text"> | ||
| 1994 | <string notr="true">=</string> | ||
| 1995 | </property> | ||
| 1996 | </widget> | ||
| 1997 | </item> | ||
| 1998 | <item row="1" column="7"> | ||
| 1999 | <widget class="QPushButton" name="button_ampersand"> | ||
| 2000 | <property name="sizePolicy"> | ||
| 2001 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2002 | <horstretch>1</horstretch> | ||
| 2003 | <verstretch>1</verstretch> | ||
| 2004 | </sizepolicy> | ||
| 2005 | </property> | ||
| 2006 | <property name="font"> | ||
| 2007 | <font> | ||
| 2008 | <pointsize>28</pointsize> | ||
| 2009 | </font> | ||
| 2010 | </property> | ||
| 2011 | <property name="text"> | ||
| 2012 | <string notr="true">&&</string> | ||
| 2013 | </property> | ||
| 2014 | </widget> | ||
| 2015 | </item> | ||
| 2016 | <item row="1" column="8"> | ||
| 2017 | <widget class="QPushButton" name="button_asterisk"> | ||
| 2018 | <property name="sizePolicy"> | ||
| 2019 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2020 | <horstretch>1</horstretch> | ||
| 2021 | <verstretch>1</verstretch> | ||
| 2022 | </sizepolicy> | ||
| 2023 | </property> | ||
| 2024 | <property name="font"> | ||
| 2025 | <font> | ||
| 2026 | <pointsize>28</pointsize> | ||
| 2027 | </font> | ||
| 2028 | </property> | ||
| 2029 | <property name="text"> | ||
| 2030 | <string notr="true">*</string> | ||
| 2031 | </property> | ||
| 2032 | </widget> | ||
| 2033 | </item> | ||
| 2034 | <item row="1" column="10"> | ||
| 2035 | <widget class="QPushButton" name="button_right_parenthesis"> | ||
| 2036 | <property name="sizePolicy"> | ||
| 2037 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2038 | <horstretch>1</horstretch> | ||
| 2039 | <verstretch>1</verstretch> | ||
| 2040 | </sizepolicy> | ||
| 2041 | </property> | ||
| 2042 | <property name="font"> | ||
| 2043 | <font> | ||
| 2044 | <pointsize>28</pointsize> | ||
| 2045 | </font> | ||
| 2046 | </property> | ||
| 2047 | <property name="text"> | ||
| 2048 | <string notr="true">)</string> | ||
| 2049 | </property> | ||
| 2050 | </widget> | ||
| 2051 | </item> | ||
| 2052 | <item row="1" column="9"> | ||
| 2053 | <widget class="QPushButton" name="button_left_parenthesis"> | ||
| 2054 | <property name="sizePolicy"> | ||
| 2055 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2056 | <horstretch>1</horstretch> | ||
| 2057 | <verstretch>1</verstretch> | ||
| 2058 | </sizepolicy> | ||
| 2059 | </property> | ||
| 2060 | <property name="font"> | ||
| 2061 | <font> | ||
| 2062 | <pointsize>28</pointsize> | ||
| 2063 | </font> | ||
| 2064 | </property> | ||
| 2065 | <property name="text"> | ||
| 2066 | <string notr="true">(</string> | ||
| 2067 | </property> | ||
| 2068 | </widget> | ||
| 2069 | </item> | ||
| 2070 | <item row="2" column="2"> | ||
| 2071 | <widget class="QPushButton" name="button_w_shift"> | ||
| 2072 | <property name="sizePolicy"> | ||
| 2073 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2074 | <horstretch>1</horstretch> | ||
| 2075 | <verstretch>1</verstretch> | ||
| 2076 | </sizepolicy> | ||
| 2077 | </property> | ||
| 2078 | <property name="font"> | ||
| 2079 | <font> | ||
| 2080 | <pointsize>28</pointsize> | ||
| 2081 | </font> | ||
| 2082 | </property> | ||
| 2083 | <property name="text"> | ||
| 2084 | <string notr="true">W</string> | ||
| 2085 | </property> | ||
| 2086 | </widget> | ||
| 2087 | </item> | ||
| 2088 | <item row="2" column="4"> | ||
| 2089 | <widget class="QPushButton" name="button_r_shift"> | ||
| 2090 | <property name="sizePolicy"> | ||
| 2091 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2092 | <horstretch>1</horstretch> | ||
| 2093 | <verstretch>1</verstretch> | ||
| 2094 | </sizepolicy> | ||
| 2095 | </property> | ||
| 2096 | <property name="font"> | ||
| 2097 | <font> | ||
| 2098 | <pointsize>28</pointsize> | ||
| 2099 | </font> | ||
| 2100 | </property> | ||
| 2101 | <property name="text"> | ||
| 2102 | <string notr="true">R</string> | ||
| 2103 | </property> | ||
| 2104 | </widget> | ||
| 2105 | </item> | ||
| 2106 | <item row="2" column="3"> | ||
| 2107 | <widget class="QPushButton" name="button_e_shift"> | ||
| 2108 | <property name="sizePolicy"> | ||
| 2109 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2110 | <horstretch>1</horstretch> | ||
| 2111 | <verstretch>1</verstretch> | ||
| 2112 | </sizepolicy> | ||
| 2113 | </property> | ||
| 2114 | <property name="font"> | ||
| 2115 | <font> | ||
| 2116 | <pointsize>28</pointsize> | ||
| 2117 | </font> | ||
| 2118 | </property> | ||
| 2119 | <property name="text"> | ||
| 2120 | <string notr="true">E</string> | ||
| 2121 | </property> | ||
| 2122 | </widget> | ||
| 2123 | </item> | ||
| 2124 | <item row="2" column="1"> | ||
| 2125 | <widget class="QPushButton" name="button_q_shift"> | ||
| 2126 | <property name="sizePolicy"> | ||
| 2127 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2128 | <horstretch>1</horstretch> | ||
| 2129 | <verstretch>1</verstretch> | ||
| 2130 | </sizepolicy> | ||
| 2131 | </property> | ||
| 2132 | <property name="font"> | ||
| 2133 | <font> | ||
| 2134 | <pointsize>28</pointsize> | ||
| 2135 | </font> | ||
| 2136 | </property> | ||
| 2137 | <property name="text"> | ||
| 2138 | <string notr="true">Q</string> | ||
| 2139 | </property> | ||
| 2140 | </widget> | ||
| 2141 | </item> | ||
| 2142 | <item row="2" column="7"> | ||
| 2143 | <widget class="QPushButton" name="button_u_shift"> | ||
| 2144 | <property name="sizePolicy"> | ||
| 2145 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2146 | <horstretch>1</horstretch> | ||
| 2147 | <verstretch>1</verstretch> | ||
| 2148 | </sizepolicy> | ||
| 2149 | </property> | ||
| 2150 | <property name="font"> | ||
| 2151 | <font> | ||
| 2152 | <pointsize>28</pointsize> | ||
| 2153 | </font> | ||
| 2154 | </property> | ||
| 2155 | <property name="text"> | ||
| 2156 | <string notr="true">U</string> | ||
| 2157 | </property> | ||
| 2158 | </widget> | ||
| 2159 | </item> | ||
| 2160 | <item row="2" column="6"> | ||
| 2161 | <widget class="QPushButton" name="button_y_shift"> | ||
| 2162 | <property name="sizePolicy"> | ||
| 2163 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2164 | <horstretch>1</horstretch> | ||
| 2165 | <verstretch>1</verstretch> | ||
| 2166 | </sizepolicy> | ||
| 2167 | </property> | ||
| 2168 | <property name="font"> | ||
| 2169 | <font> | ||
| 2170 | <pointsize>28</pointsize> | ||
| 2171 | </font> | ||
| 2172 | </property> | ||
| 2173 | <property name="text"> | ||
| 2174 | <string notr="true">Y</string> | ||
| 2175 | </property> | ||
| 2176 | </widget> | ||
| 2177 | </item> | ||
| 2178 | <item row="2" column="5"> | ||
| 2179 | <widget class="QPushButton" name="button_t_shift"> | ||
| 2180 | <property name="sizePolicy"> | ||
| 2181 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2182 | <horstretch>1</horstretch> | ||
| 2183 | <verstretch>1</verstretch> | ||
| 2184 | </sizepolicy> | ||
| 2185 | </property> | ||
| 2186 | <property name="font"> | ||
| 2187 | <font> | ||
| 2188 | <pointsize>28</pointsize> | ||
| 2189 | </font> | ||
| 2190 | </property> | ||
| 2191 | <property name="text"> | ||
| 2192 | <string notr="true">T</string> | ||
| 2193 | </property> | ||
| 2194 | </widget> | ||
| 2195 | </item> | ||
| 2196 | <item row="2" column="9"> | ||
| 2197 | <widget class="QPushButton" name="button_o_shift"> | ||
| 2198 | <property name="sizePolicy"> | ||
| 2199 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2200 | <horstretch>1</horstretch> | ||
| 2201 | <verstretch>1</verstretch> | ||
| 2202 | </sizepolicy> | ||
| 2203 | </property> | ||
| 2204 | <property name="font"> | ||
| 2205 | <font> | ||
| 2206 | <pointsize>28</pointsize> | ||
| 2207 | </font> | ||
| 2208 | </property> | ||
| 2209 | <property name="text"> | ||
| 2210 | <string notr="true">O</string> | ||
| 2211 | </property> | ||
| 2212 | </widget> | ||
| 2213 | </item> | ||
| 2214 | <item row="2" column="10"> | ||
| 2215 | <widget class="QPushButton" name="button_p_shift"> | ||
| 2216 | <property name="sizePolicy"> | ||
| 2217 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2218 | <horstretch>1</horstretch> | ||
| 2219 | <verstretch>1</verstretch> | ||
| 2220 | </sizepolicy> | ||
| 2221 | </property> | ||
| 2222 | <property name="font"> | ||
| 2223 | <font> | ||
| 2224 | <pointsize>28</pointsize> | ||
| 2225 | </font> | ||
| 2226 | </property> | ||
| 2227 | <property name="text"> | ||
| 2228 | <string notr="true">P</string> | ||
| 2229 | </property> | ||
| 2230 | </widget> | ||
| 2231 | </item> | ||
| 2232 | <item row="2" column="8"> | ||
| 2233 | <widget class="QPushButton" name="button_i_shift"> | ||
| 2234 | <property name="sizePolicy"> | ||
| 2235 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2236 | <horstretch>1</horstretch> | ||
| 2237 | <verstretch>1</verstretch> | ||
| 2238 | </sizepolicy> | ||
| 2239 | </property> | ||
| 2240 | <property name="font"> | ||
| 2241 | <font> | ||
| 2242 | <pointsize>28</pointsize> | ||
| 2243 | </font> | ||
| 2244 | </property> | ||
| 2245 | <property name="text"> | ||
| 2246 | <string notr="true">I</string> | ||
| 2247 | </property> | ||
| 2248 | </widget> | ||
| 2249 | </item> | ||
| 2250 | <item row="3" column="1"> | ||
| 2251 | <widget class="QPushButton" name="button_a_shift"> | ||
| 2252 | <property name="sizePolicy"> | ||
| 2253 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2254 | <horstretch>1</horstretch> | ||
| 2255 | <verstretch>1</verstretch> | ||
| 2256 | </sizepolicy> | ||
| 2257 | </property> | ||
| 2258 | <property name="font"> | ||
| 2259 | <font> | ||
| 2260 | <pointsize>28</pointsize> | ||
| 2261 | </font> | ||
| 2262 | </property> | ||
| 2263 | <property name="text"> | ||
| 2264 | <string notr="true">A</string> | ||
| 2265 | </property> | ||
| 2266 | </widget> | ||
| 2267 | </item> | ||
| 2268 | <item row="3" column="2"> | ||
| 2269 | <widget class="QPushButton" name="button_s_shift"> | ||
| 2270 | <property name="sizePolicy"> | ||
| 2271 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2272 | <horstretch>1</horstretch> | ||
| 2273 | <verstretch>1</verstretch> | ||
| 2274 | </sizepolicy> | ||
| 2275 | </property> | ||
| 2276 | <property name="font"> | ||
| 2277 | <font> | ||
| 2278 | <pointsize>28</pointsize> | ||
| 2279 | </font> | ||
| 2280 | </property> | ||
| 2281 | <property name="text"> | ||
| 2282 | <string notr="true">S</string> | ||
| 2283 | </property> | ||
| 2284 | </widget> | ||
| 2285 | </item> | ||
| 2286 | <item row="3" column="3"> | ||
| 2287 | <widget class="QPushButton" name="button_d_shift"> | ||
| 2288 | <property name="sizePolicy"> | ||
| 2289 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2290 | <horstretch>1</horstretch> | ||
| 2291 | <verstretch>1</verstretch> | ||
| 2292 | </sizepolicy> | ||
| 2293 | </property> | ||
| 2294 | <property name="font"> | ||
| 2295 | <font> | ||
| 2296 | <pointsize>28</pointsize> | ||
| 2297 | </font> | ||
| 2298 | </property> | ||
| 2299 | <property name="text"> | ||
| 2300 | <string notr="true">D</string> | ||
| 2301 | </property> | ||
| 2302 | </widget> | ||
| 2303 | </item> | ||
| 2304 | <item row="3" column="4"> | ||
| 2305 | <widget class="QPushButton" name="button_f_shift"> | ||
| 2306 | <property name="sizePolicy"> | ||
| 2307 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2308 | <horstretch>1</horstretch> | ||
| 2309 | <verstretch>1</verstretch> | ||
| 2310 | </sizepolicy> | ||
| 2311 | </property> | ||
| 2312 | <property name="font"> | ||
| 2313 | <font> | ||
| 2314 | <pointsize>28</pointsize> | ||
| 2315 | </font> | ||
| 2316 | </property> | ||
| 2317 | <property name="text"> | ||
| 2318 | <string notr="true">F</string> | ||
| 2319 | </property> | ||
| 2320 | </widget> | ||
| 2321 | </item> | ||
| 2322 | <item row="3" column="6"> | ||
| 2323 | <widget class="QPushButton" name="button_h_shift"> | ||
| 2324 | <property name="sizePolicy"> | ||
| 2325 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2326 | <horstretch>1</horstretch> | ||
| 2327 | <verstretch>1</verstretch> | ||
| 2328 | </sizepolicy> | ||
| 2329 | </property> | ||
| 2330 | <property name="font"> | ||
| 2331 | <font> | ||
| 2332 | <pointsize>28</pointsize> | ||
| 2333 | </font> | ||
| 2334 | </property> | ||
| 2335 | <property name="text"> | ||
| 2336 | <string notr="true">H</string> | ||
| 2337 | </property> | ||
| 2338 | </widget> | ||
| 2339 | </item> | ||
| 2340 | <item row="3" column="7"> | ||
| 2341 | <widget class="QPushButton" name="button_j_shift"> | ||
| 2342 | <property name="sizePolicy"> | ||
| 2343 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2344 | <horstretch>1</horstretch> | ||
| 2345 | <verstretch>1</verstretch> | ||
| 2346 | </sizepolicy> | ||
| 2347 | </property> | ||
| 2348 | <property name="font"> | ||
| 2349 | <font> | ||
| 2350 | <pointsize>28</pointsize> | ||
| 2351 | </font> | ||
| 2352 | </property> | ||
| 2353 | <property name="text"> | ||
| 2354 | <string notr="true">J</string> | ||
| 2355 | </property> | ||
| 2356 | </widget> | ||
| 2357 | </item> | ||
| 2358 | <item row="3" column="5"> | ||
| 2359 | <widget class="QPushButton" name="button_g_shift"> | ||
| 2360 | <property name="sizePolicy"> | ||
| 2361 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2362 | <horstretch>1</horstretch> | ||
| 2363 | <verstretch>1</verstretch> | ||
| 2364 | </sizepolicy> | ||
| 2365 | </property> | ||
| 2366 | <property name="font"> | ||
| 2367 | <font> | ||
| 2368 | <pointsize>28</pointsize> | ||
| 2369 | </font> | ||
| 2370 | </property> | ||
| 2371 | <property name="text"> | ||
| 2372 | <string notr="true">G</string> | ||
| 2373 | </property> | ||
| 2374 | </widget> | ||
| 2375 | </item> | ||
| 2376 | <item row="3" column="8"> | ||
| 2377 | <widget class="QPushButton" name="button_k_shift"> | ||
| 2378 | <property name="sizePolicy"> | ||
| 2379 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2380 | <horstretch>1</horstretch> | ||
| 2381 | <verstretch>1</verstretch> | ||
| 2382 | </sizepolicy> | ||
| 2383 | </property> | ||
| 2384 | <property name="font"> | ||
| 2385 | <font> | ||
| 2386 | <pointsize>28</pointsize> | ||
| 2387 | </font> | ||
| 2388 | </property> | ||
| 2389 | <property name="text"> | ||
| 2390 | <string notr="true">K</string> | ||
| 2391 | </property> | ||
| 2392 | </widget> | ||
| 2393 | </item> | ||
| 2394 | <item row="3" column="9"> | ||
| 2395 | <widget class="QPushButton" name="button_l_shift"> | ||
| 2396 | <property name="sizePolicy"> | ||
| 2397 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2398 | <horstretch>1</horstretch> | ||
| 2399 | <verstretch>1</verstretch> | ||
| 2400 | </sizepolicy> | ||
| 2401 | </property> | ||
| 2402 | <property name="font"> | ||
| 2403 | <font> | ||
| 2404 | <pointsize>28</pointsize> | ||
| 2405 | </font> | ||
| 2406 | </property> | ||
| 2407 | <property name="text"> | ||
| 2408 | <string notr="true">L</string> | ||
| 2409 | </property> | ||
| 2410 | </widget> | ||
| 2411 | </item> | ||
| 2412 | <item row="3" column="10"> | ||
| 2413 | <widget class="QPushButton" name="button_semicolon"> | ||
| 2414 | <property name="sizePolicy"> | ||
| 2415 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2416 | <horstretch>1</horstretch> | ||
| 2417 | <verstretch>1</verstretch> | ||
| 2418 | </sizepolicy> | ||
| 2419 | </property> | ||
| 2420 | <property name="font"> | ||
| 2421 | <font> | ||
| 2422 | <pointsize>28</pointsize> | ||
| 2423 | </font> | ||
| 2424 | </property> | ||
| 2425 | <property name="text"> | ||
| 2426 | <string notr="true">;</string> | ||
| 2427 | </property> | ||
| 2428 | </widget> | ||
| 2429 | </item> | ||
| 2430 | <item row="2" column="12" rowspan="2"> | ||
| 2431 | <widget class="QPushButton" name="button_return_shift"> | ||
| 2432 | <property name="sizePolicy"> | ||
| 2433 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2434 | <horstretch>1</horstretch> | ||
| 2435 | <verstretch>1</verstretch> | ||
| 2436 | </sizepolicy> | ||
| 2437 | </property> | ||
| 2438 | <property name="font"> | ||
| 2439 | <font> | ||
| 2440 | <pointsize>18</pointsize> | ||
| 2441 | </font> | ||
| 2442 | </property> | ||
| 2443 | <property name="text"> | ||
| 2444 | <string notr="true">Return</string> | ||
| 2445 | </property> | ||
| 2446 | </widget> | ||
| 2447 | </item> | ||
| 2448 | <item row="4" column="12" rowspan="2"> | ||
| 2449 | <widget class="QPushButton" name="button_ok_shift"> | ||
| 2450 | <property name="sizePolicy"> | ||
| 2451 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2452 | <horstretch>1</horstretch> | ||
| 2453 | <verstretch>1</verstretch> | ||
| 2454 | </sizepolicy> | ||
| 2455 | </property> | ||
| 2456 | <property name="font"> | ||
| 2457 | <font> | ||
| 2458 | <pointsize>18</pointsize> | ||
| 2459 | </font> | ||
| 2460 | </property> | ||
| 2461 | <property name="text"> | ||
| 2462 | <string notr="true">OK</string> | ||
| 2463 | </property> | ||
| 2464 | </widget> | ||
| 2465 | </item> | ||
| 2466 | <item row="4" column="1"> | ||
| 2467 | <widget class="QPushButton" name="button_z_shift"> | ||
| 2468 | <property name="sizePolicy"> | ||
| 2469 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2470 | <horstretch>1</horstretch> | ||
| 2471 | <verstretch>1</verstretch> | ||
| 2472 | </sizepolicy> | ||
| 2473 | </property> | ||
| 2474 | <property name="font"> | ||
| 2475 | <font> | ||
| 2476 | <pointsize>28</pointsize> | ||
| 2477 | </font> | ||
| 2478 | </property> | ||
| 2479 | <property name="text"> | ||
| 2480 | <string notr="true">Z</string> | ||
| 2481 | </property> | ||
| 2482 | </widget> | ||
| 2483 | </item> | ||
| 2484 | <item row="4" column="3"> | ||
| 2485 | <widget class="QPushButton" name="button_c_shift"> | ||
| 2486 | <property name="sizePolicy"> | ||
| 2487 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2488 | <horstretch>1</horstretch> | ||
| 2489 | <verstretch>1</verstretch> | ||
| 2490 | </sizepolicy> | ||
| 2491 | </property> | ||
| 2492 | <property name="font"> | ||
| 2493 | <font> | ||
| 2494 | <pointsize>28</pointsize> | ||
| 2495 | </font> | ||
| 2496 | </property> | ||
| 2497 | <property name="text"> | ||
| 2498 | <string notr="true">C</string> | ||
| 2499 | </property> | ||
| 2500 | </widget> | ||
| 2501 | </item> | ||
| 2502 | <item row="4" column="2"> | ||
| 2503 | <widget class="QPushButton" name="button_x_shift"> | ||
| 2504 | <property name="sizePolicy"> | ||
| 2505 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2506 | <horstretch>1</horstretch> | ||
| 2507 | <verstretch>1</verstretch> | ||
| 2508 | </sizepolicy> | ||
| 2509 | </property> | ||
| 2510 | <property name="font"> | ||
| 2511 | <font> | ||
| 2512 | <pointsize>28</pointsize> | ||
| 2513 | </font> | ||
| 2514 | </property> | ||
| 2515 | <property name="text"> | ||
| 2516 | <string notr="true">X</string> | ||
| 2517 | </property> | ||
| 2518 | </widget> | ||
| 2519 | </item> | ||
| 2520 | <item row="4" column="4"> | ||
| 2521 | <widget class="QPushButton" name="button_v_shift"> | ||
| 2522 | <property name="sizePolicy"> | ||
| 2523 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2524 | <horstretch>1</horstretch> | ||
| 2525 | <verstretch>1</verstretch> | ||
| 2526 | </sizepolicy> | ||
| 2527 | </property> | ||
| 2528 | <property name="font"> | ||
| 2529 | <font> | ||
| 2530 | <pointsize>28</pointsize> | ||
| 2531 | </font> | ||
| 2532 | </property> | ||
| 2533 | <property name="text"> | ||
| 2534 | <string notr="true">V</string> | ||
| 2535 | </property> | ||
| 2536 | </widget> | ||
| 2537 | </item> | ||
| 2538 | <item row="4" column="7"> | ||
| 2539 | <widget class="QPushButton" name="button_m_shift"> | ||
| 2540 | <property name="sizePolicy"> | ||
| 2541 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2542 | <horstretch>1</horstretch> | ||
| 2543 | <verstretch>1</verstretch> | ||
| 2544 | </sizepolicy> | ||
| 2545 | </property> | ||
| 2546 | <property name="font"> | ||
| 2547 | <font> | ||
| 2548 | <pointsize>28</pointsize> | ||
| 2549 | </font> | ||
| 2550 | </property> | ||
| 2551 | <property name="text"> | ||
| 2552 | <string notr="true">M</string> | ||
| 2553 | </property> | ||
| 2554 | </widget> | ||
| 2555 | </item> | ||
| 2556 | <item row="4" column="8"> | ||
| 2557 | <widget class="QPushButton" name="button_less_than"> | ||
| 2558 | <property name="sizePolicy"> | ||
| 2559 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2560 | <horstretch>1</horstretch> | ||
| 2561 | <verstretch>1</verstretch> | ||
| 2562 | </sizepolicy> | ||
| 2563 | </property> | ||
| 2564 | <property name="font"> | ||
| 2565 | <font> | ||
| 2566 | <pointsize>28</pointsize> | ||
| 2567 | </font> | ||
| 2568 | </property> | ||
| 2569 | <property name="text"> | ||
| 2570 | <string notr="true"><</string> | ||
| 2571 | </property> | ||
| 2572 | </widget> | ||
| 2573 | </item> | ||
| 2574 | <item row="4" column="6"> | ||
| 2575 | <widget class="QPushButton" name="button_n_shift"> | ||
| 2576 | <property name="sizePolicy"> | ||
| 2577 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2578 | <horstretch>1</horstretch> | ||
| 2579 | <verstretch>1</verstretch> | ||
| 2580 | </sizepolicy> | ||
| 2581 | </property> | ||
| 2582 | <property name="font"> | ||
| 2583 | <font> | ||
| 2584 | <pointsize>28</pointsize> | ||
| 2585 | </font> | ||
| 2586 | </property> | ||
| 2587 | <property name="text"> | ||
| 2588 | <string notr="true">N</string> | ||
| 2589 | </property> | ||
| 2590 | </widget> | ||
| 2591 | </item> | ||
| 2592 | <item row="4" column="5"> | ||
| 2593 | <widget class="QPushButton" name="button_b_shift"> | ||
| 2594 | <property name="sizePolicy"> | ||
| 2595 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2596 | <horstretch>1</horstretch> | ||
| 2597 | <verstretch>1</verstretch> | ||
| 2598 | </sizepolicy> | ||
| 2599 | </property> | ||
| 2600 | <property name="font"> | ||
| 2601 | <font> | ||
| 2602 | <pointsize>28</pointsize> | ||
| 2603 | </font> | ||
| 2604 | </property> | ||
| 2605 | <property name="text"> | ||
| 2606 | <string notr="true">B</string> | ||
| 2607 | </property> | ||
| 2608 | </widget> | ||
| 2609 | </item> | ||
| 2610 | <item row="5" column="1" colspan="2"> | ||
| 2611 | <widget class="QPushButton" name="button_shift_shift"> | ||
| 2612 | <property name="sizePolicy"> | ||
| 2613 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2614 | <horstretch>1</horstretch> | ||
| 2615 | <verstretch>1</verstretch> | ||
| 2616 | </sizepolicy> | ||
| 2617 | </property> | ||
| 2618 | <property name="font"> | ||
| 2619 | <font> | ||
| 2620 | <pointsize>18</pointsize> | ||
| 2621 | </font> | ||
| 2622 | </property> | ||
| 2623 | <property name="text"> | ||
| 2624 | <string notr="true"/> | ||
| 2625 | </property> | ||
| 2626 | <property name="checkable"> | ||
| 2627 | <bool>true</bool> | ||
| 2628 | </property> | ||
| 2629 | <property name="checked"> | ||
| 2630 | <bool>false</bool> | ||
| 2631 | </property> | ||
| 2632 | </widget> | ||
| 2633 | </item> | ||
| 2634 | <item row="4" column="10"> | ||
| 2635 | <widget class="QPushButton" name="button_plus"> | ||
| 2636 | <property name="sizePolicy"> | ||
| 2637 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2638 | <horstretch>1</horstretch> | ||
| 2639 | <verstretch>1</verstretch> | ||
| 2640 | </sizepolicy> | ||
| 2641 | </property> | ||
| 2642 | <property name="font"> | ||
| 2643 | <font> | ||
| 2644 | <pointsize>28</pointsize> | ||
| 2645 | </font> | ||
| 2646 | </property> | ||
| 2647 | <property name="text"> | ||
| 2648 | <string notr="true">+</string> | ||
| 2649 | </property> | ||
| 2650 | </widget> | ||
| 2651 | </item> | ||
| 2652 | <item row="4" column="9"> | ||
| 2653 | <widget class="QPushButton" name="button_greater_than"> | ||
| 2654 | <property name="sizePolicy"> | ||
| 2655 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2656 | <horstretch>1</horstretch> | ||
| 2657 | <verstretch>1</verstretch> | ||
| 2658 | </sizepolicy> | ||
| 2659 | </property> | ||
| 2660 | <property name="font"> | ||
| 2661 | <font> | ||
| 2662 | <pointsize>28</pointsize> | ||
| 2663 | </font> | ||
| 2664 | </property> | ||
| 2665 | <property name="text"> | ||
| 2666 | <string notr="true">></string> | ||
| 2667 | </property> | ||
| 2668 | </widget> | ||
| 2669 | </item> | ||
| 2670 | <item row="1" column="1"> | ||
| 2671 | <widget class="QPushButton" name="button_hash"> | ||
| 2672 | <property name="sizePolicy"> | ||
| 2673 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2674 | <horstretch>1</horstretch> | ||
| 2675 | <verstretch>1</verstretch> | ||
| 2676 | </sizepolicy> | ||
| 2677 | </property> | ||
| 2678 | <property name="font"> | ||
| 2679 | <font> | ||
| 2680 | <pointsize>28</pointsize> | ||
| 2681 | </font> | ||
| 2682 | </property> | ||
| 2683 | <property name="text"> | ||
| 2684 | <string notr="true">#</string> | ||
| 2685 | </property> | ||
| 2686 | </widget> | ||
| 2687 | </item> | ||
| 2688 | <item row="1" column="3"> | ||
| 2689 | <widget class="QPushButton" name="button_right_bracket"> | ||
| 2690 | <property name="sizePolicy"> | ||
| 2691 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2692 | <horstretch>1</horstretch> | ||
| 2693 | <verstretch>1</verstretch> | ||
| 2694 | </sizepolicy> | ||
| 2695 | </property> | ||
| 2696 | <property name="font"> | ||
| 2697 | <font> | ||
| 2698 | <pointsize>28</pointsize> | ||
| 2699 | </font> | ||
| 2700 | </property> | ||
| 2701 | <property name="text"> | ||
| 2702 | <string notr="true">]</string> | ||
| 2703 | </property> | ||
| 2704 | </widget> | ||
| 2705 | </item> | ||
| 2706 | <item row="1" column="4"> | ||
| 2707 | <widget class="QPushButton" name="button_dollar"> | ||
| 2708 | <property name="sizePolicy"> | ||
| 2709 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2710 | <horstretch>1</horstretch> | ||
| 2711 | <verstretch>1</verstretch> | ||
| 2712 | </sizepolicy> | ||
| 2713 | </property> | ||
| 2714 | <property name="font"> | ||
| 2715 | <font> | ||
| 2716 | <pointsize>28</pointsize> | ||
| 2717 | </font> | ||
| 2718 | </property> | ||
| 2719 | <property name="text"> | ||
| 2720 | <string notr="true">$</string> | ||
| 2721 | </property> | ||
| 2722 | </widget> | ||
| 2723 | </item> | ||
| 2724 | <item row="1" column="2"> | ||
| 2725 | <widget class="QPushButton" name="button_left_bracket"> | ||
| 2726 | <property name="sizePolicy"> | ||
| 2727 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2728 | <horstretch>1</horstretch> | ||
| 2729 | <verstretch>1</verstretch> | ||
| 2730 | </sizepolicy> | ||
| 2731 | </property> | ||
| 2732 | <property name="font"> | ||
| 2733 | <font> | ||
| 2734 | <pointsize>28</pointsize> | ||
| 2735 | </font> | ||
| 2736 | </property> | ||
| 2737 | <property name="text"> | ||
| 2738 | <string notr="true">[</string> | ||
| 2739 | </property> | ||
| 2740 | </widget> | ||
| 2741 | </item> | ||
| 2742 | <item row="1" column="6"> | ||
| 2743 | <widget class="QPushButton" name="button_circumflex"> | ||
| 2744 | <property name="sizePolicy"> | ||
| 2745 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2746 | <horstretch>1</horstretch> | ||
| 2747 | <verstretch>1</verstretch> | ||
| 2748 | </sizepolicy> | ||
| 2749 | </property> | ||
| 2750 | <property name="font"> | ||
| 2751 | <font> | ||
| 2752 | <pointsize>28</pointsize> | ||
| 2753 | </font> | ||
| 2754 | </property> | ||
| 2755 | <property name="text"> | ||
| 2756 | <string notr="true">^</string> | ||
| 2757 | </property> | ||
| 2758 | </widget> | ||
| 2759 | </item> | ||
| 2760 | <item row="1" column="5"> | ||
| 2761 | <widget class="QPushButton" name="button_percent"> | ||
| 2762 | <property name="sizePolicy"> | ||
| 2763 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2764 | <horstretch>1</horstretch> | ||
| 2765 | <verstretch>1</verstretch> | ||
| 2766 | </sizepolicy> | ||
| 2767 | </property> | ||
| 2768 | <property name="font"> | ||
| 2769 | <font> | ||
| 2770 | <pointsize>28</pointsize> | ||
| 2771 | </font> | ||
| 2772 | </property> | ||
| 2773 | <property name="text"> | ||
| 2774 | <string notr="true">%</string> | ||
| 2775 | </property> | ||
| 2776 | </widget> | ||
| 2777 | </item> | ||
| 2778 | <item row="5" column="3" colspan="9"> | ||
| 2779 | <widget class="QPushButton" name="button_space_shift"> | ||
| 2780 | <property name="sizePolicy"> | ||
| 2781 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2782 | <horstretch>1</horstretch> | ||
| 2783 | <verstretch>1</verstretch> | ||
| 2784 | </sizepolicy> | ||
| 2785 | </property> | ||
| 2786 | <property name="font"> | ||
| 2787 | <font> | ||
| 2788 | <pointsize>18</pointsize> | ||
| 2789 | </font> | ||
| 2790 | </property> | ||
| 2791 | <property name="text"> | ||
| 2792 | <string notr="true">Space</string> | ||
| 2793 | </property> | ||
| 2794 | </widget> | ||
| 2795 | </item> | ||
| 2796 | <item row="1" column="12"> | ||
| 2797 | <widget class="QPushButton" name="button_backspace_shift"> | ||
| 2798 | <property name="sizePolicy"> | ||
| 2799 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2800 | <horstretch>1</horstretch> | ||
| 2801 | <verstretch>1</verstretch> | ||
| 2802 | </sizepolicy> | ||
| 2803 | </property> | ||
| 2804 | <property name="font"> | ||
| 2805 | <font> | ||
| 2806 | <pointsize>18</pointsize> | ||
| 2807 | </font> | ||
| 2808 | </property> | ||
| 2809 | <property name="text"> | ||
| 2810 | <string notr="true"/> | ||
| 2811 | </property> | ||
| 2812 | </widget> | ||
| 2813 | </item> | ||
| 2814 | <item row="1" column="0"> | ||
| 2815 | <spacer name="horizontalSpacer_33"> | ||
| 2816 | <property name="orientation"> | ||
| 2817 | <enum>Qt::Horizontal</enum> | ||
| 2818 | </property> | ||
| 2819 | <property name="sizeHint" stdset="0"> | ||
| 2820 | <size> | ||
| 2821 | <width>40</width> | ||
| 2822 | <height>20</height> | ||
| 2823 | </size> | ||
| 2824 | </property> | ||
| 2825 | </spacer> | ||
| 2826 | </item> | ||
| 2827 | <item row="0" column="1"> | ||
| 2828 | <spacer name="verticalSpacer_6"> | ||
| 2829 | <property name="orientation"> | ||
| 2830 | <enum>Qt::Vertical</enum> | ||
| 2831 | </property> | ||
| 2832 | <property name="sizeHint" stdset="0"> | ||
| 2833 | <size> | ||
| 2834 | <width>20</width> | ||
| 2835 | <height>0</height> | ||
| 2836 | </size> | ||
| 2837 | </property> | ||
| 2838 | </spacer> | ||
| 2839 | </item> | ||
| 2840 | <item row="1" column="13"> | ||
| 2841 | <spacer name="horizontalSpacer_34"> | ||
| 2842 | <property name="orientation"> | ||
| 2843 | <enum>Qt::Horizontal</enum> | ||
| 2844 | </property> | ||
| 2845 | <property name="sizeHint" stdset="0"> | ||
| 2846 | <size> | ||
| 2847 | <width>40</width> | ||
| 2848 | <height>20</height> | ||
| 2849 | </size> | ||
| 2850 | </property> | ||
| 2851 | </spacer> | ||
| 2852 | </item> | ||
| 2853 | </layout> | ||
| 2854 | </item> | ||
| 2855 | </layout> | ||
| 2856 | </widget> | ||
| 2857 | <widget class="QWidget" name="numOSK"> | ||
| 2858 | <layout class="QVBoxLayout" name="graphicsTabVerticalLayout"> | ||
| 2859 | <property name="leftMargin"> | ||
| 2860 | <number>0</number> | ||
| 2861 | </property> | ||
| 2862 | <property name="topMargin"> | ||
| 2863 | <number>0</number> | ||
| 2864 | </property> | ||
| 2865 | <property name="rightMargin"> | ||
| 2866 | <number>0</number> | ||
| 2867 | </property> | ||
| 2868 | <property name="bottomMargin"> | ||
| 2869 | <number>0</number> | ||
| 2870 | </property> | ||
| 2871 | <item> | ||
| 2872 | <layout class="QGridLayout" name="kbOSKnum" rowstretch="18,63,63,63,63,10,70" columnstretch="54,307,186,186,186,120,187,54"> | ||
| 2873 | <property name="leftMargin"> | ||
| 2874 | <number>0</number> | ||
| 2875 | </property> | ||
| 2876 | <property name="rightMargin"> | ||
| 2877 | <number>0</number> | ||
| 2878 | </property> | ||
| 2879 | <property name="spacing"> | ||
| 2880 | <number>0</number> | ||
| 2881 | </property> | ||
| 2882 | <item row="1" column="5"> | ||
| 2883 | <widget class="QPushButton" name="button_backspace_num"> | ||
| 2884 | <property name="sizePolicy"> | ||
| 2885 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 2886 | <horstretch>1</horstretch> | ||
| 2887 | <verstretch>1</verstretch> | ||
| 2888 | </sizepolicy> | ||
| 2889 | </property> | ||
| 2890 | <property name="font"> | ||
| 2891 | <font> | ||
| 2892 | <pointsize>18</pointsize> | ||
| 2893 | </font> | ||
| 2894 | </property> | ||
| 2895 | <property name="text"> | ||
| 2896 | <string notr="true"/> | ||
| 2897 | </property> | ||
| 2898 | </widget> | ||
| 2899 | </item> | ||
| 2900 | <item row="1" column="6"> | ||
| 2901 | <spacer name="horizontalSpacer_35"> | ||
| 2902 | <property name="orientation"> | ||
| 2903 | <enum>Qt::Horizontal</enum> | ||
| 2904 | </property> | ||
| 2905 | <property name="sizeHint" stdset="0"> | ||
| 2906 | <size> | ||
| 2907 | <width>40</width> | ||
| 2908 | <height>20</height> | ||
| 2909 | </size> | ||
| 2910 | </property> | ||
| 2911 | </spacer> | ||
| 2912 | </item> | ||
| 2913 | <item row="1" column="1"> | ||
| 2914 | <spacer name="horizontalSpacer_36"> | ||
| 2915 | <property name="orientation"> | ||
| 2916 | <enum>Qt::Horizontal</enum> | ||
| 2917 | </property> | ||
| 2918 | <property name="sizeHint" stdset="0"> | ||
| 2919 | <size> | ||
| 2920 | <width>40</width> | ||
| 2921 | <height>20</height> | ||
| 2922 | </size> | ||
| 2923 | </property> | ||
| 2924 | </spacer> | ||
| 2925 | </item> | ||
| 2926 | <item row="0" column="2"> | ||
| 2927 | <spacer name="verticalSpacer_7"> | ||
| 2928 | <property name="orientation"> | ||
| 2929 | <enum>Qt::Vertical</enum> | ||
| 2930 | </property> | ||
| 2931 | <property name="sizeHint" stdset="0"> | ||
| 2932 | <size> | ||
| 2933 | <width>20</width> | ||
| 2934 | <height>0</height> | ||
| 2935 | </size> | ||
| 2936 | </property> | ||
| 2937 | </spacer> | ||
| 2938 | </item> | ||
| 2939 | <item row="6" column="1" colspan="6"> | ||
| 2940 | <widget class="QWidget" name="legendOSKnum" native="true"> | ||
| 2941 | <layout class="QHBoxLayout" name="horizontalLayout_6" stretch="25,70,601,25,12,22,41,25,12,22,41,29,12,69,37,29,12,56,30"> | ||
| 2942 | <property name="spacing"> | ||
| 2943 | <number>0</number> | ||
| 2944 | </property> | ||
| 2945 | <property name="leftMargin"> | ||
| 2946 | <number>0</number> | ||
| 2947 | </property> | ||
| 2948 | <property name="topMargin"> | ||
| 2949 | <number>0</number> | ||
| 2950 | </property> | ||
| 2951 | <property name="rightMargin"> | ||
| 2952 | <number>0</number> | ||
| 2953 | </property> | ||
| 2954 | <property name="bottomMargin"> | ||
| 2955 | <number>0</number> | ||
| 2956 | </property> | ||
| 2957 | <item> | ||
| 2958 | <spacer name="horizontalSpacer_48"> | ||
| 2959 | <property name="orientation"> | ||
| 2960 | <enum>Qt::Horizontal</enum> | ||
| 2961 | </property> | ||
| 2962 | <property name="sizeHint" stdset="0"> | ||
| 2963 | <size> | ||
| 2964 | <width>40</width> | ||
| 2965 | <height>20</height> | ||
| 2966 | </size> | ||
| 2967 | </property> | ||
| 2968 | </spacer> | ||
| 2969 | </item> | ||
| 2970 | <item> | ||
| 2971 | <widget class="QWidget" name="icon_controller_num" native="true"> | ||
| 2972 | <property name="styleSheet"> | ||
| 2973 | <string notr="true"/> | ||
| 2974 | </property> | ||
| 2975 | </widget> | ||
| 2976 | </item> | ||
| 2977 | <item> | ||
| 2978 | <spacer name="horizontalSpacer_38"> | ||
| 2979 | <property name="orientation"> | ||
| 2980 | <enum>Qt::Horizontal</enum> | ||
| 2981 | </property> | ||
| 2982 | <property name="sizeHint" stdset="0"> | ||
| 2983 | <size> | ||
| 2984 | <width>0</width> | ||
| 2985 | <height>20</height> | ||
| 2986 | </size> | ||
| 2987 | </property> | ||
| 2988 | </spacer> | ||
| 2989 | </item> | ||
| 2990 | <item> | ||
| 2991 | <widget class="QWidget" name="button_L_num" native="true"/> | ||
| 2992 | </item> | ||
| 2993 | <item> | ||
| 2994 | <spacer name="horizontalSpacer_39"> | ||
| 2995 | <property name="orientation"> | ||
| 2996 | <enum>Qt::Horizontal</enum> | ||
| 2997 | </property> | ||
| 2998 | <property name="sizeHint" stdset="0"> | ||
| 2999 | <size> | ||
| 3000 | <width>0</width> | ||
| 3001 | <height>20</height> | ||
| 3002 | </size> | ||
| 3003 | </property> | ||
| 3004 | </spacer> | ||
| 3005 | </item> | ||
| 3006 | <item> | ||
| 3007 | <widget class="QWidget" name="arrow_left_num" native="true"/> | ||
| 3008 | </item> | ||
| 3009 | <item> | ||
| 3010 | <spacer name="horizontalSpacer_40"> | ||
| 3011 | <property name="orientation"> | ||
| 3012 | <enum>Qt::Horizontal</enum> | ||
| 3013 | </property> | ||
| 3014 | <property name="sizeHint" stdset="0"> | ||
| 3015 | <size> | ||
| 3016 | <width>0</width> | ||
| 3017 | <height>20</height> | ||
| 3018 | </size> | ||
| 3019 | </property> | ||
| 3020 | </spacer> | ||
| 3021 | </item> | ||
| 3022 | <item> | ||
| 3023 | <widget class="QWidget" name="button_R_num" native="true"/> | ||
| 3024 | </item> | ||
| 3025 | <item> | ||
| 3026 | <spacer name="horizontalSpacer_41"> | ||
| 3027 | <property name="orientation"> | ||
| 3028 | <enum>Qt::Horizontal</enum> | ||
| 3029 | </property> | ||
| 3030 | <property name="sizeHint" stdset="0"> | ||
| 3031 | <size> | ||
| 3032 | <width>0</width> | ||
| 3033 | <height>20</height> | ||
| 3034 | </size> | ||
| 3035 | </property> | ||
| 3036 | </spacer> | ||
| 3037 | </item> | ||
| 3038 | <item> | ||
| 3039 | <widget class="QWidget" name="arrow_right_num" native="true"/> | ||
| 3040 | </item> | ||
| 3041 | <item> | ||
| 3042 | <spacer name="horizontalSpacer_42"> | ||
| 3043 | <property name="orientation"> | ||
| 3044 | <enum>Qt::Horizontal</enum> | ||
| 3045 | </property> | ||
| 3046 | <property name="sizeHint" stdset="0"> | ||
| 3047 | <size> | ||
| 3048 | <width>0</width> | ||
| 3049 | <height>20</height> | ||
| 3050 | </size> | ||
| 3051 | </property> | ||
| 3052 | </spacer> | ||
| 3053 | </item> | ||
| 3054 | <item> | ||
| 3055 | <widget class="QWidget" name="button_X_num" native="true"/> | ||
| 3056 | </item> | ||
| 3057 | <item> | ||
| 3058 | <spacer name="horizontalSpacer_43"> | ||
| 3059 | <property name="orientation"> | ||
| 3060 | <enum>Qt::Horizontal</enum> | ||
| 3061 | </property> | ||
| 3062 | <property name="sizeHint" stdset="0"> | ||
| 3063 | <size> | ||
| 3064 | <width>0</width> | ||
| 3065 | <height>20</height> | ||
| 3066 | </size> | ||
| 3067 | </property> | ||
| 3068 | </spacer> | ||
| 3069 | </item> | ||
| 3070 | <item> | ||
| 3071 | <widget class="QLabel" name="label_cancel_num"> | ||
| 3072 | <property name="font"> | ||
| 3073 | <font> | ||
| 3074 | <pointsize>18</pointsize> | ||
| 3075 | </font> | ||
| 3076 | </property> | ||
| 3077 | <property name="text"> | ||
| 3078 | <string notr="true">Cancel</string> | ||
| 3079 | </property> | ||
| 3080 | </widget> | ||
| 3081 | </item> | ||
| 3082 | <item> | ||
| 3083 | <spacer name="horizontalSpacer_44"> | ||
| 3084 | <property name="orientation"> | ||
| 3085 | <enum>Qt::Horizontal</enum> | ||
| 3086 | </property> | ||
| 3087 | <property name="sizeHint" stdset="0"> | ||
| 3088 | <size> | ||
| 3089 | <width>0</width> | ||
| 3090 | <height>20</height> | ||
| 3091 | </size> | ||
| 3092 | </property> | ||
| 3093 | </spacer> | ||
| 3094 | </item> | ||
| 3095 | <item> | ||
| 3096 | <widget class="QWidget" name="button_A_num" native="true"/> | ||
| 3097 | </item> | ||
| 3098 | <item> | ||
| 3099 | <spacer name="horizontalSpacer_45"> | ||
| 3100 | <property name="orientation"> | ||
| 3101 | <enum>Qt::Horizontal</enum> | ||
| 3102 | </property> | ||
| 3103 | <property name="sizeHint" stdset="0"> | ||
| 3104 | <size> | ||
| 3105 | <width>0</width> | ||
| 3106 | <height>20</height> | ||
| 3107 | </size> | ||
| 3108 | </property> | ||
| 3109 | </spacer> | ||
| 3110 | </item> | ||
| 3111 | <item> | ||
| 3112 | <widget class="QLabel" name="label_enter_num"> | ||
| 3113 | <property name="font"> | ||
| 3114 | <font> | ||
| 3115 | <pointsize>18</pointsize> | ||
| 3116 | </font> | ||
| 3117 | </property> | ||
| 3118 | <property name="text"> | ||
| 3119 | <string notr="true">Enter</string> | ||
| 3120 | </property> | ||
| 3121 | </widget> | ||
| 3122 | </item> | ||
| 3123 | <item> | ||
| 3124 | <spacer name="horizontalSpacer_46"> | ||
| 3125 | <property name="orientation"> | ||
| 3126 | <enum>Qt::Horizontal</enum> | ||
| 3127 | </property> | ||
| 3128 | <property name="sizeHint" stdset="0"> | ||
| 3129 | <size> | ||
| 3130 | <width>0</width> | ||
| 3131 | <height>20</height> | ||
| 3132 | </size> | ||
| 3133 | </property> | ||
| 3134 | </spacer> | ||
| 3135 | </item> | ||
| 3136 | </layout> | ||
| 3137 | </widget> | ||
| 3138 | </item> | ||
| 3139 | <item row="2" column="4"> | ||
| 3140 | <widget class="QPushButton" name="button_6_num"> | ||
| 3141 | <property name="sizePolicy"> | ||
| 3142 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 3143 | <horstretch>1</horstretch> | ||
| 3144 | <verstretch>1</verstretch> | ||
| 3145 | </sizepolicy> | ||
| 3146 | </property> | ||
| 3147 | <property name="font"> | ||
| 3148 | <font> | ||
| 3149 | <pointsize>28</pointsize> | ||
| 3150 | </font> | ||
| 3151 | </property> | ||
| 3152 | <property name="text"> | ||
| 3153 | <string notr="true">6</string> | ||
| 3154 | </property> | ||
| 3155 | </widget> | ||
| 3156 | </item> | ||
| 3157 | <item row="2" column="2"> | ||
| 3158 | <widget class="QPushButton" name="button_4_num"> | ||
| 3159 | <property name="sizePolicy"> | ||
| 3160 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 3161 | <horstretch>1</horstretch> | ||
| 3162 | <verstretch>1</verstretch> | ||
| 3163 | </sizepolicy> | ||
| 3164 | </property> | ||
| 3165 | <property name="font"> | ||
| 3166 | <font> | ||
| 3167 | <pointsize>28</pointsize> | ||
| 3168 | </font> | ||
| 3169 | </property> | ||
| 3170 | <property name="text"> | ||
| 3171 | <string notr="true">4</string> | ||
| 3172 | </property> | ||
| 3173 | </widget> | ||
| 3174 | </item> | ||
| 3175 | <item row="3" column="4"> | ||
| 3176 | <widget class="QPushButton" name="button_9_num"> | ||
| 3177 | <property name="sizePolicy"> | ||
| 3178 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 3179 | <horstretch>1</horstretch> | ||
| 3180 | <verstretch>1</verstretch> | ||
| 3181 | </sizepolicy> | ||
| 3182 | </property> | ||
| 3183 | <property name="font"> | ||
| 3184 | <font> | ||
| 3185 | <pointsize>28</pointsize> | ||
| 3186 | </font> | ||
| 3187 | </property> | ||
| 3188 | <property name="text"> | ||
| 3189 | <string notr="true">9</string> | ||
| 3190 | </property> | ||
| 3191 | </widget> | ||
| 3192 | </item> | ||
| 3193 | <item row="2" column="3"> | ||
| 3194 | <widget class="QPushButton" name="button_5_num"> | ||
| 3195 | <property name="sizePolicy"> | ||
| 3196 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 3197 | <horstretch>1</horstretch> | ||
| 3198 | <verstretch>1</verstretch> | ||
| 3199 | </sizepolicy> | ||
| 3200 | </property> | ||
| 3201 | <property name="font"> | ||
| 3202 | <font> | ||
| 3203 | <pointsize>28</pointsize> | ||
| 3204 | </font> | ||
| 3205 | </property> | ||
| 3206 | <property name="text"> | ||
| 3207 | <string notr="true">5</string> | ||
| 3208 | </property> | ||
| 3209 | </widget> | ||
| 3210 | </item> | ||
| 3211 | <item row="2" column="5" rowspan="3"> | ||
| 3212 | <widget class="QPushButton" name="button_ok_num"> | ||
| 3213 | <property name="sizePolicy"> | ||
| 3214 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 3215 | <horstretch>1</horstretch> | ||
| 3216 | <verstretch>1</verstretch> | ||
| 3217 | </sizepolicy> | ||
| 3218 | </property> | ||
| 3219 | <property name="font"> | ||
| 3220 | <font> | ||
| 3221 | <pointsize>18</pointsize> | ||
| 3222 | </font> | ||
| 3223 | </property> | ||
| 3224 | <property name="text"> | ||
| 3225 | <string notr="true">OK</string> | ||
| 3226 | </property> | ||
| 3227 | </widget> | ||
| 3228 | </item> | ||
| 3229 | <item row="3" column="2"> | ||
| 3230 | <widget class="QPushButton" name="button_7_num"> | ||
| 3231 | <property name="sizePolicy"> | ||
| 3232 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 3233 | <horstretch>1</horstretch> | ||
| 3234 | <verstretch>1</verstretch> | ||
| 3235 | </sizepolicy> | ||
| 3236 | </property> | ||
| 3237 | <property name="font"> | ||
| 3238 | <font> | ||
| 3239 | <pointsize>28</pointsize> | ||
| 3240 | </font> | ||
| 3241 | </property> | ||
| 3242 | <property name="text"> | ||
| 3243 | <string notr="true">7</string> | ||
| 3244 | </property> | ||
| 3245 | </widget> | ||
| 3246 | </item> | ||
| 3247 | <item row="3" column="3"> | ||
| 3248 | <widget class="QPushButton" name="button_8_num"> | ||
| 3249 | <property name="sizePolicy"> | ||
| 3250 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 3251 | <horstretch>1</horstretch> | ||
| 3252 | <verstretch>1</verstretch> | ||
| 3253 | </sizepolicy> | ||
| 3254 | </property> | ||
| 3255 | <property name="font"> | ||
| 3256 | <font> | ||
| 3257 | <pointsize>28</pointsize> | ||
| 3258 | </font> | ||
| 3259 | </property> | ||
| 3260 | <property name="text"> | ||
| 3261 | <string notr="true">8</string> | ||
| 3262 | </property> | ||
| 3263 | </widget> | ||
| 3264 | </item> | ||
| 3265 | <item row="1" column="3"> | ||
| 3266 | <widget class="QPushButton" name="button_2_num"> | ||
| 3267 | <property name="sizePolicy"> | ||
| 3268 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 3269 | <horstretch>1</horstretch> | ||
| 3270 | <verstretch>1</verstretch> | ||
| 3271 | </sizepolicy> | ||
| 3272 | </property> | ||
| 3273 | <property name="font"> | ||
| 3274 | <font> | ||
| 3275 | <pointsize>28</pointsize> | ||
| 3276 | </font> | ||
| 3277 | </property> | ||
| 3278 | <property name="text"> | ||
| 3279 | <string notr="true">2</string> | ||
| 3280 | </property> | ||
| 3281 | </widget> | ||
| 3282 | </item> | ||
| 3283 | <item row="1" column="2"> | ||
| 3284 | <widget class="QPushButton" name="button_1_num"> | ||
| 3285 | <property name="sizePolicy"> | ||
| 3286 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 3287 | <horstretch>1</horstretch> | ||
| 3288 | <verstretch>1</verstretch> | ||
| 3289 | </sizepolicy> | ||
| 3290 | </property> | ||
| 3291 | <property name="font"> | ||
| 3292 | <font> | ||
| 3293 | <pointsize>28</pointsize> | ||
| 3294 | </font> | ||
| 3295 | </property> | ||
| 3296 | <property name="text"> | ||
| 3297 | <string notr="true">1</string> | ||
| 3298 | </property> | ||
| 3299 | </widget> | ||
| 3300 | </item> | ||
| 3301 | <item row="4" column="3"> | ||
| 3302 | <widget class="QPushButton" name="button_0_num"> | ||
| 3303 | <property name="sizePolicy"> | ||
| 3304 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 3305 | <horstretch>1</horstretch> | ||
| 3306 | <verstretch>1</verstretch> | ||
| 3307 | </sizepolicy> | ||
| 3308 | </property> | ||
| 3309 | <property name="font"> | ||
| 3310 | <font> | ||
| 3311 | <pointsize>28</pointsize> | ||
| 3312 | </font> | ||
| 3313 | </property> | ||
| 3314 | <property name="text"> | ||
| 3315 | <string notr="true">0</string> | ||
| 3316 | </property> | ||
| 3317 | </widget> | ||
| 3318 | </item> | ||
| 3319 | <item row="1" column="4"> | ||
| 3320 | <widget class="QPushButton" name="button_3_num"> | ||
| 3321 | <property name="sizePolicy"> | ||
| 3322 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 3323 | <horstretch>1</horstretch> | ||
| 3324 | <verstretch>1</verstretch> | ||
| 3325 | </sizepolicy> | ||
| 3326 | </property> | ||
| 3327 | <property name="font"> | ||
| 3328 | <font> | ||
| 3329 | <pointsize>28</pointsize> | ||
| 3330 | </font> | ||
| 3331 | </property> | ||
| 3332 | <property name="text"> | ||
| 3333 | <string notr="true">3</string> | ||
| 3334 | </property> | ||
| 3335 | </widget> | ||
| 3336 | </item> | ||
| 3337 | <item row="1" column="0"> | ||
| 3338 | <spacer name="horizontalSpacer_37"> | ||
| 3339 | <property name="orientation"> | ||
| 3340 | <enum>Qt::Horizontal</enum> | ||
| 3341 | </property> | ||
| 3342 | <property name="sizeHint" stdset="0"> | ||
| 3343 | <size> | ||
| 3344 | <width>40</width> | ||
| 3345 | <height>20</height> | ||
| 3346 | </size> | ||
| 3347 | </property> | ||
| 3348 | </spacer> | ||
| 3349 | </item> | ||
| 3350 | <item row="1" column="7"> | ||
| 3351 | <spacer name="horizontalSpacer_47"> | ||
| 3352 | <property name="orientation"> | ||
| 3353 | <enum>Qt::Horizontal</enum> | ||
| 3354 | </property> | ||
| 3355 | <property name="sizeHint" stdset="0"> | ||
| 3356 | <size> | ||
| 3357 | <width>40</width> | ||
| 3358 | <height>20</height> | ||
| 3359 | </size> | ||
| 3360 | </property> | ||
| 3361 | </spacer> | ||
| 3362 | </item> | ||
| 3363 | <item row="5" column="3"> | ||
| 3364 | <spacer name="verticalSpacer_8"> | ||
| 3365 | <property name="orientation"> | ||
| 3366 | <enum>Qt::Vertical</enum> | ||
| 3367 | </property> | ||
| 3368 | <property name="sizeHint" stdset="0"> | ||
| 3369 | <size> | ||
| 3370 | <width>20</width> | ||
| 3371 | <height>0</height> | ||
| 3372 | </size> | ||
| 3373 | </property> | ||
| 3374 | </spacer> | ||
| 3375 | </item> | ||
| 3376 | </layout> | ||
| 3377 | </item> | ||
| 3378 | </layout> | ||
| 3379 | </widget> | ||
| 3380 | </widget> | ||
| 3381 | </item> | ||
| 3382 | </layout> | ||
| 3383 | </widget> | ||
| 3384 | </item> | ||
| 3385 | </layout> | ||
| 3386 | </widget> | ||
| 3387 | <tabstops> | ||
| 3388 | <tabstop>button_1</tabstop> | ||
| 3389 | <tabstop>button_2</tabstop> | ||
| 3390 | <tabstop>button_3</tabstop> | ||
| 3391 | <tabstop>button_4</tabstop> | ||
| 3392 | <tabstop>button_5</tabstop> | ||
| 3393 | <tabstop>button_6</tabstop> | ||
| 3394 | <tabstop>button_7</tabstop> | ||
| 3395 | <tabstop>button_8</tabstop> | ||
| 3396 | <tabstop>button_9</tabstop> | ||
| 3397 | <tabstop>button_0</tabstop> | ||
| 3398 | <tabstop>button_minus</tabstop> | ||
| 3399 | <tabstop>button_backspace</tabstop> | ||
| 3400 | <tabstop>button_q</tabstop> | ||
| 3401 | <tabstop>button_w</tabstop> | ||
| 3402 | <tabstop>button_e</tabstop> | ||
| 3403 | <tabstop>button_r</tabstop> | ||
| 3404 | <tabstop>button_t</tabstop> | ||
| 3405 | <tabstop>button_y</tabstop> | ||
| 3406 | <tabstop>button_u</tabstop> | ||
| 3407 | <tabstop>button_i</tabstop> | ||
| 3408 | <tabstop>button_o</tabstop> | ||
| 3409 | <tabstop>button_p</tabstop> | ||
| 3410 | <tabstop>button_slash</tabstop> | ||
| 3411 | <tabstop>button_return</tabstop> | ||
| 3412 | <tabstop>button_a</tabstop> | ||
| 3413 | <tabstop>button_s</tabstop> | ||
| 3414 | <tabstop>button_d</tabstop> | ||
| 3415 | <tabstop>button_f</tabstop> | ||
| 3416 | <tabstop>button_g</tabstop> | ||
| 3417 | <tabstop>button_h</tabstop> | ||
| 3418 | <tabstop>button_j</tabstop> | ||
| 3419 | <tabstop>button_k</tabstop> | ||
| 3420 | <tabstop>button_l</tabstop> | ||
| 3421 | <tabstop>button_colon</tabstop> | ||
| 3422 | <tabstop>button_apostrophe</tabstop> | ||
| 3423 | <tabstop>button_z</tabstop> | ||
| 3424 | <tabstop>button_x</tabstop> | ||
| 3425 | <tabstop>button_c</tabstop> | ||
| 3426 | <tabstop>button_v</tabstop> | ||
| 3427 | <tabstop>button_b</tabstop> | ||
| 3428 | <tabstop>button_n</tabstop> | ||
| 3429 | <tabstop>button_m</tabstop> | ||
| 3430 | <tabstop>button_comma</tabstop> | ||
| 3431 | <tabstop>button_dot</tabstop> | ||
| 3432 | <tabstop>button_question</tabstop> | ||
| 3433 | <tabstop>button_exclamation</tabstop> | ||
| 3434 | <tabstop>button_ok</tabstop> | ||
| 3435 | <tabstop>button_shift</tabstop> | ||
| 3436 | <tabstop>button_space</tabstop> | ||
| 3437 | <tabstop>button_hash</tabstop> | ||
| 3438 | <tabstop>button_left_bracket</tabstop> | ||
| 3439 | <tabstop>button_right_bracket</tabstop> | ||
| 3440 | <tabstop>button_dollar</tabstop> | ||
| 3441 | <tabstop>button_percent</tabstop> | ||
| 3442 | <tabstop>button_circumflex</tabstop> | ||
| 3443 | <tabstop>button_ampersand</tabstop> | ||
| 3444 | <tabstop>button_asterisk</tabstop> | ||
| 3445 | <tabstop>button_left_parenthesis</tabstop> | ||
| 3446 | <tabstop>button_right_parenthesis</tabstop> | ||
| 3447 | <tabstop>button_underscore</tabstop> | ||
| 3448 | <tabstop>button_backspace_shift</tabstop> | ||
| 3449 | <tabstop>button_q_shift</tabstop> | ||
| 3450 | <tabstop>button_w_shift</tabstop> | ||
| 3451 | <tabstop>button_e_shift</tabstop> | ||
| 3452 | <tabstop>button_r_shift</tabstop> | ||
| 3453 | <tabstop>button_t_shift</tabstop> | ||
| 3454 | <tabstop>button_y_shift</tabstop> | ||
| 3455 | <tabstop>button_u_shift</tabstop> | ||
| 3456 | <tabstop>button_i_shift</tabstop> | ||
| 3457 | <tabstop>button_o_shift</tabstop> | ||
| 3458 | <tabstop>button_p_shift</tabstop> | ||
| 3459 | <tabstop>button_at</tabstop> | ||
| 3460 | <tabstop>button_return_shift</tabstop> | ||
| 3461 | <tabstop>button_a_shift</tabstop> | ||
| 3462 | <tabstop>button_s_shift</tabstop> | ||
| 3463 | <tabstop>button_d_shift</tabstop> | ||
| 3464 | <tabstop>button_f_shift</tabstop> | ||
| 3465 | <tabstop>button_g_shift</tabstop> | ||
| 3466 | <tabstop>button_h_shift</tabstop> | ||
| 3467 | <tabstop>button_j_shift</tabstop> | ||
| 3468 | <tabstop>button_k_shift</tabstop> | ||
| 3469 | <tabstop>button_l_shift</tabstop> | ||
| 3470 | <tabstop>button_semicolon</tabstop> | ||
| 3471 | <tabstop>button_quotation</tabstop> | ||
| 3472 | <tabstop>button_z_shift</tabstop> | ||
| 3473 | <tabstop>button_x_shift</tabstop> | ||
| 3474 | <tabstop>button_c_shift</tabstop> | ||
| 3475 | <tabstop>button_v_shift</tabstop> | ||
| 3476 | <tabstop>button_b_shift</tabstop> | ||
| 3477 | <tabstop>button_n_shift</tabstop> | ||
| 3478 | <tabstop>button_m_shift</tabstop> | ||
| 3479 | <tabstop>button_less_than</tabstop> | ||
| 3480 | <tabstop>button_greater_than</tabstop> | ||
| 3481 | <tabstop>button_plus</tabstop> | ||
| 3482 | <tabstop>button_equal</tabstop> | ||
| 3483 | <tabstop>button_ok_shift</tabstop> | ||
| 3484 | <tabstop>button_shift_shift</tabstop> | ||
| 3485 | <tabstop>button_space_shift</tabstop> | ||
| 3486 | <tabstop>button_1_num</tabstop> | ||
| 3487 | <tabstop>button_2_num</tabstop> | ||
| 3488 | <tabstop>button_3_num</tabstop> | ||
| 3489 | <tabstop>button_backspace_num</tabstop> | ||
| 3490 | <tabstop>button_4_num</tabstop> | ||
| 3491 | <tabstop>button_5_num</tabstop> | ||
| 3492 | <tabstop>button_6_num</tabstop> | ||
| 3493 | <tabstop>button_ok_num</tabstop> | ||
| 3494 | <tabstop>button_7_num</tabstop> | ||
| 3495 | <tabstop>button_8_num</tabstop> | ||
| 3496 | <tabstop>button_9_num</tabstop> | ||
| 3497 | <tabstop>button_0_num</tabstop> | ||
| 3498 | </tabstops> | ||
| 3499 | <resources> | ||
| 3500 | <include location="../../../dist/icons/overlay/overlay.qrc"/> | ||
| 3501 | </resources> | ||
| 3502 | <connections/> | ||
| 3503 | </ui> | ||
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index fbf96be03..5f6cdc0c6 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -101,6 +101,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual | |||
| 101 | #include "core/perf_stats.h" | 101 | #include "core/perf_stats.h" |
| 102 | #include "core/telemetry_session.h" | 102 | #include "core/telemetry_session.h" |
| 103 | #include "input_common/main.h" | 103 | #include "input_common/main.h" |
| 104 | #include "util/overlay_dialog.h" | ||
| 104 | #include "video_core/gpu.h" | 105 | #include "video_core/gpu.h" |
| 105 | #include "video_core/shader_notify.h" | 106 | #include "video_core/shader_notify.h" |
| 106 | #include "yuzu/about_dialog.h" | 107 | #include "yuzu/about_dialog.h" |
| @@ -227,6 +228,8 @@ GMainWindow::GMainWindow() | |||
| 227 | SetDiscordEnabled(UISettings::values.enable_discord_presence); | 228 | SetDiscordEnabled(UISettings::values.enable_discord_presence); |
| 228 | discord_rpc->Update(); | 229 | discord_rpc->Update(); |
| 229 | 230 | ||
| 231 | RegisterMetaTypes(); | ||
| 232 | |||
| 230 | InitializeWidgets(); | 233 | InitializeWidgets(); |
| 231 | InitializeDebugWidgets(); | 234 | InitializeDebugWidgets(); |
| 232 | InitializeRecentFileMenuActions(); | 235 | InitializeRecentFileMenuActions(); |
| @@ -375,6 +378,55 @@ GMainWindow::~GMainWindow() { | |||
| 375 | delete render_window; | 378 | delete render_window; |
| 376 | } | 379 | } |
| 377 | 380 | ||
| 381 | void GMainWindow::RegisterMetaTypes() { | ||
| 382 | // Register integral and floating point types | ||
| 383 | qRegisterMetaType<u8>("u8"); | ||
| 384 | qRegisterMetaType<u16>("u16"); | ||
| 385 | qRegisterMetaType<u32>("u32"); | ||
| 386 | qRegisterMetaType<u64>("u64"); | ||
| 387 | qRegisterMetaType<u128>("u128"); | ||
| 388 | qRegisterMetaType<s8>("s8"); | ||
| 389 | qRegisterMetaType<s16>("s16"); | ||
| 390 | qRegisterMetaType<s32>("s32"); | ||
| 391 | qRegisterMetaType<s64>("s64"); | ||
| 392 | qRegisterMetaType<f32>("f32"); | ||
| 393 | qRegisterMetaType<f64>("f64"); | ||
| 394 | |||
| 395 | // Register string types | ||
| 396 | qRegisterMetaType<std::string>("std::string"); | ||
| 397 | qRegisterMetaType<std::wstring>("std::wstring"); | ||
| 398 | qRegisterMetaType<std::u8string>("std::u8string"); | ||
| 399 | qRegisterMetaType<std::u16string>("std::u16string"); | ||
| 400 | qRegisterMetaType<std::u32string>("std::u32string"); | ||
| 401 | qRegisterMetaType<std::string_view>("std::string_view"); | ||
| 402 | qRegisterMetaType<std::wstring_view>("std::wstring_view"); | ||
| 403 | qRegisterMetaType<std::u8string_view>("std::u8string_view"); | ||
| 404 | qRegisterMetaType<std::u16string_view>("std::u16string_view"); | ||
| 405 | qRegisterMetaType<std::u32string_view>("std::u32string_view"); | ||
| 406 | |||
| 407 | // Register applet types | ||
| 408 | |||
| 409 | // Controller Applet | ||
| 410 | qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters"); | ||
| 411 | |||
| 412 | // Software Keyboard Applet | ||
| 413 | qRegisterMetaType<Core::Frontend::KeyboardInitializeParameters>( | ||
| 414 | "Core::Frontend::KeyboardInitializeParameters"); | ||
| 415 | qRegisterMetaType<Core::Frontend::InlineAppearParameters>( | ||
| 416 | "Core::Frontend::InlineAppearParameters"); | ||
| 417 | qRegisterMetaType<Core::Frontend::InlineTextParameters>("Core::Frontend::InlineTextParameters"); | ||
| 418 | qRegisterMetaType<Service::AM::Applets::SwkbdResult>("Service::AM::Applets::SwkbdResult"); | ||
| 419 | qRegisterMetaType<Service::AM::Applets::SwkbdTextCheckResult>( | ||
| 420 | "Service::AM::Applets::SwkbdTextCheckResult"); | ||
| 421 | qRegisterMetaType<Service::AM::Applets::SwkbdReplyType>("Service::AM::Applets::SwkbdReplyType"); | ||
| 422 | |||
| 423 | // Web Browser Applet | ||
| 424 | qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason"); | ||
| 425 | |||
| 426 | // Register loader types | ||
| 427 | qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus"); | ||
| 428 | } | ||
| 429 | |||
| 378 | void GMainWindow::ControllerSelectorReconfigureControllers( | 430 | void GMainWindow::ControllerSelectorReconfigureControllers( |
| 379 | const Core::Frontend::ControllerParameters& parameters) { | 431 | const Core::Frontend::ControllerParameters& parameters) { |
| 380 | QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get()); | 432 | QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get()); |
| @@ -414,25 +466,112 @@ void GMainWindow::ProfileSelectorSelectProfile() { | |||
| 414 | emit ProfileSelectorFinishedSelection(uuid); | 466 | emit ProfileSelectorFinishedSelection(uuid); |
| 415 | } | 467 | } |
| 416 | 468 | ||
| 417 | void GMainWindow::SoftwareKeyboardGetText( | 469 | void GMainWindow::SoftwareKeyboardInitialize( |
| 418 | const Core::Frontend::SoftwareKeyboardParameters& parameters) { | 470 | bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) { |
| 419 | QtSoftwareKeyboardDialog dialog(this, parameters); | 471 | if (software_keyboard) { |
| 420 | dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | | 472 | LOG_ERROR(Frontend, "The software keyboard is already initialized!"); |
| 421 | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | | 473 | return; |
| 422 | Qt::WindowCloseButtonHint); | 474 | } |
| 423 | dialog.setWindowModality(Qt::WindowModal); | ||
| 424 | 475 | ||
| 425 | if (dialog.exec() == QDialog::Rejected) { | 476 | software_keyboard = new QtSoftwareKeyboardDialog(render_window, Core::System::GetInstance(), |
| 426 | emit SoftwareKeyboardFinishedText(std::nullopt); | 477 | is_inline, std::move(initialize_parameters)); |
| 478 | |||
| 479 | if (is_inline) { | ||
| 480 | connect( | ||
| 481 | software_keyboard, &QtSoftwareKeyboardDialog::SubmitInlineText, this, | ||
| 482 | [this](Service::AM::Applets::SwkbdReplyType reply_type, std::u16string submitted_text, | ||
| 483 | s32 cursor_position) { | ||
| 484 | emit SoftwareKeyboardSubmitInlineText(reply_type, submitted_text, cursor_position); | ||
| 485 | }, | ||
| 486 | Qt::QueuedConnection); | ||
| 487 | } else { | ||
| 488 | connect( | ||
| 489 | software_keyboard, &QtSoftwareKeyboardDialog::SubmitNormalText, this, | ||
| 490 | [this](Service::AM::Applets::SwkbdResult result, std::u16string submitted_text) { | ||
| 491 | emit SoftwareKeyboardSubmitNormalText(result, submitted_text); | ||
| 492 | }, | ||
| 493 | Qt::QueuedConnection); | ||
| 494 | } | ||
| 495 | } | ||
| 496 | |||
| 497 | void GMainWindow::SoftwareKeyboardShowNormal() { | ||
| 498 | if (!software_keyboard) { | ||
| 499 | LOG_ERROR(Frontend, "The software keyboard is not initialized!"); | ||
| 427 | return; | 500 | return; |
| 428 | } | 501 | } |
| 429 | 502 | ||
| 430 | emit SoftwareKeyboardFinishedText(dialog.GetText()); | 503 | const auto& layout = render_window->GetFramebufferLayout(); |
| 504 | |||
| 505 | const auto x = layout.screen.left; | ||
| 506 | const auto y = layout.screen.top; | ||
| 507 | const auto w = layout.screen.GetWidth(); | ||
| 508 | const auto h = layout.screen.GetHeight(); | ||
| 509 | |||
| 510 | software_keyboard->ShowNormalKeyboard(render_window->mapToGlobal(QPoint(x, y)), QSize(w, h)); | ||
| 431 | } | 511 | } |
| 432 | 512 | ||
| 433 | void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message) { | 513 | void GMainWindow::SoftwareKeyboardShowTextCheck( |
| 434 | QMessageBox::warning(this, tr("Text Check Failed"), QString::fromStdU16String(error_message)); | 514 | Service::AM::Applets::SwkbdTextCheckResult text_check_result, |
| 435 | emit SoftwareKeyboardFinishedCheckDialog(); | 515 | std::u16string text_check_message) { |
| 516 | if (!software_keyboard) { | ||
| 517 | LOG_ERROR(Frontend, "The software keyboard is not initialized!"); | ||
| 518 | return; | ||
| 519 | } | ||
| 520 | |||
| 521 | software_keyboard->ShowTextCheckDialog(text_check_result, text_check_message); | ||
| 522 | } | ||
| 523 | |||
| 524 | void GMainWindow::SoftwareKeyboardShowInline( | ||
| 525 | Core::Frontend::InlineAppearParameters appear_parameters) { | ||
| 526 | if (!software_keyboard) { | ||
| 527 | LOG_ERROR(Frontend, "The software keyboard is not initialized!"); | ||
| 528 | return; | ||
| 529 | } | ||
| 530 | |||
| 531 | const auto& layout = render_window->GetFramebufferLayout(); | ||
| 532 | |||
| 533 | const auto x = | ||
| 534 | static_cast<int>(layout.screen.left + (0.5f * layout.screen.GetWidth() * | ||
| 535 | ((2.0f * appear_parameters.key_top_translate_x) + | ||
| 536 | (1.0f - appear_parameters.key_top_scale_x)))); | ||
| 537 | const auto y = | ||
| 538 | static_cast<int>(layout.screen.top + (layout.screen.GetHeight() * | ||
| 539 | ((2.0f * appear_parameters.key_top_translate_y) + | ||
| 540 | (1.0f - appear_parameters.key_top_scale_y)))); | ||
| 541 | const auto w = static_cast<int>(layout.screen.GetWidth() * appear_parameters.key_top_scale_x); | ||
| 542 | const auto h = static_cast<int>(layout.screen.GetHeight() * appear_parameters.key_top_scale_y); | ||
| 543 | |||
| 544 | software_keyboard->ShowInlineKeyboard(std::move(appear_parameters), | ||
| 545 | render_window->mapToGlobal(QPoint(x, y)), QSize(w, h)); | ||
| 546 | } | ||
| 547 | |||
| 548 | void GMainWindow::SoftwareKeyboardHideInline() { | ||
| 549 | if (!software_keyboard) { | ||
| 550 | LOG_ERROR(Frontend, "The software keyboard is not initialized!"); | ||
| 551 | return; | ||
| 552 | } | ||
| 553 | |||
| 554 | software_keyboard->HideInlineKeyboard(); | ||
| 555 | } | ||
| 556 | |||
| 557 | void GMainWindow::SoftwareKeyboardInlineTextChanged( | ||
| 558 | Core::Frontend::InlineTextParameters text_parameters) { | ||
| 559 | if (!software_keyboard) { | ||
| 560 | LOG_ERROR(Frontend, "The software keyboard is not initialized!"); | ||
| 561 | return; | ||
| 562 | } | ||
| 563 | |||
| 564 | software_keyboard->InlineTextChanged(std::move(text_parameters)); | ||
| 565 | } | ||
| 566 | |||
| 567 | void GMainWindow::SoftwareKeyboardExit() { | ||
| 568 | if (!software_keyboard) { | ||
| 569 | return; | ||
| 570 | } | ||
| 571 | |||
| 572 | software_keyboard->ExitKeyboard(); | ||
| 573 | |||
| 574 | software_keyboard = nullptr; | ||
| 436 | } | 575 | } |
| 437 | 576 | ||
| 438 | void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args, | 577 | void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args, |
| @@ -978,6 +1117,10 @@ void GMainWindow::ConnectWidgetEvents() { | |||
| 978 | connect(this, &GMainWindow::EmulationStopping, render_window, | 1117 | connect(this, &GMainWindow::EmulationStopping, render_window, |
| 979 | &GRenderWindow::OnEmulationStopping); | 1118 | &GRenderWindow::OnEmulationStopping); |
| 980 | 1119 | ||
| 1120 | // Software Keyboard Applet | ||
| 1121 | connect(this, &GMainWindow::EmulationStarting, this, &GMainWindow::SoftwareKeyboardExit); | ||
| 1122 | connect(this, &GMainWindow::EmulationStopping, this, &GMainWindow::SoftwareKeyboardExit); | ||
| 1123 | |||
| 981 | connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar); | 1124 | connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar); |
| 982 | } | 1125 | } |
| 983 | 1126 | ||
| @@ -2187,15 +2330,6 @@ void GMainWindow::OnStartGame() { | |||
| 2187 | 2330 | ||
| 2188 | emu_thread->SetRunning(true); | 2331 | emu_thread->SetRunning(true); |
| 2189 | 2332 | ||
| 2190 | qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters"); | ||
| 2191 | qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>( | ||
| 2192 | "Core::Frontend::SoftwareKeyboardParameters"); | ||
| 2193 | qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus"); | ||
| 2194 | qRegisterMetaType<std::string>("std::string"); | ||
| 2195 | qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>"); | ||
| 2196 | qRegisterMetaType<std::string_view>("std::string_view"); | ||
| 2197 | qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason"); | ||
| 2198 | |||
| 2199 | connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); | 2333 | connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); |
| 2200 | 2334 | ||
| 2201 | ui.action_Start->setEnabled(false); | 2335 | ui.action_Start->setEnabled(false); |
| @@ -2244,8 +2378,11 @@ void GMainWindow::OnExecuteProgram(std::size_t program_index) { | |||
| 2244 | BootGame(last_filename_booted, program_index); | 2378 | BootGame(last_filename_booted, program_index); |
| 2245 | } | 2379 | } |
| 2246 | 2380 | ||
| 2247 | void GMainWindow::ErrorDisplayDisplayError(QString body) { | 2381 | void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { |
| 2248 | QMessageBox::critical(this, tr("Error Display"), body); | 2382 | OverlayDialog dialog(render_window, Core::System::GetInstance(), error_code, error_text, |
| 2383 | QString{}, tr("OK"), Qt::AlignLeft | Qt::AlignVCenter); | ||
| 2384 | dialog.exec(); | ||
| 2385 | |||
| 2249 | emit ErrorDisplayFinished(); | 2386 | emit ErrorDisplayFinished(); |
| 2250 | } | 2387 | } |
| 2251 | 2388 | ||
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 04d37d4ae..7f1e50a5b 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -37,9 +37,13 @@ enum class GameListRemoveTarget; | |||
| 37 | enum class InstalledEntryType; | 37 | enum class InstalledEntryType; |
| 38 | class GameListPlaceholder; | 38 | class GameListPlaceholder; |
| 39 | 39 | ||
| 40 | class QtSoftwareKeyboardDialog; | ||
| 41 | |||
| 40 | namespace Core::Frontend { | 42 | namespace Core::Frontend { |
| 41 | struct ControllerParameters; | 43 | struct ControllerParameters; |
| 42 | struct SoftwareKeyboardParameters; | 44 | struct InlineAppearParameters; |
| 45 | struct InlineTextParameters; | ||
| 46 | struct KeyboardInitializeParameters; | ||
| 43 | } // namespace Core::Frontend | 47 | } // namespace Core::Frontend |
| 44 | 48 | ||
| 45 | namespace DiscordRPC { | 49 | namespace DiscordRPC { |
| @@ -57,8 +61,11 @@ class InputSubsystem; | |||
| 57 | } | 61 | } |
| 58 | 62 | ||
| 59 | namespace Service::AM::Applets { | 63 | namespace Service::AM::Applets { |
| 64 | enum class SwkbdResult : u32; | ||
| 65 | enum class SwkbdTextCheckResult : u32; | ||
| 66 | enum class SwkbdReplyType : u32; | ||
| 60 | enum class WebExitReason : u32; | 67 | enum class WebExitReason : u32; |
| 61 | } | 68 | } // namespace Service::AM::Applets |
| 62 | 69 | ||
| 63 | enum class EmulatedDirectoryTarget { | 70 | enum class EmulatedDirectoryTarget { |
| 64 | NAND, | 71 | NAND, |
| @@ -128,8 +135,10 @@ signals: | |||
| 128 | 135 | ||
| 129 | void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid); | 136 | void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid); |
| 130 | 137 | ||
| 131 | void SoftwareKeyboardFinishedText(std::optional<std::u16string> text); | 138 | void SoftwareKeyboardSubmitNormalText(Service::AM::Applets::SwkbdResult result, |
| 132 | void SoftwareKeyboardFinishedCheckDialog(); | 139 | std::u16string submitted_text); |
| 140 | void SoftwareKeyboardSubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, | ||
| 141 | std::u16string submitted_text, s32 cursor_position); | ||
| 133 | 142 | ||
| 134 | void WebBrowserExtractOfflineRomFS(); | 143 | void WebBrowserExtractOfflineRomFS(); |
| 135 | void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url); | 144 | void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url); |
| @@ -139,15 +148,24 @@ public slots: | |||
| 139 | void OnExecuteProgram(std::size_t program_index); | 148 | void OnExecuteProgram(std::size_t program_index); |
| 140 | void ControllerSelectorReconfigureControllers( | 149 | void ControllerSelectorReconfigureControllers( |
| 141 | const Core::Frontend::ControllerParameters& parameters); | 150 | const Core::Frontend::ControllerParameters& parameters); |
| 142 | void ErrorDisplayDisplayError(QString body); | 151 | void SoftwareKeyboardInitialize( |
| 152 | bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters); | ||
| 153 | void SoftwareKeyboardShowNormal(); | ||
| 154 | void SoftwareKeyboardShowTextCheck(Service::AM::Applets::SwkbdTextCheckResult text_check_result, | ||
| 155 | std::u16string text_check_message); | ||
| 156 | void SoftwareKeyboardShowInline(Core::Frontend::InlineAppearParameters appear_parameters); | ||
| 157 | void SoftwareKeyboardHideInline(); | ||
| 158 | void SoftwareKeyboardInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters); | ||
| 159 | void SoftwareKeyboardExit(); | ||
| 160 | void ErrorDisplayDisplayError(QString error_code, QString error_text); | ||
| 143 | void ProfileSelectorSelectProfile(); | 161 | void ProfileSelectorSelectProfile(); |
| 144 | void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); | ||
| 145 | void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message); | ||
| 146 | void WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args, | 162 | void WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args, |
| 147 | bool is_local); | 163 | bool is_local); |
| 148 | void OnAppFocusStateChanged(Qt::ApplicationState state); | 164 | void OnAppFocusStateChanged(Qt::ApplicationState state); |
| 149 | 165 | ||
| 150 | private: | 166 | private: |
| 167 | void RegisterMetaTypes(); | ||
| 168 | |||
| 151 | void InitializeWidgets(); | 169 | void InitializeWidgets(); |
| 152 | void InitializeDebugWidgets(); | 170 | void InitializeDebugWidgets(); |
| 153 | void InitializeRecentFileMenuActions(); | 171 | void InitializeRecentFileMenuActions(); |
| @@ -334,6 +352,9 @@ private: | |||
| 334 | // Disables the web applet for the rest of the emulated session | 352 | // Disables the web applet for the rest of the emulated session |
| 335 | bool disable_web_applet{}; | 353 | bool disable_web_applet{}; |
| 336 | 354 | ||
| 355 | // Applets | ||
| 356 | QtSoftwareKeyboardDialog* software_keyboard = nullptr; | ||
| 357 | |||
| 337 | protected: | 358 | protected: |
| 338 | void dropEvent(QDropEvent* event) override; | 359 | void dropEvent(QDropEvent* event) override; |
| 339 | void dragEnterEvent(QDragEnterEvent* event) override; | 360 | void dragEnterEvent(QDragEnterEvent* event) override; |
diff --git a/src/yuzu/util/overlay_dialog.cpp b/src/yuzu/util/overlay_dialog.cpp new file mode 100644 index 000000000..95b148545 --- /dev/null +++ b/src/yuzu/util/overlay_dialog.cpp | |||
| @@ -0,0 +1,249 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <QKeyEvent> | ||
| 6 | #include <QScreen> | ||
| 7 | |||
| 8 | #include "core/core.h" | ||
| 9 | #include "core/frontend/input_interpreter.h" | ||
| 10 | #include "ui_overlay_dialog.h" | ||
| 11 | #include "yuzu/util/overlay_dialog.h" | ||
| 12 | |||
| 13 | namespace { | ||
| 14 | |||
| 15 | constexpr float BASE_TITLE_FONT_SIZE = 14.0f; | ||
| 16 | constexpr float BASE_FONT_SIZE = 18.0f; | ||
| 17 | constexpr float BASE_WIDTH = 1280.0f; | ||
| 18 | constexpr float BASE_HEIGHT = 720.0f; | ||
| 19 | |||
| 20 | } // Anonymous namespace | ||
| 21 | |||
| 22 | OverlayDialog::OverlayDialog(QWidget* parent, Core::System& system, const QString& title_text, | ||
| 23 | const QString& body_text, const QString& left_button_text, | ||
| 24 | const QString& right_button_text, Qt::Alignment alignment, | ||
| 25 | bool use_rich_text_) | ||
| 26 | : QDialog(parent), ui{std::make_unique<Ui::OverlayDialog>()}, use_rich_text{use_rich_text_} { | ||
| 27 | ui->setupUi(this); | ||
| 28 | |||
| 29 | setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowTitleHint | | ||
| 30 | Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint); | ||
| 31 | setWindowModality(Qt::WindowModal); | ||
| 32 | setAttribute(Qt::WA_TranslucentBackground); | ||
| 33 | |||
| 34 | if (use_rich_text) { | ||
| 35 | InitializeRichTextDialog(title_text, body_text, left_button_text, right_button_text, | ||
| 36 | alignment); | ||
| 37 | } else { | ||
| 38 | InitializeRegularTextDialog(title_text, body_text, left_button_text, right_button_text, | ||
| 39 | alignment); | ||
| 40 | } | ||
| 41 | |||
| 42 | MoveAndResizeWindow(); | ||
| 43 | |||
| 44 | // TODO (Morph): Remove this when InputInterpreter no longer relies on the HID backend | ||
| 45 | if (system.IsPoweredOn()) { | ||
| 46 | input_interpreter = std::make_unique<InputInterpreter>(system); | ||
| 47 | |||
| 48 | StartInputThread(); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | OverlayDialog::~OverlayDialog() { | ||
| 53 | StopInputThread(); | ||
| 54 | } | ||
| 55 | |||
| 56 | void OverlayDialog::InitializeRegularTextDialog(const QString& title_text, const QString& body_text, | ||
| 57 | const QString& left_button_text, | ||
| 58 | const QString& right_button_text, | ||
| 59 | Qt::Alignment alignment) { | ||
| 60 | ui->stackedDialog->setCurrentIndex(0); | ||
| 61 | |||
| 62 | ui->label_title->setText(title_text); | ||
| 63 | ui->label_dialog->setText(body_text); | ||
| 64 | ui->button_cancel->setText(left_button_text); | ||
| 65 | ui->button_ok_label->setText(right_button_text); | ||
| 66 | |||
| 67 | ui->label_dialog->setAlignment(alignment); | ||
| 68 | |||
| 69 | if (title_text.isEmpty()) { | ||
| 70 | ui->label_title->hide(); | ||
| 71 | ui->verticalLayout_2->setStretch(0, 0); | ||
| 72 | ui->verticalLayout_2->setStretch(1, 219); | ||
| 73 | ui->verticalLayout_2->setStretch(2, 82); | ||
| 74 | } | ||
| 75 | |||
| 76 | if (left_button_text.isEmpty()) { | ||
| 77 | ui->button_cancel->hide(); | ||
| 78 | ui->button_cancel->setEnabled(false); | ||
| 79 | } | ||
| 80 | |||
| 81 | if (right_button_text.isEmpty()) { | ||
| 82 | ui->button_ok_label->hide(); | ||
| 83 | ui->button_ok_label->setEnabled(false); | ||
| 84 | } | ||
| 85 | |||
| 86 | connect( | ||
| 87 | ui->button_cancel, &QPushButton::clicked, this, | ||
| 88 | [this](bool) { | ||
| 89 | StopInputThread(); | ||
| 90 | QDialog::reject(); | ||
| 91 | }, | ||
| 92 | Qt::QueuedConnection); | ||
| 93 | connect( | ||
| 94 | ui->button_ok_label, &QPushButton::clicked, this, | ||
| 95 | [this](bool) { | ||
| 96 | StopInputThread(); | ||
| 97 | QDialog::accept(); | ||
| 98 | }, | ||
| 99 | Qt::QueuedConnection); | ||
| 100 | } | ||
| 101 | |||
| 102 | void OverlayDialog::InitializeRichTextDialog(const QString& title_text, const QString& body_text, | ||
| 103 | const QString& left_button_text, | ||
| 104 | const QString& right_button_text, | ||
| 105 | Qt::Alignment alignment) { | ||
| 106 | ui->stackedDialog->setCurrentIndex(1); | ||
| 107 | |||
| 108 | ui->label_title_rich->setText(title_text); | ||
| 109 | ui->text_browser_dialog->setText(body_text); | ||
| 110 | ui->button_cancel_rich->setText(left_button_text); | ||
| 111 | ui->button_ok_rich->setText(right_button_text); | ||
| 112 | |||
| 113 | // TODO (Morph/Rei): Replace this with something that works better | ||
| 114 | ui->text_browser_dialog->setAlignment(alignment); | ||
| 115 | |||
| 116 | if (title_text.isEmpty()) { | ||
| 117 | ui->label_title_rich->hide(); | ||
| 118 | ui->verticalLayout_3->setStretch(0, 0); | ||
| 119 | ui->verticalLayout_3->setStretch(1, 438); | ||
| 120 | ui->verticalLayout_3->setStretch(2, 82); | ||
| 121 | } | ||
| 122 | |||
| 123 | if (left_button_text.isEmpty()) { | ||
| 124 | ui->button_cancel_rich->hide(); | ||
| 125 | ui->button_cancel_rich->setEnabled(false); | ||
| 126 | } | ||
| 127 | |||
| 128 | if (right_button_text.isEmpty()) { | ||
| 129 | ui->button_ok_rich->hide(); | ||
| 130 | ui->button_ok_rich->setEnabled(false); | ||
| 131 | } | ||
| 132 | |||
| 133 | connect( | ||
| 134 | ui->button_cancel_rich, &QPushButton::clicked, this, | ||
| 135 | [this](bool) { | ||
| 136 | StopInputThread(); | ||
| 137 | QDialog::reject(); | ||
| 138 | }, | ||
| 139 | Qt::QueuedConnection); | ||
| 140 | connect( | ||
| 141 | ui->button_ok_rich, &QPushButton::clicked, this, | ||
| 142 | [this](bool) { | ||
| 143 | StopInputThread(); | ||
| 144 | QDialog::accept(); | ||
| 145 | }, | ||
| 146 | Qt::QueuedConnection); | ||
| 147 | } | ||
| 148 | |||
| 149 | void OverlayDialog::MoveAndResizeWindow() { | ||
| 150 | const auto pos = parentWidget()->mapToGlobal(parentWidget()->rect().topLeft()); | ||
| 151 | const auto width = static_cast<float>(parentWidget()->width()); | ||
| 152 | const auto height = static_cast<float>(parentWidget()->height()); | ||
| 153 | |||
| 154 | // High DPI | ||
| 155 | const float dpi_scale = qApp->screenAt(pos)->logicalDotsPerInch() / 96.0f; | ||
| 156 | |||
| 157 | const auto title_text_font_size = BASE_TITLE_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale; | ||
| 158 | const auto body_text_font_size = | ||
| 159 | BASE_FONT_SIZE * (((width / BASE_WIDTH) + (height / BASE_HEIGHT)) / 2.0f) / dpi_scale; | ||
| 160 | const auto button_text_font_size = BASE_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale; | ||
| 161 | |||
| 162 | QFont title_text_font(QStringLiteral("MS Shell Dlg 2"), title_text_font_size, QFont::Normal); | ||
| 163 | QFont body_text_font(QStringLiteral("MS Shell Dlg 2"), body_text_font_size, QFont::Normal); | ||
| 164 | QFont button_text_font(QStringLiteral("MS Shell Dlg 2"), button_text_font_size, QFont::Normal); | ||
| 165 | |||
| 166 | if (use_rich_text) { | ||
| 167 | ui->label_title_rich->setFont(title_text_font); | ||
| 168 | ui->text_browser_dialog->setFont(body_text_font); | ||
| 169 | ui->button_cancel_rich->setFont(button_text_font); | ||
| 170 | ui->button_ok_rich->setFont(button_text_font); | ||
| 171 | } else { | ||
| 172 | ui->label_title->setFont(title_text_font); | ||
| 173 | ui->label_dialog->setFont(body_text_font); | ||
| 174 | ui->button_cancel->setFont(button_text_font); | ||
| 175 | ui->button_ok_label->setFont(button_text_font); | ||
| 176 | } | ||
| 177 | |||
| 178 | QDialog::move(pos); | ||
| 179 | QDialog::resize(width, height); | ||
| 180 | } | ||
| 181 | |||
| 182 | template <HIDButton... T> | ||
| 183 | void OverlayDialog::HandleButtonPressedOnce() { | ||
| 184 | const auto f = [this](HIDButton button) { | ||
| 185 | if (input_interpreter->IsButtonPressedOnce(button)) { | ||
| 186 | TranslateButtonPress(button); | ||
| 187 | } | ||
| 188 | }; | ||
| 189 | |||
| 190 | (f(T), ...); | ||
| 191 | } | ||
| 192 | |||
| 193 | void OverlayDialog::TranslateButtonPress(HIDButton button) { | ||
| 194 | QPushButton* left_button = use_rich_text ? ui->button_cancel_rich : ui->button_cancel; | ||
| 195 | QPushButton* right_button = use_rich_text ? ui->button_ok_rich : ui->button_ok_label; | ||
| 196 | |||
| 197 | // TODO (Morph): Handle QTextBrowser text scrolling | ||
| 198 | // TODO (Morph): focusPrevious/NextChild() doesn't work well with the rich text dialog, fix it | ||
| 199 | |||
| 200 | switch (button) { | ||
| 201 | case HIDButton::A: | ||
| 202 | case HIDButton::B: | ||
| 203 | if (left_button->hasFocus()) { | ||
| 204 | left_button->click(); | ||
| 205 | } else if (right_button->hasFocus()) { | ||
| 206 | right_button->click(); | ||
| 207 | } | ||
| 208 | break; | ||
| 209 | case HIDButton::DLeft: | ||
| 210 | case HIDButton::LStickLeft: | ||
| 211 | focusPreviousChild(); | ||
| 212 | break; | ||
| 213 | case HIDButton::DRight: | ||
| 214 | case HIDButton::LStickRight: | ||
| 215 | focusNextChild(); | ||
| 216 | break; | ||
| 217 | default: | ||
| 218 | break; | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | void OverlayDialog::StartInputThread() { | ||
| 223 | if (input_thread_running) { | ||
| 224 | return; | ||
| 225 | } | ||
| 226 | |||
| 227 | input_thread_running = true; | ||
| 228 | |||
| 229 | input_thread = std::thread(&OverlayDialog::InputThread, this); | ||
| 230 | } | ||
| 231 | |||
| 232 | void OverlayDialog::StopInputThread() { | ||
| 233 | input_thread_running = false; | ||
| 234 | |||
| 235 | if (input_thread.joinable()) { | ||
| 236 | input_thread.join(); | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | void OverlayDialog::InputThread() { | ||
| 241 | while (input_thread_running) { | ||
| 242 | input_interpreter->PollInput(); | ||
| 243 | |||
| 244 | HandleButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::DLeft, HIDButton::DRight, | ||
| 245 | HIDButton::LStickLeft, HIDButton::LStickRight>(); | ||
| 246 | |||
| 247 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); | ||
| 248 | } | ||
| 249 | } | ||
diff --git a/src/yuzu/util/overlay_dialog.h b/src/yuzu/util/overlay_dialog.h new file mode 100644 index 000000000..e8c388bd0 --- /dev/null +++ b/src/yuzu/util/overlay_dialog.h | |||
| @@ -0,0 +1,107 @@ | |||
| 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 | #include <atomic> | ||
| 9 | #include <memory> | ||
| 10 | #include <thread> | ||
| 11 | |||
| 12 | #include <QDialog> | ||
| 13 | |||
| 14 | #include "common/common_types.h" | ||
| 15 | |||
| 16 | enum class HIDButton : u8; | ||
| 17 | |||
| 18 | class InputInterpreter; | ||
| 19 | |||
| 20 | namespace Core { | ||
| 21 | class System; | ||
| 22 | } | ||
| 23 | |||
| 24 | namespace Ui { | ||
| 25 | class OverlayDialog; | ||
| 26 | } | ||
| 27 | |||
| 28 | /** | ||
| 29 | * An OverlayDialog is an interactive dialog that accepts controller input (while a game is running) | ||
| 30 | * This dialog attempts to replicate the look and feel of the Nintendo Switch's overlay dialogs and | ||
| 31 | * provide some extra features such as embedding HTML/Rich Text content in a QTextBrowser. | ||
| 32 | * The OverlayDialog provides 2 modes: one to embed regular text into a QLabel and another to embed | ||
| 33 | * HTML/Rich Text content into a QTextBrowser. | ||
| 34 | */ | ||
| 35 | class OverlayDialog final : public QDialog { | ||
| 36 | Q_OBJECT | ||
| 37 | |||
| 38 | public: | ||
| 39 | explicit OverlayDialog(QWidget* parent, Core::System& system, const QString& title_text, | ||
| 40 | const QString& body_text, const QString& left_button_text, | ||
| 41 | const QString& right_button_text, | ||
| 42 | Qt::Alignment alignment = Qt::AlignCenter, bool use_rich_text_ = false); | ||
| 43 | ~OverlayDialog() override; | ||
| 44 | |||
| 45 | private: | ||
| 46 | /** | ||
| 47 | * Initializes a text dialog with a QLabel storing text. | ||
| 48 | * Only use this for short text as the dialog buttons would be squashed with longer text. | ||
| 49 | * | ||
| 50 | * @param title_text Title text to be displayed | ||
| 51 | * @param body_text Main text to be displayed | ||
| 52 | * @param left_button_text Left button text. If empty, the button is hidden and disabled | ||
| 53 | * @param right_button_text Right button text. If empty, the button is hidden and disabled | ||
| 54 | * @param alignment Main text alignment | ||
| 55 | */ | ||
| 56 | void InitializeRegularTextDialog(const QString& title_text, const QString& body_text, | ||
| 57 | const QString& left_button_text, | ||
| 58 | const QString& right_button_text, Qt::Alignment alignment); | ||
| 59 | |||
| 60 | /** | ||
| 61 | * Initializes a text dialog with a QTextBrowser storing text. | ||
| 62 | * This is ideal for longer text or rich text content. A scrollbar is shown for longer text. | ||
| 63 | * | ||
| 64 | * @param title_text Title text to be displayed | ||
| 65 | * @param body_text Main text to be displayed | ||
| 66 | * @param left_button_text Left button text. If empty, the button is hidden and disabled | ||
| 67 | * @param right_button_text Right button text. If empty, the button is hidden and disabled | ||
| 68 | * @param alignment Main text alignment | ||
| 69 | */ | ||
| 70 | void InitializeRichTextDialog(const QString& title_text, const QString& body_text, | ||
| 71 | const QString& left_button_text, const QString& right_button_text, | ||
| 72 | Qt::Alignment alignment); | ||
| 73 | |||
| 74 | /// Moves and resizes the dialog to be fully overlayed on top of the parent window. | ||
| 75 | void MoveAndResizeWindow(); | ||
| 76 | |||
| 77 | /** | ||
| 78 | * Handles button presses and converts them into keyboard input. | ||
| 79 | * | ||
| 80 | * @tparam HIDButton The list of buttons that can be converted into keyboard input. | ||
| 81 | */ | ||
| 82 | template <HIDButton... T> | ||
| 83 | void HandleButtonPressedOnce(); | ||
| 84 | |||
| 85 | /** | ||
| 86 | * Translates a button press to focus or click either the left or right buttons. | ||
| 87 | * | ||
| 88 | * @param button The button press to process. | ||
| 89 | */ | ||
| 90 | void TranslateButtonPress(HIDButton button); | ||
| 91 | |||
| 92 | void StartInputThread(); | ||
| 93 | void StopInputThread(); | ||
| 94 | |||
| 95 | /// The thread where input is being polled and processed. | ||
| 96 | void InputThread(); | ||
| 97 | |||
| 98 | std::unique_ptr<Ui::OverlayDialog> ui; | ||
| 99 | |||
| 100 | bool use_rich_text; | ||
| 101 | |||
| 102 | std::unique_ptr<InputInterpreter> input_interpreter; | ||
| 103 | |||
| 104 | std::thread input_thread; | ||
| 105 | |||
| 106 | std::atomic<bool> input_thread_running{}; | ||
| 107 | }; | ||
diff --git a/src/yuzu/util/overlay_dialog.ui b/src/yuzu/util/overlay_dialog.ui new file mode 100644 index 000000000..278e2f219 --- /dev/null +++ b/src/yuzu/util/overlay_dialog.ui | |||
| @@ -0,0 +1,404 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>OverlayDialog</class> | ||
| 4 | <widget class="QDialog" name="OverlayDialog"> | ||
| 5 | <property name="geometry"> | ||
| 6 | <rect> | ||
| 7 | <x>0</x> | ||
| 8 | <y>0</y> | ||
| 9 | <width>1280</width> | ||
| 10 | <height>720</height> | ||
| 11 | </rect> | ||
| 12 | </property> | ||
| 13 | <property name="windowTitle"> | ||
| 14 | <string>Dialog</string> | ||
| 15 | </property> | ||
| 16 | <property name="styleSheet"> | ||
| 17 | <string notr="true"/> | ||
| 18 | </property> | ||
| 19 | <layout class="QVBoxLayout" name="verticalLayout"> | ||
| 20 | <property name="spacing"> | ||
| 21 | <number>0</number> | ||
| 22 | </property> | ||
| 23 | <property name="leftMargin"> | ||
| 24 | <number>0</number> | ||
| 25 | </property> | ||
| 26 | <property name="topMargin"> | ||
| 27 | <number>0</number> | ||
| 28 | </property> | ||
| 29 | <property name="rightMargin"> | ||
| 30 | <number>0</number> | ||
| 31 | </property> | ||
| 32 | <property name="bottomMargin"> | ||
| 33 | <number>0</number> | ||
| 34 | </property> | ||
| 35 | <item> | ||
| 36 | <widget class="QStackedWidget" name="stackedDialog"> | ||
| 37 | <property name="currentIndex"> | ||
| 38 | <number>0</number> | ||
| 39 | </property> | ||
| 40 | <widget class="QWidget" name="lineDialog"> | ||
| 41 | <layout class="QGridLayout" name="lineDialogGridLayout" rowstretch="210,300,210" columnstretch="250,780,250"> | ||
| 42 | <property name="leftMargin"> | ||
| 43 | <number>0</number> | ||
| 44 | </property> | ||
| 45 | <property name="topMargin"> | ||
| 46 | <number>0</number> | ||
| 47 | </property> | ||
| 48 | <property name="rightMargin"> | ||
| 49 | <number>0</number> | ||
| 50 | </property> | ||
| 51 | <property name="bottomMargin"> | ||
| 52 | <number>0</number> | ||
| 53 | </property> | ||
| 54 | <property name="spacing"> | ||
| 55 | <number>0</number> | ||
| 56 | </property> | ||
| 57 | <item row="1" column="1"> | ||
| 58 | <widget class="QWidget" name="contentDialog" native="true"> | ||
| 59 | <layout class="QVBoxLayout" name="verticalLayout_2" stretch="70,149,82"> | ||
| 60 | <property name="spacing"> | ||
| 61 | <number>0</number> | ||
| 62 | </property> | ||
| 63 | <property name="leftMargin"> | ||
| 64 | <number>0</number> | ||
| 65 | </property> | ||
| 66 | <property name="topMargin"> | ||
| 67 | <number>0</number> | ||
| 68 | </property> | ||
| 69 | <property name="rightMargin"> | ||
| 70 | <number>0</number> | ||
| 71 | </property> | ||
| 72 | <property name="bottomMargin"> | ||
| 73 | <number>0</number> | ||
| 74 | </property> | ||
| 75 | <item> | ||
| 76 | <widget class="QLabel" name="label_title"> | ||
| 77 | <property name="font"> | ||
| 78 | <font> | ||
| 79 | <pointsize>14</pointsize> | ||
| 80 | </font> | ||
| 81 | </property> | ||
| 82 | <property name="alignment"> | ||
| 83 | <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> | ||
| 84 | </property> | ||
| 85 | </widget> | ||
| 86 | </item> | ||
| 87 | <item> | ||
| 88 | <widget class="QLabel" name="label_dialog"> | ||
| 89 | <property name="font"> | ||
| 90 | <font> | ||
| 91 | <pointsize>18</pointsize> | ||
| 92 | </font> | ||
| 93 | </property> | ||
| 94 | <property name="alignment"> | ||
| 95 | <set>Qt::AlignCenter</set> | ||
| 96 | </property> | ||
| 97 | <property name="wordWrap"> | ||
| 98 | <bool>true</bool> | ||
| 99 | </property> | ||
| 100 | </widget> | ||
| 101 | </item> | ||
| 102 | <item> | ||
| 103 | <widget class="QWidget" name="buttonsDialog" native="true"> | ||
| 104 | <layout class="QHBoxLayout" name="horizontalLayout"> | ||
| 105 | <property name="spacing"> | ||
| 106 | <number>0</number> | ||
| 107 | </property> | ||
| 108 | <property name="leftMargin"> | ||
| 109 | <number>0</number> | ||
| 110 | </property> | ||
| 111 | <property name="topMargin"> | ||
| 112 | <number>0</number> | ||
| 113 | </property> | ||
| 114 | <property name="rightMargin"> | ||
| 115 | <number>0</number> | ||
| 116 | </property> | ||
| 117 | <property name="bottomMargin"> | ||
| 118 | <number>0</number> | ||
| 119 | </property> | ||
| 120 | <item> | ||
| 121 | <widget class="QPushButton" name="button_cancel"> | ||
| 122 | <property name="sizePolicy"> | ||
| 123 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 124 | <horstretch>0</horstretch> | ||
| 125 | <verstretch>0</verstretch> | ||
| 126 | </sizepolicy> | ||
| 127 | </property> | ||
| 128 | <property name="font"> | ||
| 129 | <font> | ||
| 130 | <pointsize>18</pointsize> | ||
| 131 | </font> | ||
| 132 | </property> | ||
| 133 | <property name="text"> | ||
| 134 | <string>Cancel</string> | ||
| 135 | </property> | ||
| 136 | </widget> | ||
| 137 | </item> | ||
| 138 | <item> | ||
| 139 | <widget class="QPushButton" name="button_ok_label"> | ||
| 140 | <property name="sizePolicy"> | ||
| 141 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 142 | <horstretch>0</horstretch> | ||
| 143 | <verstretch>0</verstretch> | ||
| 144 | </sizepolicy> | ||
| 145 | </property> | ||
| 146 | <property name="font"> | ||
| 147 | <font> | ||
| 148 | <pointsize>18</pointsize> | ||
| 149 | </font> | ||
| 150 | </property> | ||
| 151 | <property name="text"> | ||
| 152 | <string>OK</string> | ||
| 153 | </property> | ||
| 154 | </widget> | ||
| 155 | </item> | ||
| 156 | </layout> | ||
| 157 | </widget> | ||
| 158 | </item> | ||
| 159 | </layout> | ||
| 160 | </widget> | ||
| 161 | </item> | ||
| 162 | <item row="0" column="1"> | ||
| 163 | <spacer name="verticalSpacer"> | ||
| 164 | <property name="orientation"> | ||
| 165 | <enum>Qt::Vertical</enum> | ||
| 166 | </property> | ||
| 167 | <property name="sizeHint" stdset="0"> | ||
| 168 | <size> | ||
| 169 | <width>20</width> | ||
| 170 | <height>40</height> | ||
| 171 | </size> | ||
| 172 | </property> | ||
| 173 | </spacer> | ||
| 174 | </item> | ||
| 175 | <item row="1" column="0"> | ||
| 176 | <spacer name="horizontalSpacer"> | ||
| 177 | <property name="orientation"> | ||
| 178 | <enum>Qt::Horizontal</enum> | ||
| 179 | </property> | ||
| 180 | <property name="sizeHint" stdset="0"> | ||
| 181 | <size> | ||
| 182 | <width>40</width> | ||
| 183 | <height>20</height> | ||
| 184 | </size> | ||
| 185 | </property> | ||
| 186 | </spacer> | ||
| 187 | </item> | ||
| 188 | <item row="2" column="1"> | ||
| 189 | <spacer name="verticalSpacer_2"> | ||
| 190 | <property name="orientation"> | ||
| 191 | <enum>Qt::Vertical</enum> | ||
| 192 | </property> | ||
| 193 | <property name="sizeHint" stdset="0"> | ||
| 194 | <size> | ||
| 195 | <width>20</width> | ||
| 196 | <height>40</height> | ||
| 197 | </size> | ||
| 198 | </property> | ||
| 199 | </spacer> | ||
| 200 | </item> | ||
| 201 | <item row="1" column="2"> | ||
| 202 | <spacer name="horizontalSpacer_2"> | ||
| 203 | <property name="orientation"> | ||
| 204 | <enum>Qt::Horizontal</enum> | ||
| 205 | </property> | ||
| 206 | <property name="sizeHint" stdset="0"> | ||
| 207 | <size> | ||
| 208 | <width>40</width> | ||
| 209 | <height>20</height> | ||
| 210 | </size> | ||
| 211 | </property> | ||
| 212 | </spacer> | ||
| 213 | </item> | ||
| 214 | </layout> | ||
| 215 | </widget> | ||
| 216 | <widget class="QWidget" name="richDialog"> | ||
| 217 | <layout class="QGridLayout" name="richDialogGridLayout" rowstretch="100,520,100" columnstretch="165,950,165"> | ||
| 218 | <property name="leftMargin"> | ||
| 219 | <number>0</number> | ||
| 220 | </property> | ||
| 221 | <property name="topMargin"> | ||
| 222 | <number>0</number> | ||
| 223 | </property> | ||
| 224 | <property name="rightMargin"> | ||
| 225 | <number>0</number> | ||
| 226 | </property> | ||
| 227 | <property name="bottomMargin"> | ||
| 228 | <number>0</number> | ||
| 229 | </property> | ||
| 230 | <property name="spacing"> | ||
| 231 | <number>0</number> | ||
| 232 | </property> | ||
| 233 | <item row="1" column="0"> | ||
| 234 | <spacer name="horizontalSpacer_3"> | ||
| 235 | <property name="orientation"> | ||
| 236 | <enum>Qt::Horizontal</enum> | ||
| 237 | </property> | ||
| 238 | <property name="sizeHint" stdset="0"> | ||
| 239 | <size> | ||
| 240 | <width>40</width> | ||
| 241 | <height>20</height> | ||
| 242 | </size> | ||
| 243 | </property> | ||
| 244 | </spacer> | ||
| 245 | </item> | ||
| 246 | <item row="2" column="1"> | ||
| 247 | <spacer name="verticalSpacer_4"> | ||
| 248 | <property name="orientation"> | ||
| 249 | <enum>Qt::Vertical</enum> | ||
| 250 | </property> | ||
| 251 | <property name="sizeHint" stdset="0"> | ||
| 252 | <size> | ||
| 253 | <width>20</width> | ||
| 254 | <height>40</height> | ||
| 255 | </size> | ||
| 256 | </property> | ||
| 257 | </spacer> | ||
| 258 | </item> | ||
| 259 | <item row="0" column="1"> | ||
| 260 | <spacer name="verticalSpacer_3"> | ||
| 261 | <property name="orientation"> | ||
| 262 | <enum>Qt::Vertical</enum> | ||
| 263 | </property> | ||
| 264 | <property name="sizeHint" stdset="0"> | ||
| 265 | <size> | ||
| 266 | <width>20</width> | ||
| 267 | <height>40</height> | ||
| 268 | </size> | ||
| 269 | </property> | ||
| 270 | </spacer> | ||
| 271 | </item> | ||
| 272 | <item row="1" column="1"> | ||
| 273 | <widget class="QWidget" name="contentRichDialog" native="true"> | ||
| 274 | <layout class="QVBoxLayout" name="verticalLayout_3" stretch="70,368,82"> | ||
| 275 | <property name="spacing"> | ||
| 276 | <number>0</number> | ||
| 277 | </property> | ||
| 278 | <property name="leftMargin"> | ||
| 279 | <number>0</number> | ||
| 280 | </property> | ||
| 281 | <property name="topMargin"> | ||
| 282 | <number>0</number> | ||
| 283 | </property> | ||
| 284 | <property name="rightMargin"> | ||
| 285 | <number>0</number> | ||
| 286 | </property> | ||
| 287 | <property name="bottomMargin"> | ||
| 288 | <number>0</number> | ||
| 289 | </property> | ||
| 290 | <item> | ||
| 291 | <widget class="QLabel" name="label_title_rich"> | ||
| 292 | <property name="font"> | ||
| 293 | <font> | ||
| 294 | <pointsize>14</pointsize> | ||
| 295 | </font> | ||
| 296 | </property> | ||
| 297 | <property name="text"> | ||
| 298 | <string/> | ||
| 299 | </property> | ||
| 300 | <property name="alignment"> | ||
| 301 | <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> | ||
| 302 | </property> | ||
| 303 | </widget> | ||
| 304 | </item> | ||
| 305 | <item> | ||
| 306 | <widget class="QTextBrowser" name="text_browser_dialog"> | ||
| 307 | <property name="font"> | ||
| 308 | <font> | ||
| 309 | <pointsize>18</pointsize> | ||
| 310 | </font> | ||
| 311 | </property> | ||
| 312 | <property name="html"> | ||
| 313 | <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> | ||
| 314 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> | ||
| 315 | p, li { white-space: pre-wrap; } | ||
| 316 | </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:18pt; font-weight:400; font-style:normal;"> | ||
| 317 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string> | ||
| 318 | </property> | ||
| 319 | </widget> | ||
| 320 | </item> | ||
| 321 | <item> | ||
| 322 | <widget class="QWidget" name="buttonsRichDialog" native="true"> | ||
| 323 | <layout class="QHBoxLayout" name="horizontalLayout_2"> | ||
| 324 | <property name="spacing"> | ||
| 325 | <number>0</number> | ||
| 326 | </property> | ||
| 327 | <property name="leftMargin"> | ||
| 328 | <number>0</number> | ||
| 329 | </property> | ||
| 330 | <property name="topMargin"> | ||
| 331 | <number>0</number> | ||
| 332 | </property> | ||
| 333 | <property name="rightMargin"> | ||
| 334 | <number>0</number> | ||
| 335 | </property> | ||
| 336 | <property name="bottomMargin"> | ||
| 337 | <number>0</number> | ||
| 338 | </property> | ||
| 339 | <item> | ||
| 340 | <widget class="QPushButton" name="button_cancel_rich"> | ||
| 341 | <property name="sizePolicy"> | ||
| 342 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 343 | <horstretch>0</horstretch> | ||
| 344 | <verstretch>0</verstretch> | ||
| 345 | </sizepolicy> | ||
| 346 | </property> | ||
| 347 | <property name="font"> | ||
| 348 | <font> | ||
| 349 | <pointsize>18</pointsize> | ||
| 350 | </font> | ||
| 351 | </property> | ||
| 352 | <property name="text"> | ||
| 353 | <string>Cancel</string> | ||
| 354 | </property> | ||
| 355 | </widget> | ||
| 356 | </item> | ||
| 357 | <item> | ||
| 358 | <widget class="QPushButton" name="button_ok_rich"> | ||
| 359 | <property name="sizePolicy"> | ||
| 360 | <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| 361 | <horstretch>0</horstretch> | ||
| 362 | <verstretch>0</verstretch> | ||
| 363 | </sizepolicy> | ||
| 364 | </property> | ||
| 365 | <property name="font"> | ||
| 366 | <font> | ||
| 367 | <pointsize>18</pointsize> | ||
| 368 | </font> | ||
| 369 | </property> | ||
| 370 | <property name="text"> | ||
| 371 | <string>OK</string> | ||
| 372 | </property> | ||
| 373 | </widget> | ||
| 374 | </item> | ||
| 375 | </layout> | ||
| 376 | </widget> | ||
| 377 | </item> | ||
| 378 | </layout> | ||
| 379 | </widget> | ||
| 380 | </item> | ||
| 381 | <item row="1" column="2"> | ||
| 382 | <spacer name="horizontalSpacer_4"> | ||
| 383 | <property name="orientation"> | ||
| 384 | <enum>Qt::Horizontal</enum> | ||
| 385 | </property> | ||
| 386 | <property name="sizeHint" stdset="0"> | ||
| 387 | <size> | ||
| 388 | <width>40</width> | ||
| 389 | <height>20</height> | ||
| 390 | </size> | ||
| 391 | </property> | ||
| 392 | </spacer> | ||
| 393 | </item> | ||
| 394 | </layout> | ||
| 395 | </widget> | ||
| 396 | </widget> | ||
| 397 | </item> | ||
| 398 | </layout> | ||
| 399 | </widget> | ||
| 400 | <resources> | ||
| 401 | <include location="../../../dist/icons/overlay/overlay.qrc"/> | ||
| 402 | </resources> | ||
| 403 | <connections/> | ||
| 404 | </ui> | ||