2022-04-23 10:59:50 +02:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2018-11-10 02:13:15 +01:00
|
|
|
|
|
|
|
#pragma once
|
2018-11-11 22:39:25 +01:00
|
|
|
|
2021-03-27 20:15:32 +01:00
|
|
|
#include <array>
|
|
|
|
#include <atomic>
|
|
|
|
#include <memory>
|
|
|
|
#include <thread>
|
|
|
|
|
2018-11-10 02:13:15 +01:00
|
|
|
#include <QDialog>
|
|
|
|
#include <QValidator>
|
2021-01-30 20:38:00 +01:00
|
|
|
|
2018-11-10 02:13:15 +01:00
|
|
|
#include "core/frontend/applets/software_keyboard.h"
|
|
|
|
|
2021-03-27 20:15:32 +01:00
|
|
|
class InputInterpreter;
|
|
|
|
|
|
|
|
namespace Core {
|
|
|
|
class System;
|
|
|
|
}
|
|
|
|
|
2021-09-21 03:19:28 +02:00
|
|
|
namespace Core::HID {
|
|
|
|
enum class NpadButton : u64;
|
|
|
|
}
|
|
|
|
|
2021-03-27 20:15:32 +01:00
|
|
|
namespace Ui {
|
|
|
|
class QtSoftwareKeyboardDialog;
|
|
|
|
}
|
|
|
|
|
|
|
|
class GMainWindow;
|
2018-11-10 02:13:15 +01:00
|
|
|
|
|
|
|
class QtSoftwareKeyboardDialog final : public QDialog {
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
2021-03-27 20:15:32 +01:00
|
|
|
QtSoftwareKeyboardDialog(QWidget* parent, Core::System& system_, bool is_inline_,
|
|
|
|
Core::Frontend::KeyboardInitializeParameters initialize_parameters_);
|
2018-11-11 22:39:25 +01:00
|
|
|
~QtSoftwareKeyboardDialog() override;
|
2021-03-27 20:15:32 +01:00
|
|
|
|
|
|
|
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:
|
2021-11-08 19:05:50 +01:00
|
|
|
void SubmitNormalText(Service::AM::Applets::SwkbdResult result, std::u16string submitted_text,
|
|
|
|
bool confirmed = false) const;
|
2021-03-27 20:15:32 +01:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2021-09-21 03:19:28 +02:00
|
|
|
template <Core::HID::NpadButton... T>
|
2021-03-27 20:15:32 +01:00
|
|
|
void HandleButtonPressedOnce();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handles button holds and converts them into keyboard input.
|
|
|
|
*
|
|
|
|
* @tparam HIDButton The list of buttons that can be converted into keyboard input.
|
|
|
|
*/
|
2021-09-21 03:19:28 +02:00
|
|
|
template <Core::HID::NpadButton... T>
|
2021-03-27 20:15:32 +01:00
|
|
|
void HandleButtonHold();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Translates a button press to focus or click a keyboard button.
|
|
|
|
*
|
|
|
|
* @param button The button press to process.
|
|
|
|
*/
|
2021-09-21 03:19:28 +02:00
|
|
|
void TranslateButtonPress(Core::HID::NpadButton button);
|
2021-03-27 20:15:32 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
2022-07-24 13:21:02 +02:00
|
|
|
std::array<QPushButton*, 112> all_buttons;
|
2021-03-27 20:15:32 +01:00
|
|
|
|
|
|
|
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{};
|
2018-11-10 02:13:15 +01:00
|
|
|
};
|
|
|
|
|
2018-11-11 22:39:25 +01:00
|
|
|
class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet {
|
2018-11-12 17:08:09 +01:00
|
|
|
Q_OBJECT
|
|
|
|
|
2018-11-10 02:13:15 +01:00
|
|
|
public:
|
2018-11-11 22:39:25 +01:00
|
|
|
explicit QtSoftwareKeyboard(GMainWindow& parent);
|
|
|
|
~QtSoftwareKeyboard() override;
|
2021-03-27 20:15:32 +01:00
|
|
|
|
|
|
|
void InitializeKeyboard(
|
|
|
|
bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters,
|
2021-11-08 19:05:50 +01:00
|
|
|
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
|
2021-03-27 20:15:32 +01:00
|
|
|
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:
|
2021-11-08 19:05:50 +01:00
|
|
|
void SubmitNormalText(Service::AM::Applets::SwkbdResult result, std::u16string submitted_text,
|
|
|
|
bool confirmed) const;
|
2021-03-27 20:15:32 +01:00
|
|
|
|
|
|
|
void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
|
|
|
|
std::u16string submitted_text, s32 cursor_position) const;
|
|
|
|
|
2021-11-08 19:05:50 +01:00
|
|
|
mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
|
2021-03-27 20:15:32 +01:00
|
|
|
submit_normal_callback;
|
|
|
|
mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
|
|
|
submit_inline_callback;
|
2018-11-10 02:13:15 +01:00
|
|
|
};
|