qt_software_keyboard.h 8.9 KB

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