qt_software_keyboard.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <array>
  5. #include <atomic>
  6. #include <memory>
  7. #include <thread>
  8. #include <QDialog>
  9. #include <QValidator>
  10. #include "core/frontend/applets/software_keyboard.h"
  11. class InputInterpreter;
  12. namespace Core {
  13. class System;
  14. }
  15. namespace Core::HID {
  16. enum class NpadButton : u64;
  17. }
  18. namespace Ui {
  19. class QtSoftwareKeyboardDialog;
  20. }
  21. class GMainWindow;
  22. class QtSoftwareKeyboardDialog final : public QDialog {
  23. Q_OBJECT
  24. public:
  25. QtSoftwareKeyboardDialog(QWidget* parent, Core::System& system_, bool is_inline_,
  26. Core::Frontend::KeyboardInitializeParameters initialize_parameters_);
  27. ~QtSoftwareKeyboardDialog() override;
  28. void ShowNormalKeyboard(QPoint pos, QSize size);
  29. void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
  30. std::u16string text_check_message);
  31. void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos,
  32. QSize size);
  33. void HideInlineKeyboard();
  34. void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters);
  35. void ExitKeyboard();
  36. signals:
  37. void SubmitNormalText(Service::AM::Applets::SwkbdResult result, std::u16string submitted_text,
  38. bool confirmed = false) const;
  39. void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
  40. std::u16string submitted_text, s32 cursor_position) const;
  41. public slots:
  42. void open() override;
  43. void reject() override;
  44. protected:
  45. /// We override the keyPressEvent for inputting text into the inline software keyboard.
  46. void keyPressEvent(QKeyEvent* event) override;
  47. private:
  48. enum class Direction {
  49. Left,
  50. Up,
  51. Right,
  52. Down,
  53. };
  54. enum class BottomOSKIndex {
  55. LowerCase,
  56. UpperCase,
  57. NumberPad,
  58. };
  59. /**
  60. * Moves and resizes the window to a specified position and size.
  61. *
  62. * @param pos Top-left window position
  63. * @param size Window size
  64. */
  65. void MoveAndResizeWindow(QPoint pos, QSize size);
  66. /**
  67. * Rescales all keyboard elements to account for High DPI displays.
  68. *
  69. * @param width Window width
  70. * @param height Window height
  71. * @param dpi_scale Display scaling factor
  72. */
  73. void RescaleKeyboardElements(float width, float height, float dpi_scale);
  74. /// Sets the keyboard type based on initialize_parameters.
  75. void SetKeyboardType();
  76. /// Sets the password mode based on initialize_parameters.
  77. void SetPasswordMode();
  78. /// Sets the text draw type based on initialize_parameters.
  79. void SetTextDrawType();
  80. /// Sets the controller image at the bottom left of the software keyboard.
  81. void SetControllerImage();
  82. /// Disables buttons based on initialize_parameters.
  83. void DisableKeyboardButtons();
  84. /// Changes whether the backspace or/and ok buttons should be enabled or disabled.
  85. void SetBackspaceOkEnabled();
  86. /**
  87. * Validates the input text sent in based on the parameters in initialize_parameters.
  88. *
  89. * @param input_text Input text
  90. *
  91. * @returns True if the input text is valid, false otherwise.
  92. */
  93. bool ValidateInputText(const QString& input_text);
  94. /// Switches between LowerCase and UpperCase (Shift and Caps Lock)
  95. void ChangeBottomOSKIndex();
  96. /// Processes a keyboard button click from the UI as normal keyboard input.
  97. void NormalKeyboardButtonClicked(QPushButton* button);
  98. /// Processes a keyboard button click from the UI as inline keyboard input.
  99. void InlineKeyboardButtonClicked(QPushButton* button);
  100. /**
  101. * Inserts a string of arbitrary length into the current_text at the current cursor position.
  102. * This is only used for the inline software keyboard.
  103. */
  104. void InlineTextInsertString(std::u16string_view string);
  105. /// Setup the mouse hover workaround for "focusing" buttons. This should only be called once.
  106. void SetupMouseHover();
  107. /**
  108. * Handles button presses and converts them into keyboard input.
  109. *
  110. * @tparam HIDButton The list of buttons that can be converted into keyboard input.
  111. */
  112. template <Core::HID::NpadButton... T>
  113. void HandleButtonPressedOnce();
  114. /**
  115. * Handles button holds and converts them into keyboard input.
  116. *
  117. * @tparam HIDButton The list of buttons that can be converted into keyboard input.
  118. */
  119. template <Core::HID::NpadButton... T>
  120. void HandleButtonHold();
  121. /**
  122. * Translates a button press to focus or click a keyboard button.
  123. *
  124. * @param button The button press to process.
  125. */
  126. void TranslateButtonPress(Core::HID::NpadButton button);
  127. /**
  128. * Moves the focus of a button in a certain direction.
  129. *
  130. * @param direction The direction to move.
  131. */
  132. void MoveButtonDirection(Direction direction);
  133. /**
  134. * Moves the text cursor in a certain direction.
  135. *
  136. * @param direction The direction to move.
  137. */
  138. void MoveTextCursorDirection(Direction direction);
  139. void StartInputThread();
  140. void StopInputThread();
  141. /// The thread where input is being polled and processed.
  142. void InputThread();
  143. std::unique_ptr<Ui::QtSoftwareKeyboardDialog> ui;
  144. Core::System& system;
  145. // True if it is the inline software keyboard.
  146. bool is_inline;
  147. // Common software keyboard initialize parameters.
  148. Core::Frontend::KeyboardInitializeParameters initialize_parameters;
  149. // Used only by the inline software keyboard since the QLineEdit or QTextEdit is hidden.
  150. std::u16string current_text;
  151. s32 cursor_position{0};
  152. static constexpr std::size_t NUM_ROWS_NORMAL = 5;
  153. static constexpr std::size_t NUM_COLUMNS_NORMAL = 12;
  154. static constexpr std::size_t NUM_ROWS_NUMPAD = 4;
  155. static constexpr std::size_t NUM_COLUMNS_NUMPAD = 4;
  156. // Stores the normal keyboard layout.
  157. std::array<std::array<std::array<QPushButton*, NUM_COLUMNS_NORMAL>, NUM_ROWS_NORMAL>, 2>
  158. keyboard_buttons;
  159. // Stores the numberpad keyboard layout.
  160. std::array<std::array<QPushButton*, NUM_COLUMNS_NUMPAD>, NUM_ROWS_NUMPAD> numberpad_buttons;
  161. // Contains a set of all buttons used in keyboard_buttons and numberpad_buttons.
  162. std::array<QPushButton*, 112> all_buttons;
  163. std::size_t row{0};
  164. std::size_t column{0};
  165. BottomOSKIndex bottom_osk_index{BottomOSKIndex::LowerCase};
  166. std::atomic<bool> caps_lock_enabled{false};
  167. std::unique_ptr<InputInterpreter> input_interpreter;
  168. std::thread input_thread;
  169. std::atomic<bool> input_thread_running{};
  170. };
  171. class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet {
  172. Q_OBJECT
  173. public:
  174. explicit QtSoftwareKeyboard(GMainWindow& parent);
  175. ~QtSoftwareKeyboard() override;
  176. void InitializeKeyboard(bool is_inline,
  177. Core::Frontend::KeyboardInitializeParameters initialize_parameters,
  178. SubmitNormalCallback submit_normal_callback_,
  179. SubmitInlineCallback submit_inline_callback_) override;
  180. void ShowNormalKeyboard() const override;
  181. void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
  182. std::u16string text_check_message) const override;
  183. void ShowInlineKeyboard(
  184. Core::Frontend::InlineAppearParameters appear_parameters) const override;
  185. void HideInlineKeyboard() const override;
  186. void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const override;
  187. void ExitKeyboard() const override;
  188. signals:
  189. void MainWindowInitializeKeyboard(
  190. bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) const;
  191. void MainWindowShowNormalKeyboard() const;
  192. void MainWindowShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
  193. std::u16string text_check_message) const;
  194. void MainWindowShowInlineKeyboard(
  195. Core::Frontend::InlineAppearParameters appear_parameters) const;
  196. void MainWindowHideInlineKeyboard() const;
  197. void MainWindowInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const;
  198. void MainWindowExitKeyboard() const;
  199. private:
  200. void SubmitNormalText(Service::AM::Applets::SwkbdResult result, std::u16string submitted_text,
  201. bool confirmed) const;
  202. void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
  203. std::u16string submitted_text, s32 cursor_position) const;
  204. mutable SubmitNormalCallback submit_normal_callback;
  205. mutable SubmitInlineCallback submit_inline_callback;
  206. };