diff options
Diffstat (limited to 'src/yuzu/applets/qt_software_keyboard.h')
-rw-r--r-- | src/yuzu/applets/qt_software_keyboard.h | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/src/yuzu/applets/qt_software_keyboard.h b/src/yuzu/applets/qt_software_keyboard.h new file mode 100644 index 0000000000..1a03c098ce --- /dev/null +++ b/src/yuzu/applets/qt_software_keyboard.h @@ -0,0 +1,285 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <atomic> +#include <memory> +#include <thread> + +#include <QDialog> +#include <QValidator> + +#include "core/frontend/applets/software_keyboard.h" + +enum class HIDButton : u8; + +class InputInterpreter; + +namespace Core { +class System; +} + +namespace Ui { +class QtSoftwareKeyboardDialog; +} + +class GMainWindow; + +class QtSoftwareKeyboardDialog final : public QDialog { + Q_OBJECT + +public: + QtSoftwareKeyboardDialog(QWidget* parent, Core::System& system_, bool is_inline_, + Core::Frontend::KeyboardInitializeParameters initialize_parameters_); + ~QtSoftwareKeyboardDialog() override; + + void ShowNormalKeyboard(QPoint pos, QSize size); + + void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, + std::u16string text_check_message); + + void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos, + QSize size); + + void HideInlineKeyboard(); + + void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters); + + void ExitKeyboard(); + +signals: + void SubmitNormalText(Service::AM::Applets::SwkbdResult result, + std::u16string submitted_text) const; + + void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, + std::u16string submitted_text, s32 cursor_position) const; + +public slots: + void open() override; + void reject() override; + +protected: + /// We override the keyPressEvent for inputting text into the inline software keyboard. + void keyPressEvent(QKeyEvent* event) override; + +private: + enum class Direction { + Left, + Up, + Right, + Down, + }; + + enum class BottomOSKIndex { + LowerCase, + UpperCase, + NumberPad, + }; + + /** + * Moves and resizes the window to a specified position and size. + * + * @param pos Top-left window position + * @param size Window size + */ + void MoveAndResizeWindow(QPoint pos, QSize size); + + /** + * Rescales all keyboard elements to account for High DPI displays. + * + * @param width Window width + * @param height Window height + * @param dpi_scale Display scaling factor + */ + void RescaleKeyboardElements(float width, float height, float dpi_scale); + + /// Sets the keyboard type based on initialize_parameters. + void SetKeyboardType(); + + /// Sets the password mode based on initialize_parameters. + void SetPasswordMode(); + + /// Sets the text draw type based on initialize_parameters. + void SetTextDrawType(); + + /// Sets the controller image at the bottom left of the software keyboard. + void SetControllerImage(); + + /// Disables buttons based on initialize_parameters. + void DisableKeyboardButtons(); + + /// Changes whether the backspace or/and ok buttons should be enabled or disabled. + void SetBackspaceOkEnabled(); + + /** + * Validates the input text sent in based on the parameters in initialize_parameters. + * + * @param input_text Input text + * + * @returns True if the input text is valid, false otherwise. + */ + bool ValidateInputText(const QString& input_text); + + /// Switches between LowerCase and UpperCase (Shift and Caps Lock) + void ChangeBottomOSKIndex(); + + /// Processes a keyboard button click from the UI as normal keyboard input. + void NormalKeyboardButtonClicked(QPushButton* button); + + /// Processes a keyboard button click from the UI as inline keyboard input. + void InlineKeyboardButtonClicked(QPushButton* button); + + /** + * Inserts a string of arbitrary length into the current_text at the current cursor position. + * This is only used for the inline software keyboard. + */ + void InlineTextInsertString(std::u16string_view string); + + /// Setup the mouse hover workaround for "focusing" buttons. This should only be called once. + void SetupMouseHover(); + + /** + * Handles button presses and converts them into keyboard input. + * + * @tparam HIDButton The list of buttons that can be converted into keyboard input. + */ + template <HIDButton... T> + void HandleButtonPressedOnce(); + + /** + * Handles button holds and converts them into keyboard input. + * + * @tparam HIDButton The list of buttons that can be converted into keyboard input. + */ + template <HIDButton... T> + void HandleButtonHold(); + + /** + * Translates a button press to focus or click a keyboard button. + * + * @param button The button press to process. + */ + void TranslateButtonPress(HIDButton button); + + /** + * Moves the focus of a button in a certain direction. + * + * @param direction The direction to move. + */ + void MoveButtonDirection(Direction direction); + + /** + * Moves the text cursor in a certain direction. + * + * @param direction The direction to move. + */ + void MoveTextCursorDirection(Direction direction); + + void StartInputThread(); + void StopInputThread(); + + /// The thread where input is being polled and processed. + void InputThread(); + + std::unique_ptr<Ui::QtSoftwareKeyboardDialog> ui; + + Core::System& system; + + // True if it is the inline software keyboard. + bool is_inline; + + // Common software keyboard initialize parameters. + Core::Frontend::KeyboardInitializeParameters initialize_parameters; + + // Used only by the inline software keyboard since the QLineEdit or QTextEdit is hidden. + std::u16string current_text; + s32 cursor_position{0}; + + static constexpr std::size_t NUM_ROWS_NORMAL = 5; + static constexpr std::size_t NUM_COLUMNS_NORMAL = 12; + static constexpr std::size_t NUM_ROWS_NUMPAD = 4; + static constexpr std::size_t NUM_COLUMNS_NUMPAD = 4; + + // Stores the normal keyboard layout. + std::array<std::array<std::array<QPushButton*, NUM_COLUMNS_NORMAL>, NUM_ROWS_NORMAL>, 2> + keyboard_buttons; + // Stores the numberpad keyboard layout. + std::array<std::array<QPushButton*, NUM_COLUMNS_NUMPAD>, NUM_ROWS_NUMPAD> numberpad_buttons; + + // Contains a set of all buttons used in keyboard_buttons and numberpad_buttons. + std::array<QPushButton*, 110> all_buttons; + + std::size_t row{0}; + std::size_t column{0}; + + BottomOSKIndex bottom_osk_index{BottomOSKIndex::LowerCase}; + std::atomic<bool> caps_lock_enabled{false}; + + std::unique_ptr<InputInterpreter> input_interpreter; + + std::thread input_thread; + + std::atomic<bool> input_thread_running{}; +}; + +class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet { + Q_OBJECT + +public: + explicit QtSoftwareKeyboard(GMainWindow& parent); + ~QtSoftwareKeyboard() override; + + void InitializeKeyboard( + bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters, + std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> + submit_normal_callback_, + std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> + submit_inline_callback_) override; + + void ShowNormalKeyboard() const override; + + void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, + std::u16string text_check_message) const override; + + void ShowInlineKeyboard( + Core::Frontend::InlineAppearParameters appear_parameters) const override; + + void HideInlineKeyboard() const override; + + void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const override; + + void ExitKeyboard() const override; + +signals: + void MainWindowInitializeKeyboard( + bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) const; + + void MainWindowShowNormalKeyboard() const; + + void MainWindowShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, + std::u16string text_check_message) const; + + void MainWindowShowInlineKeyboard( + Core::Frontend::InlineAppearParameters appear_parameters) const; + + void MainWindowHideInlineKeyboard() const; + + void MainWindowInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const; + + void MainWindowExitKeyboard() const; + +private: + void SubmitNormalText(Service::AM::Applets::SwkbdResult result, + std::u16string submitted_text) const; + + void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, + std::u16string submitted_text, s32 cursor_position) const; + + mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> + submit_normal_callback; + mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> + submit_inline_callback; +}; |