summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dist/icons/overlay/arrow_left.pngbin0 -> 1490 bytes
-rw-r--r--dist/icons/overlay/arrow_left_dark.pngbin0 -> 712 bytes
-rw-r--r--dist/icons/overlay/arrow_right.pngbin0 -> 1394 bytes
-rw-r--r--dist/icons/overlay/arrow_right_dark.pngbin0 -> 683 bytes
-rw-r--r--dist/icons/overlay/button_A.pngbin0 -> 3494 bytes
-rw-r--r--dist/icons/overlay/button_A_dark.pngbin0 -> 3167 bytes
-rw-r--r--dist/icons/overlay/button_B.pngbin0 -> 3375 bytes
-rw-r--r--dist/icons/overlay/button_B_dark.pngbin0 -> 2975 bytes
-rw-r--r--dist/icons/overlay/button_L.pngbin0 -> 796 bytes
-rw-r--r--dist/icons/overlay/button_L_dark.pngbin0 -> 745 bytes
-rw-r--r--dist/icons/overlay/button_R.pngbin0 -> 1841 bytes
-rw-r--r--dist/icons/overlay/button_R_dark.pngbin0 -> 1835 bytes
-rw-r--r--dist/icons/overlay/button_X.pngbin0 -> 3968 bytes
-rw-r--r--dist/icons/overlay/button_X_dark.pngbin0 -> 3530 bytes
-rw-r--r--dist/icons/overlay/button_Y.pngbin0 -> 3337 bytes
-rw-r--r--dist/icons/overlay/button_Y_dark.pngbin0 -> 2883 bytes
-rw-r--r--dist/icons/overlay/button_minus.pngbin0 -> 2401 bytes
-rw-r--r--dist/icons/overlay/button_minus_dark.pngbin0 -> 1969 bytes
-rw-r--r--dist/icons/overlay/button_plus.pngbin0 -> 2497 bytes
-rw-r--r--dist/icons/overlay/button_plus_dark.pngbin0 -> 2066 bytes
-rw-r--r--dist/icons/overlay/button_press_stick.pngbin0 -> 5225 bytes
-rw-r--r--dist/icons/overlay/button_press_stick_dark.pngbin0 -> 3636 bytes
-rw-r--r--dist/icons/overlay/controller_dual_joycon.pngbin0 -> 7312 bytes
-rw-r--r--dist/icons/overlay/controller_dual_joycon_dark.pngbin0 -> 5889 bytes
-rw-r--r--dist/icons/overlay/controller_handheld.pngbin0 -> 4645 bytes
-rw-r--r--dist/icons/overlay/controller_handheld_dark.pngbin0 -> 3745 bytes
-rw-r--r--dist/icons/overlay/controller_pro.pngbin0 -> 9493 bytes
-rw-r--r--dist/icons/overlay/controller_pro_dark.pngbin0 -> 7488 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left.pngbin0 -> 7489 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_a.pngbin0 -> 2609 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_a_dark.pngbin0 -> 2564 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_b.pngbin0 -> 2559 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_b_dark.pngbin0 -> 2383 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_dark.pngbin0 -> 6768 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_x.pngbin0 -> 2541 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_x_dark.pngbin0 -> 2392 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_y.pngbin0 -> 2641 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_left_y_dark.pngbin0 -> 2639 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_right.pngbin0 -> 7497 bytes
-rw-r--r--dist/icons/overlay/controller_single_joycon_right_dark.pngbin0 -> 6729 bytes
-rw-r--r--dist/icons/overlay/osk_button_B.pngbin0 -> 741 bytes
-rw-r--r--dist/icons/overlay/osk_button_B_dark.pngbin0 -> 767 bytes
-rw-r--r--dist/icons/overlay/osk_button_B_dark_disabled.pngbin0 -> 781 bytes
-rw-r--r--dist/icons/overlay/osk_button_B_disabled.pngbin0 -> 791 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y.pngbin0 -> 726 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y_dark.pngbin0 -> 502 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y_dark_disabled.pngbin0 -> 694 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y_disabled.pngbin0 -> 699 bytes
-rw-r--r--dist/icons/overlay/osk_button_backspace.pngbin0 -> 2919 bytes
-rw-r--r--dist/icons/overlay/osk_button_backspace_dark.pngbin0 -> 2958 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus.pngbin0 -> 626 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus_dark.pngbin0 -> 676 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus_dark_disabled.pngbin0 -> 645 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus_disabled.pngbin0 -> 664 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift.pngbin0 -> 1876 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift_dark.pngbin0 -> 2003 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift_lock_off.pngbin0 -> 281 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift_lock_on.pngbin0 -> 274 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift_on.pngbin0 -> 1573 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift_on_dark.pngbin0 -> 1937 bytes
-rw-r--r--dist/icons/overlay/overlay.qrc64
-rw-r--r--dist/qt_themes/default/style.qss377
-rw-r--r--dist/qt_themes/qdarkstyle/style.qss399
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/style.qss439
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/frontend/applets/software_keyboard.cpp148
-rw-r--r--src/core/frontend/applets/software_keyboard.h118
-rw-r--r--src/core/frontend/input_interpreter.cpp15
-rw-r--r--src/core/frontend/input_interpreter.h3
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp8
-rw-r--r--src/core/hle/kernel/hle_ipc.h10
-rw-r--r--src/core/hle/service/am/am.cpp89
-rw-r--r--src/core/hle/service/am/am.h4
-rw-r--r--src/core/hle/service/am/applets/applets.cpp57
-rw-r--r--src/core/hle/service/am/applets/applets.h30
-rw-r--r--src/core/hle/service/am/applets/controller.cpp5
-rw-r--r--src/core/hle/service/am/applets/controller.h3
-rw-r--r--src/core/hle/service/am/applets/error.cpp5
-rw-r--r--src/core/hle/service/am/applets/error.h3
-rw-r--r--src/core/hle/service/am/applets/general_backend.cpp14
-rw-r--r--src/core/hle/service/am/applets/general_backend.h8
-rw-r--r--src/core/hle/service/am/applets/profile_select.cpp4
-rw-r--r--src/core/hle/service/am/applets/profile_select.h2
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp1153
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.h186
-rw-r--r--src/core/hle/service/am/applets/software_keyboard_types.h295
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp5
-rw-r--r--src/core/hle/service/am/applets/web_browser.h3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp10
-rw-r--r--src/video_core/gpu.cpp12
-rw-r--r--src/video_core/gpu.h3
-rw-r--r--src/yuzu/CMakeLists.txt4
-rw-r--r--src/yuzu/applets/error.cpp22
-rw-r--r--src/yuzu/applets/error.h2
-rw-r--r--src/yuzu/applets/software_keyboard.cpp1712
-rw-r--r--src/yuzu/applets/software_keyboard.h283
-rw-r--r--src/yuzu/applets/software_keyboard.ui3503
-rw-r--r--src/yuzu/main.cpp185
-rw-r--r--src/yuzu/main.h35
-rw-r--r--src/yuzu/util/overlay_dialog.cpp249
-rw-r--r--src/yuzu/util/overlay_dialog.h107
-rw-r--r--src/yuzu/util/overlay_dialog.ui404
102 files changed, 9461 insertions, 518 deletions
diff --git a/dist/icons/overlay/arrow_left.png b/dist/icons/overlay/arrow_left.png
new file mode 100644
index 000000000..a5d4fecfe
--- /dev/null
+++ b/dist/icons/overlay/arrow_left.png
Binary files differ
diff --git a/dist/icons/overlay/arrow_left_dark.png b/dist/icons/overlay/arrow_left_dark.png
new file mode 100644
index 000000000..f73672a59
--- /dev/null
+++ b/dist/icons/overlay/arrow_left_dark.png
Binary files differ
diff --git a/dist/icons/overlay/arrow_right.png b/dist/icons/overlay/arrow_right.png
new file mode 100644
index 000000000..e47ee94bd
--- /dev/null
+++ b/dist/icons/overlay/arrow_right.png
Binary files differ
diff --git a/dist/icons/overlay/arrow_right_dark.png b/dist/icons/overlay/arrow_right_dark.png
new file mode 100644
index 000000000..91cf83d2c
--- /dev/null
+++ b/dist/icons/overlay/arrow_right_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_A.png b/dist/icons/overlay/button_A.png
new file mode 100644
index 000000000..fd90f8b42
--- /dev/null
+++ b/dist/icons/overlay/button_A.png
Binary files differ
diff --git a/dist/icons/overlay/button_A_dark.png b/dist/icons/overlay/button_A_dark.png
new file mode 100644
index 000000000..d6b5514fa
--- /dev/null
+++ b/dist/icons/overlay/button_A_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_B.png b/dist/icons/overlay/button_B.png
new file mode 100644
index 000000000..e8927addc
--- /dev/null
+++ b/dist/icons/overlay/button_B.png
Binary files differ
diff --git a/dist/icons/overlay/button_B_dark.png b/dist/icons/overlay/button_B_dark.png
new file mode 100644
index 000000000..3acbeddcd
--- /dev/null
+++ b/dist/icons/overlay/button_B_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_L.png b/dist/icons/overlay/button_L.png
new file mode 100644
index 000000000..77838369e
--- /dev/null
+++ b/dist/icons/overlay/button_L.png
Binary files differ
diff --git a/dist/icons/overlay/button_L_dark.png b/dist/icons/overlay/button_L_dark.png
new file mode 100644
index 000000000..c96a5e868
--- /dev/null
+++ b/dist/icons/overlay/button_L_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_R.png b/dist/icons/overlay/button_R.png
new file mode 100644
index 000000000..4e5553954
--- /dev/null
+++ b/dist/icons/overlay/button_R.png
Binary files differ
diff --git a/dist/icons/overlay/button_R_dark.png b/dist/icons/overlay/button_R_dark.png
new file mode 100644
index 000000000..ed13199c4
--- /dev/null
+++ b/dist/icons/overlay/button_R_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_X.png b/dist/icons/overlay/button_X.png
new file mode 100644
index 000000000..fe70fb685
--- /dev/null
+++ b/dist/icons/overlay/button_X.png
Binary files differ
diff --git a/dist/icons/overlay/button_X_dark.png b/dist/icons/overlay/button_X_dark.png
new file mode 100644
index 000000000..b2c83d0c1
--- /dev/null
+++ b/dist/icons/overlay/button_X_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_Y.png b/dist/icons/overlay/button_Y.png
new file mode 100644
index 000000000..ca0de569d
--- /dev/null
+++ b/dist/icons/overlay/button_Y.png
Binary files differ
diff --git a/dist/icons/overlay/button_Y_dark.png b/dist/icons/overlay/button_Y_dark.png
new file mode 100644
index 000000000..0f3e4df25
--- /dev/null
+++ b/dist/icons/overlay/button_Y_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_minus.png b/dist/icons/overlay/button_minus.png
new file mode 100644
index 000000000..7b315fe79
--- /dev/null
+++ b/dist/icons/overlay/button_minus.png
Binary files differ
diff --git a/dist/icons/overlay/button_minus_dark.png b/dist/icons/overlay/button_minus_dark.png
new file mode 100644
index 000000000..6dfcdc1b5
--- /dev/null
+++ b/dist/icons/overlay/button_minus_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_plus.png b/dist/icons/overlay/button_plus.png
new file mode 100644
index 000000000..4d8090d7d
--- /dev/null
+++ b/dist/icons/overlay/button_plus.png
Binary files differ
diff --git a/dist/icons/overlay/button_plus_dark.png b/dist/icons/overlay/button_plus_dark.png
new file mode 100644
index 000000000..abe8b9c95
--- /dev/null
+++ b/dist/icons/overlay/button_plus_dark.png
Binary files differ
diff --git a/dist/icons/overlay/button_press_stick.png b/dist/icons/overlay/button_press_stick.png
new file mode 100644
index 000000000..6d0254d50
--- /dev/null
+++ b/dist/icons/overlay/button_press_stick.png
Binary files differ
diff --git a/dist/icons/overlay/button_press_stick_dark.png b/dist/icons/overlay/button_press_stick_dark.png
new file mode 100644
index 000000000..757d0ab29
--- /dev/null
+++ b/dist/icons/overlay/button_press_stick_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_dual_joycon.png b/dist/icons/overlay/controller_dual_joycon.png
new file mode 100644
index 000000000..8e8b5ad41
--- /dev/null
+++ b/dist/icons/overlay/controller_dual_joycon.png
Binary files differ
diff --git a/dist/icons/overlay/controller_dual_joycon_dark.png b/dist/icons/overlay/controller_dual_joycon_dark.png
new file mode 100644
index 000000000..63e03eb4e
--- /dev/null
+++ b/dist/icons/overlay/controller_dual_joycon_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_handheld.png b/dist/icons/overlay/controller_handheld.png
new file mode 100644
index 000000000..deb375011
--- /dev/null
+++ b/dist/icons/overlay/controller_handheld.png
Binary files differ
diff --git a/dist/icons/overlay/controller_handheld_dark.png b/dist/icons/overlay/controller_handheld_dark.png
new file mode 100644
index 000000000..1f5317aa0
--- /dev/null
+++ b/dist/icons/overlay/controller_handheld_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_pro.png b/dist/icons/overlay/controller_pro.png
new file mode 100644
index 000000000..67cf86d5c
--- /dev/null
+++ b/dist/icons/overlay/controller_pro.png
Binary files differ
diff --git a/dist/icons/overlay/controller_pro_dark.png b/dist/icons/overlay/controller_pro_dark.png
new file mode 100644
index 000000000..7be655b96
--- /dev/null
+++ b/dist/icons/overlay/controller_pro_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left.png b/dist/icons/overlay/controller_single_joycon_left.png
new file mode 100644
index 000000000..340ddc71b
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_a.png b/dist/icons/overlay/controller_single_joycon_left_a.png
new file mode 100644
index 000000000..e0f5c2ad4
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_a.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_a_dark.png b/dist/icons/overlay/controller_single_joycon_left_a_dark.png
new file mode 100644
index 000000000..53e04781e
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_a_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_b.png b/dist/icons/overlay/controller_single_joycon_left_b.png
new file mode 100644
index 000000000..7429450a3
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_b.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_b_dark.png b/dist/icons/overlay/controller_single_joycon_left_b_dark.png
new file mode 100644
index 000000000..3bd97a8eb
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_b_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_dark.png b/dist/icons/overlay/controller_single_joycon_left_dark.png
new file mode 100644
index 000000000..24ed2c44c
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_x.png b/dist/icons/overlay/controller_single_joycon_left_x.png
new file mode 100644
index 000000000..4615172a3
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_x.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_x_dark.png b/dist/icons/overlay/controller_single_joycon_left_x_dark.png
new file mode 100644
index 000000000..119e3091a
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_x_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_y.png b/dist/icons/overlay/controller_single_joycon_left_y.png
new file mode 100644
index 000000000..24421d8b9
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_y.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_left_y_dark.png b/dist/icons/overlay/controller_single_joycon_left_y_dark.png
new file mode 100644
index 000000000..fdf177c12
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_left_y_dark.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_right.png b/dist/icons/overlay/controller_single_joycon_right.png
new file mode 100644
index 000000000..5b8fc0eff
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_right.png
Binary files differ
diff --git a/dist/icons/overlay/controller_single_joycon_right_dark.png b/dist/icons/overlay/controller_single_joycon_right_dark.png
new file mode 100644
index 000000000..afa80e6ef
--- /dev/null
+++ b/dist/icons/overlay/controller_single_joycon_right_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_B.png b/dist/icons/overlay/osk_button_B.png
new file mode 100644
index 000000000..f4a041178
--- /dev/null
+++ b/dist/icons/overlay/osk_button_B.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_B_dark.png b/dist/icons/overlay/osk_button_B_dark.png
new file mode 100644
index 000000000..2d2bffcca
--- /dev/null
+++ b/dist/icons/overlay/osk_button_B_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_B_dark_disabled.png b/dist/icons/overlay/osk_button_B_dark_disabled.png
new file mode 100644
index 000000000..93c102b1b
--- /dev/null
+++ b/dist/icons/overlay/osk_button_B_dark_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_B_disabled.png b/dist/icons/overlay/osk_button_B_disabled.png
new file mode 100644
index 000000000..5900982f6
--- /dev/null
+++ b/dist/icons/overlay/osk_button_B_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y.png b/dist/icons/overlay/osk_button_Y.png
new file mode 100644
index 000000000..b08b4e26b
--- /dev/null
+++ b/dist/icons/overlay/osk_button_Y.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y_dark.png b/dist/icons/overlay/osk_button_Y_dark.png
new file mode 100644
index 000000000..1fba9ca93
--- /dev/null
+++ b/dist/icons/overlay/osk_button_Y_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y_dark_disabled.png b/dist/icons/overlay/osk_button_Y_dark_disabled.png
new file mode 100644
index 000000000..6ce53f9e4
--- /dev/null
+++ b/dist/icons/overlay/osk_button_Y_dark_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y_disabled.png b/dist/icons/overlay/osk_button_Y_disabled.png
new file mode 100644
index 000000000..25db07f66
--- /dev/null
+++ b/dist/icons/overlay/osk_button_Y_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_backspace.png b/dist/icons/overlay/osk_button_backspace.png
new file mode 100644
index 000000000..4ad284720
--- /dev/null
+++ b/dist/icons/overlay/osk_button_backspace.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_backspace_dark.png b/dist/icons/overlay/osk_button_backspace_dark.png
new file mode 100644
index 000000000..19ac8847e
--- /dev/null
+++ b/dist/icons/overlay/osk_button_backspace_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus.png b/dist/icons/overlay/osk_button_plus.png
new file mode 100644
index 000000000..5baa5201e
--- /dev/null
+++ b/dist/icons/overlay/osk_button_plus.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus_dark.png b/dist/icons/overlay/osk_button_plus_dark.png
new file mode 100644
index 000000000..4cadb438b
--- /dev/null
+++ b/dist/icons/overlay/osk_button_plus_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus_dark_disabled.png b/dist/icons/overlay/osk_button_plus_dark_disabled.png
new file mode 100644
index 000000000..b8eb8dc3d
--- /dev/null
+++ b/dist/icons/overlay/osk_button_plus_dark_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus_disabled.png b/dist/icons/overlay/osk_button_plus_disabled.png
new file mode 100644
index 000000000..c23e9d95d
--- /dev/null
+++ b/dist/icons/overlay/osk_button_plus_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift.png b/dist/icons/overlay/osk_button_shift.png
new file mode 100644
index 000000000..f03e30697
--- /dev/null
+++ b/dist/icons/overlay/osk_button_shift.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift_dark.png b/dist/icons/overlay/osk_button_shift_dark.png
new file mode 100644
index 000000000..c9cc5cd9a
--- /dev/null
+++ b/dist/icons/overlay/osk_button_shift_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift_lock_off.png b/dist/icons/overlay/osk_button_shift_lock_off.png
new file mode 100644
index 000000000..585500b3a
--- /dev/null
+++ b/dist/icons/overlay/osk_button_shift_lock_off.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift_lock_on.png b/dist/icons/overlay/osk_button_shift_lock_on.png
new file mode 100644
index 000000000..09077ab01
--- /dev/null
+++ b/dist/icons/overlay/osk_button_shift_lock_on.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift_on.png b/dist/icons/overlay/osk_button_shift_on.png
new file mode 100644
index 000000000..e7c1187f9
--- /dev/null
+++ b/dist/icons/overlay/osk_button_shift_on.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift_on_dark.png b/dist/icons/overlay/osk_button_shift_on_dark.png
new file mode 100644
index 000000000..58e0d9cf4
--- /dev/null
+++ b/dist/icons/overlay/osk_button_shift_on_dark.png
Binary files differ
diff --git a/dist/icons/overlay/overlay.qrc b/dist/icons/overlay/overlay.qrc
new file mode 100644
index 000000000..d5a21ce10
--- /dev/null
+++ b/dist/icons/overlay/overlay.qrc
@@ -0,0 +1,64 @@
1<RCC>
2 <qresource prefix="overlay">
3 <file>arrow_left.png</file>
4 <file>arrow_left_dark.png</file>
5 <file>arrow_right.png</file>
6 <file>arrow_right_dark.png</file>
7 <file>button_minus.png</file>
8 <file>button_minus_dark.png</file>
9 <file>button_plus.png</file>
10 <file>button_plus_dark.png</file>
11 <file>button_A.png</file>
12 <file>button_A_dark.png</file>
13 <file>button_B.png</file>
14 <file>button_B_dark.png</file>
15 <file>button_X.png</file>
16 <file>button_X_dark.png</file>
17 <file>button_Y.png</file>
18 <file>button_Y_dark.png</file>
19 <file>button_L.png</file>
20 <file>button_L_dark.png</file>
21 <file>button_R.png</file>
22 <file>button_R_dark.png</file>
23 <file>button_press_stick.png</file>
24 <file>button_press_stick_dark.png</file>
25 <file>osk_button_B.png</file>
26 <file>osk_button_B_disabled.png</file>
27 <file>osk_button_B_dark.png</file>
28 <file>osk_button_B_dark_disabled.png</file>
29 <file>osk_button_Y.png</file>
30 <file>osk_button_Y_disabled.png</file>
31 <file>osk_button_Y_dark.png</file>
32 <file>osk_button_Y_dark_disabled.png</file>
33 <file>osk_button_backspace.png</file>
34 <file>osk_button_backspace_dark.png</file>
35 <file>osk_button_plus.png</file>
36 <file>osk_button_plus_disabled.png</file>
37 <file>osk_button_plus_dark.png</file>
38 <file>osk_button_plus_dark_disabled.png</file>
39 <file>osk_button_shift.png</file>
40 <file>osk_button_shift_dark.png</file>
41 <file>osk_button_shift_on.png</file>
42 <file>osk_button_shift_on_dark.png</file>
43 <file>osk_button_shift_lock_on.png</file>
44 <file>osk_button_shift_lock_off.png</file>
45 <file>controller_dual_joycon.png</file>
46 <file>controller_dual_joycon_dark.png</file>
47 <file>controller_pro.png</file>
48 <file>controller_pro_dark.png</file>
49 <file>controller_handheld.png</file>
50 <file>controller_handheld_dark.png</file>
51 <file>controller_single_joycon_left.png</file>
52 <file>controller_single_joycon_left_dark.png</file>
53 <file>controller_single_joycon_right.png</file>
54 <file>controller_single_joycon_right_dark.png</file>
55 <file>controller_single_joycon_left_a.png</file>
56 <file>controller_single_joycon_left_a_dark.png</file>
57 <file>controller_single_joycon_left_b.png</file>
58 <file>controller_single_joycon_left_b_dark.png</file>
59 <file>controller_single_joycon_left_x.png</file>
60 <file>controller_single_joycon_left_x_dark.png</file>
61 <file>controller_single_joycon_left_y.png</file>
62 <file>controller_single_joycon_left_y_dark.png</file>
63 </qresource>
64</RCC>
diff --git a/dist/qt_themes/default/style.qss b/dist/qt_themes/default/style.qss
index 836dd25ca..3bc92b69d 100644
--- a/dist/qt_themes/default/style.qss
+++ b/dist/qt_themes/default/style.qss
@@ -281,3 +281,380 @@ QWidget#controllerPlayer7,
281QWidget#controllerPlayer8 { 281QWidget#controllerPlayer8 {
282 background: transparent; 282 background: transparent;
283} 283}
284
285QDialog#QtSoftwareKeyboardDialog,
286QStackedWidget#topOSK {
287 background: rgba(51, 51, 51, .9);
288}
289
290
291QDialog#OverlayDialog,
292QStackedWidget#stackedDialog {
293 background: rgba(51, 51, 51, .7);
294}
295
296QWidget#boxOSK,
297QWidget#lineOSK,
298QWidget#richDialog,
299QWidget#lineDialog {
300 background: transparent;
301}
302
303QStackedWidget#bottomOSK,
304QWidget#contentDialog,
305QWidget#contentRichDialog {
306 background: rgba(240, 240, 240, 1);
307}
308
309QWidget#contentDialog,
310QWidget#contentRichDialog {
311 margin: 5px;
312 border-radius: 6px;
313}
314
315QWidget#buttonsDialog,
316QWidget#buttonsRichDialog {
317 margin: 5px;
318 border-top: 2px solid rgba(44, 44, 44, 1);
319}
320
321QWidget#legendOSKnum {
322 border-top: 1px solid rgba(44, 44, 44, 1);
323}
324
325QStackedWidget#stackedDialog QTextBrowser QScrollBar::vertical {
326 background: #cdcdcd;
327 width: 15px;
328 margin: 15px 3px 15px 3px;
329 border: 1px transparent;
330 border-radius: 4px;
331}
332
333QStackedWidget#stackedDialog QTextBrowser QScrollBar::horizoncal {
334 background: #cdcdcd;
335 height: 15px;
336 margin: 3px 15px 3px 15px;
337 border: 1px transparent;
338 border-radius: 4px;
339}
340
341QStackedWidget#stackedDialog QTextBrowser QScrollBar::handle {
342 background: #fff;
343 border-radius: 4px;
344 min-height: 5px;
345 min-width: 5px;
346}
347
348QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-line,
349QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-line,
350QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-page,
351QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-page {
352 background: none;
353}
354
355QWidget#inputOSK {
356 border-bottom: 3px solid rgba(255, 255, 255, .9);
357}
358
359QWidget#inputOSK QLineEdit {
360 background: transparent;
361 border: none;
362 color: #ccc;
363}
364
365QWidget#inputBoxOSK {
366 border: 2px solid rgba(255, 255, 255, .9);
367}
368
369QWidget#inputBoxOSK QTextEdit {
370 background: transparent;
371 border: none;
372 color: #ccc;
373}
374
375QWidget#richDialog QTextBrowser {
376 background: transparent;
377 border: none;
378 padding: 35px 65px;
379}
380
381
382QWidget#lineOSK QLabel#label_header {
383 color: #f0f0f0;
384}
385
386QWidget#lineOSK QLabel#label_sub,
387QWidget#lineOSK QLabel#label_characters,
388QWidget#boxOSK QLabel#label_characters_box {
389 color: #ccc;
390}
391
392QWidget#contentDialog QLabel#label_title,
393QWidget#contentRichDialog QLabel#label_title_rich {
394 color: #888;
395}
396
397QWidget#contentDialog QLabel#label_dialog {
398 padding: 20px 65px;
399}
400
401QWidget#contentDialog QLabel#label_title,
402QWidget#contentRichDialog QLabel#label_title_rich {
403 padding: 0px 65px;
404}
405
406QDialog#OverlayDialog QPushButton {
407 color: rgba(49, 79, 239, 1);
408 background: transparent;
409 border: none;
410 padding: 0px;
411 min-width: 0px;
412}
413
414QDialog#OverlayDialog QPushButton:focus,
415QDialog#OverlayDialog QPushButton:hover {
416 color: rgba(49, 79, 239, 1);
417 background: rgba(255, 255, 255, 1);
418 border: 5px solid rgba(148, 250, 202, 1);
419 border-radius: 6px;
420 outline: none;
421}
422
423QDialog#OverlayDialog QPushButton:pressed {
424 color: rgba(240, 240, 240, 1);
425 background: rgba(150, 150, 150, 1);
426 border: 5px solid rgba(148, 250, 202, 1);
427 border-radius: 6px;
428 outline: none;
429}
430
431QDialog#QtSoftwareKeyboardDialog QPushButton {
432 background: rgba(232, 232, 232, 1);
433 border: 2px solid rgba(240, 240, 240, 1);
434}
435
436QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift,
437QDialog#QtSoftwareKeyboardDialog QPushButton#button_return,
438QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
439QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift,
440QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift,
441QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
442 background: rgba(218, 218, 218, 1);
443 border: 2px solid rgba(240, 240, 240, 1);
444}
445
446QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
447QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
448QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
449 color: rgba(240, 240, 240, 1);
450 background: rgba(44, 44, 44, 1);
451 border: 2px solid rgba(240, 240, 240, 1);
452}
453
454QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
455QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
456QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
457 color: rgba(240, 240, 240, 1);
458 background: rgba(49, 79, 239, 1);
459 border: 2px solid rgba(240, 240, 240, 1);
460}
461
462QDialog#QtSoftwareKeyboardDialog QPushButton:focus,
463QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:focus,
464QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:focus,
465QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:focus,
466QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:focus,
467QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:focus,
468QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:focus,
469QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:focus,
470QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:focus,
471QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:focus,
472QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:focus,
473QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:focus,
474QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:focus,
475
476QDialog#QtSoftwareKeyboardDialog QPushButton:hover,
477QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:hover,
478QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:hover,
479QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:hover,
480QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:hover,
481QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:hover,
482QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:hover,
483QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:hover,
484QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:hover,
485QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:hover,
486QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:hover,
487QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:hover,
488QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:hover {
489 color: rgba(0, 0, 0, 1);
490 background: rgba(255, 255, 255, 1);
491 border: 5px solid rgba(148, 250, 202, 1);
492 border-radius: 6px;
493 outline: none;
494}
495
496QDialog#QtSoftwareKeyboardDialog QPushButton:pressed,
497QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:pressed,
498QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:pressed,
499QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:pressed,
500QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:pressed,
501QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:pressed,
502QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:pressed,
503QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:pressed,
504QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:pressed,
505QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:pressed,
506QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:pressed,
507QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:pressed,
508QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
509 color: rgba(240, 240, 240, 1);
510 background: rgba(150, 150, 150, 1);
511 border: 5px solid rgba(148, 250, 202, 1);
512 border-radius: 6px;
513}
514
515QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
516QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
517QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
518 background-position: right top;
519 background-repeat: no-repeat;
520 background-origin: content;
521 background-image: url(:/overlay/osk_button_B.png);
522 qproperty-icon: url(:/overlay/osk_button_backspace.png);
523 qproperty-iconSize: 36px;
524}
525
526QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
527QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
528 background-position: right top;
529 background-repeat: no-repeat;
530 background-origin: content;
531 background-image: url(:/overlay/osk_button_Y.png);
532}
533
534QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
535QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
536QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
537 background-position: right top;
538 background-repeat: no-repeat;
539 background-origin: content;
540 background-image: url(:/overlay/osk_button_plus.png);
541}
542
543QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
544 background-position: left top;
545 background-repeat: no-repeat;
546 background-origin: content;
547 background-image: url(:/overlay/osk_button_shift_lock_off.png);
548 qproperty-icon: url(:/overlay/osk_button_shift.png);
549 qproperty-iconSize: 36px;
550}
551
552QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
553 background-position: left top;
554 background-repeat: no-repeat;
555 background-origin: content;
556 background-image: url(:/overlay/osk_button_shift_lock_off.png);
557 qproperty-icon: url(:/overlay/osk_button_shift_on.png);
558 qproperty-iconSize: 36px;
559}
560
561QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_bracket,
562QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_bracket,
563QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_parenthesis,
564QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_parenthesis {
565 padding-bottom: 7px;
566}
567
568QDialog#QtSoftwareKeyboardDialog QWidget#titleOSK QLabel {
569 background: transparent;
570 color: #ccc;
571}
572
573QDialog#QtSoftwareKeyboardDialog QWidget#button_L,
574QDialog#QtSoftwareKeyboardDialog QWidget#button_L_shift,
575QDialog#QtSoftwareKeyboardDialog QWidget#button_L_num {
576 image: url(:/overlay/button_L.png);
577}
578
579QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left,
580QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_shift,
581QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_num {
582 image: url(:/overlay/arrow_left.png);
583}
584
585QDialog#QtSoftwareKeyboardDialog QWidget#button_R,
586QDialog#QtSoftwareKeyboardDialog QWidget#button_R_shift,
587QDialog#QtSoftwareKeyboardDialog QWidget#button_R_num {
588 image: url(:/overlay/button_R.png);
589}
590
591QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right,
592QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_shift,
593QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_num {
594 image: url(:/overlay/arrow_right.png);
595}
596
597QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick,
598QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick_shift {
599 image: url(:/overlay/button_press_stick.png);
600}
601
602QDialog#QtSoftwareKeyboardDialog QWidget#button_X,
603QDialog#QtSoftwareKeyboardDialog QWidget#button_X_shift,
604QDialog#QtSoftwareKeyboardDialog QWidget#button_X_num {
605 image: url(:/overlay/button_X.png);
606}
607
608QDialog#QtSoftwareKeyboardDialog QWidget#button_A,
609QDialog#QtSoftwareKeyboardDialog QWidget#button_A_shift,
610QDialog#QtSoftwareKeyboardDialog QWidget#button_A_num {
611 image: url(:/overlay/button_A.png);
612}
613
614QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
615QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
616QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled,
617QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
618QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
619QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled,
620QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:disabled,
621QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
622QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled,
623QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
624 color: rgba(164, 164, 164, 1);
625 background-color: rgba(218, 218, 218, 1);
626}
627
628QDialog#QtSoftwareKeyboardDialog QPushButton#button_at:disabled,
629QDialog#QtSoftwareKeyboardDialog QPushButton#button_slash:disabled,
630QDialog#QtSoftwareKeyboardDialog QPushButton#button_percent:disabled,
631QDialog#QtSoftwareKeyboardDialog QPushButton#button_1:disabled,
632QDialog#QtSoftwareKeyboardDialog QPushButton#button_2:disabled,
633QDialog#QtSoftwareKeyboardDialog QPushButton#button_3:disabled,
634QDialog#QtSoftwareKeyboardDialog QPushButton#button_4:disabled,
635QDialog#QtSoftwareKeyboardDialog QPushButton#button_5:disabled,
636QDialog#QtSoftwareKeyboardDialog QPushButton#button_6:disabled,
637QDialog#QtSoftwareKeyboardDialog QPushButton#button_7:disabled,
638QDialog#QtSoftwareKeyboardDialog QPushButton#button_8:disabled,
639QDialog#QtSoftwareKeyboardDialog QPushButton#button_9:disabled,
640QDialog#QtSoftwareKeyboardDialog QPushButton#button_0:disabled,
641QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
642 color: rgba(164, 164, 164, 1);
643}
644
645QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
646QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
647QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
648 background-image: url(:/overlay/osk_button_plus_disabled.png);
649}
650
651QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
652QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
653QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
654 background-image: url(:/overlay/osk_button_B_disabled.png);
655}
656
657QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
658QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
659 background-image: url(:/overlay/osk_button_Y_disabled.png);
660}
diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss
index 2a1e8ddeb..8ce6d75f7 100644
--- a/dist/qt_themes/qdarkstyle/style.qss
+++ b/dist/qt_themes/qdarkstyle/style.qss
@@ -1560,7 +1560,400 @@ QWidget#controllerPlayer8 {
1560 background: transparent; 1560 background: transparent;
1561} 1561}
1562 1562
1563/* touchscreen mapping widget */ 1563QDialog#QtSoftwareKeyboardDialog,
1564TouchScreenPreview { 1564QStackedWidget#topOSK {
1565 qproperty-dotHighlightColor: #3daee9; 1565 background: rgba(41, 41, 41, .9);
1566}
1567
1568
1569QDialog#OverlayDialog,
1570QStackedWidget#stackedDialog {
1571 background: rgba(41, 41, 41, .7);
1572}
1573
1574QWidget#boxOSK,
1575QWidget#lineOSK,
1576QWidget#richDialog,
1577QWidget#lineDialog {
1578 background: transparent;
1579}
1580
1581QStackedWidget#bottomOSK,
1582QWidget#contentDialog,
1583QWidget#contentRichDialog {
1584 background: rgba(71, 69, 71, 1);
1585}
1586
1587QWidget#contentDialog,
1588QWidget#contentRichDialog {
1589 margin: 5px;
1590 border-radius: 6px;
1591}
1592
1593QWidget#buttonsDialog,
1594QWidget#buttonsRichDialog {
1595 margin: 5px;
1596 border-top: 2px solid rgba(255, 255, 255, .9);
1597}
1598
1599QWidget#legendOSKnum {
1600 border-top: 1px solid rgba(255, 255, 255, 1);
1601}
1602
1603QStackedWidget#stackedDialog QTextBrowser QWidget {
1604 background: transparent;
1605}
1606
1607QStackedWidget#stackedDialog QTextBrowser QScrollBar {
1608 background: #2a2929;
1609}
1610
1611QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-line,
1612QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-line {
1613 border-image: none;
1614}
1615
1616QWidget#inputOSK {
1617 border-bottom: 3px solid rgba(255, 255, 255, .9);
1618}
1619
1620QWidget#inputOSK QLineEdit {
1621 background: transparent;
1622 border: none;
1623 color: #ccc;
1624 padding: 0px;
1625}
1626
1627QWidget#inputBoxOSK {
1628 border: 2px solid rgba(255, 255, 255, .9);
1629}
1630
1631QWidget#inputBoxOSK QTextEdit {
1632 background: transparent;
1633 border: none;
1634 color: #ccc;
1635}
1636
1637QWidget#richDialog QTextBrowser {
1638 background: transparent;
1639 border: none;
1640 color: #fff;
1641 padding: 35px 65px;
1642}
1643
1644QWidget#lineOSK QLabel#label_header {
1645 color: #f0f0f0;
1646}
1647
1648QWidget#lineOSK QLabel#label_sub,
1649QWidget#lineOSK QLabel#label_characters,
1650QWidget#contentDialog QLabel#label_title,
1651QWidget#contentRichDialog QLabel#label_title_rich,
1652QWidget#boxOSK QLabel#label_characters_box {
1653 color: #ccc;
1654}
1655
1656QWidget#buttonsDialog,
1657QWidget#buttonsRichDialog,
1658QWidget#mainOSK,
1659QWidget#headerOSK,
1660QWidget#normalOSK,
1661QWidget#shiftOSK,
1662QWidget#numOSK,
1663QWidget#subOSK,
1664QWidget#inputOSK,
1665QWidget#inputBoxOSK,
1666QWidget#charactersOSK,
1667QWidget#charactersBoxOSK,
1668QWidget#legendOSK,
1669QWidget#legendOSK QWidget,
1670QWidget#legendOSKshift,
1671QWidget#legendOSKshift QWidget,
1672QWidget#legendOSKnum,
1673QWidget#legendOSKnum QWidget {
1674 background: transparent;
1675}
1676
1677QWidget#contentDialog QLabel,
1678QWidget#legendOSK QLabel,
1679QWidget#legendOSKshift QLabel,
1680QWidget#legendOSKnum QLabel {
1681 color: rgba(255, 255, 255, 1);
1682}
1683
1684QWidget#contentDialog QLabel#label_dialog {
1685 padding: 20px 65px;
1686}
1687
1688QWidget#contentDialog QLabel#label_title,
1689QWidget#contentRichDialog QLabel#label_title_rich {
1690 padding: 0px 65px;
1691}
1692
1693QDialog#OverlayDialog QPushButton {
1694 color: rgba(1, 253, 201, 1);
1695 background: transparent;
1696 border: none;
1697 padding: 0px;
1698 min-width: 0px;
1699}
1700
1701QDialog#OverlayDialog QPushButton:focus,
1702QDialog#OverlayDialog QPushButton:hover {
1703 color: rgba(1, 253, 201, 1);
1704 background: rgba(58, 61, 66, 1);
1705 border: 5px solid rgba(56, 189, 225, 1);
1706 border-radius: 6px;
1707 outline: none;
1708}
1709
1710QDialog#OverlayDialog QPushButton:pressed {
1711 color: rgba(240, 240, 240, 1);
1712 background: rgba(150, 150, 150, 1);
1713 border: 5px solid rgba(56, 189, 225, 1);
1714 border-radius: 6px;
1715 outline: none;
1716}
1717
1718QDialog#QtSoftwareKeyboardDialog QPushButton {
1719 color: rgba(255, 255, 255, 1);
1720 background: rgba(80, 79, 80, 1);
1721 border: 2px solid rgba(71, 69, 71, 1);
1722 padding: 0px;
1723 min-width: 0px;
1724}
1725
1726QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift,
1727QDialog#QtSoftwareKeyboardDialog QPushButton#button_return,
1728QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
1729QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift,
1730QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift,
1731QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
1732 background: rgba(95, 94, 95, 1);
1733 border: 2px solid rgba(71, 69, 71, 1);
1734}
1735
1736QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
1737QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
1738QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
1739 color: rgba(240, 240, 240, 1);
1740 background: rgba(255, 255, 255, 1);
1741 border: 2px solid rgba(71, 69, 71, 1);
1742}
1743
1744QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
1745QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
1746QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
1747 color: rgba(0, 0, 0, 1);
1748 background: rgba(1, 253, 201, 1);
1749 border: 2px solid rgba(71, 69, 71, 1);
1750}
1751
1752QDialog#QtSoftwareKeyboardDialog QPushButton:focus,
1753QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:focus,
1754QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:focus,
1755QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:focus,
1756QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:focus,
1757QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:focus,
1758QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:focus,
1759QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:focus,
1760QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:focus,
1761QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:focus,
1762QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:focus,
1763QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:focus,
1764QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:focus,
1765
1766QDialog#QtSoftwareKeyboardDialog QPushButton:hover,
1767QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:hover,
1768QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:hover,
1769QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:hover,
1770QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:hover,
1771QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:hover,
1772QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:hover,
1773QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:hover,
1774QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:hover,
1775QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:hover,
1776QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:hover,
1777QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:hover,
1778QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:hover {
1779 color: rgba(255, 255, 255, 1);
1780 background: rgba(58, 61, 66, 1);
1781 border: 5px solid rgba(56, 189, 225, 1);
1782 border-radius: 6px;
1783 outline: none;
1784}
1785
1786QDialog#QtSoftwareKeyboardDialog QPushButton:pressed,
1787QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:pressed,
1788QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:pressed,
1789QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:pressed,
1790QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:pressed,
1791QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:pressed,
1792QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:pressed,
1793QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:pressed,
1794QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:pressed,
1795QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:pressed,
1796QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:pressed,
1797QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:pressed,
1798QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
1799 color: rgba(240, 240, 240, 1);
1800 background: rgba(150, 150, 150, 1);
1801 border: 5px solid rgba(56, 189, 225, 1);
1802 border-radius: 6px;
1803}
1804
1805QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
1806QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
1807QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
1808 background-position: right top;
1809 background-repeat: no-repeat;
1810 background-origin: content;
1811 background-image: url(:/overlay/osk_button_B_dark.png);
1812 qproperty-icon: url(:/overlay/osk_button_backspace_dark.png);
1813 qproperty-iconSize: 36px;
1814}
1815
1816QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
1817QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
1818 background-position: right top;
1819 background-repeat: no-repeat;
1820 background-origin: content;
1821 background-image: url(:/overlay/osk_button_Y_dark.png);
1822}
1823
1824QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
1825QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
1826QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
1827 color: rgba(44, 44, 44, 1);
1828 background-position: right top;
1829 background-repeat: no-repeat;
1830 background-origin: content;
1831 background-image: url(:/overlay/osk_button_plus_dark.png);
1832}
1833
1834QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
1835 background-position: left top;
1836 background-repeat: no-repeat;
1837 background-origin: content;
1838 background-image: url(:/overlay/osk_button_shift_lock_off.png);
1839 qproperty-icon: url(:/overlay/osk_button_shift_dark.png);
1840 qproperty-iconSize: 36px;
1841}
1842
1843QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
1844 background-position: left top;
1845 background-repeat: no-repeat;
1846 background-origin: content;
1847 background-image: url(:/overlay/osk_button_shift_lock_off.png);
1848 qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png);
1849 qproperty-iconSize: 36px;
1850}
1851
1852QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_bracket,
1853QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_bracket,
1854QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_parenthesis,
1855QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_parenthesis {
1856 padding-bottom: 7px;
1857}
1858
1859QDialog#QtSoftwareKeyboardDialog QWidget#titleOSK QLabel {
1860 background: transparent;
1861 color: #ccc;
1862}
1863
1864QDialog#QtSoftwareKeyboardDialog QWidget#button_L,
1865QDialog#QtSoftwareKeyboardDialog QWidget#button_L_shift,
1866QDialog#QtSoftwareKeyboardDialog QWidget#button_L_num {
1867 image: url(:/overlay/button_L_dark.png);
1868}
1869
1870QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left,
1871QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_shift,
1872QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_num {
1873 image: url(:/overlay/arrow_left_dark.png);
1874}
1875
1876QDialog#QtSoftwareKeyboardDialog QWidget#button_R,
1877QDialog#QtSoftwareKeyboardDialog QWidget#button_R_shift,
1878QDialog#QtSoftwareKeyboardDialog QWidget#button_R_num {
1879 image: url(:/overlay/button_R_dark.png);
1880}
1881
1882QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right,
1883QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_shift,
1884QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_num {
1885 image: url(:/overlay/arrow_right_dark.png);
1886}
1887
1888QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick,
1889QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick_shift {
1890 image: url(:/overlay/button_press_stick_dark.png);
1891}
1892
1893QDialog#QtSoftwareKeyboardDialog QWidget#button_X,
1894QDialog#QtSoftwareKeyboardDialog QWidget#button_X_shift,
1895QDialog#QtSoftwareKeyboardDialog QWidget#button_X_num {
1896 image: url(:/overlay/button_X_dark.png);
1897}
1898
1899QDialog#QtSoftwareKeyboardDialog QWidget#button_A,
1900QDialog#QtSoftwareKeyboardDialog QWidget#button_A_shift,
1901QDialog#QtSoftwareKeyboardDialog QWidget#button_A_num {
1902 image: url(:/overlay/button_A_dark.png);
1903}
1904
1905QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
1906QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
1907QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled,
1908QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
1909QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
1910QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled,
1911QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:disabled,
1912QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
1913QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled,
1914QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
1915 color: rgba(144, 144, 144, 1);
1916 background-color: rgba(95, 94, 95, 1);
1917}
1918
1919QDialog#QtSoftwareKeyboardDialog QPushButton#button_at:disabled,
1920QDialog#QtSoftwareKeyboardDialog QPushButton#button_slash:disabled,
1921QDialog#QtSoftwareKeyboardDialog QPushButton#button_percent:disabled,
1922QDialog#QtSoftwareKeyboardDialog QPushButton#button_1:disabled,
1923QDialog#QtSoftwareKeyboardDialog QPushButton#button_2:disabled,
1924QDialog#QtSoftwareKeyboardDialog QPushButton#button_3:disabled,
1925QDialog#QtSoftwareKeyboardDialog QPushButton#button_4:disabled,
1926QDialog#QtSoftwareKeyboardDialog QPushButton#button_5:disabled,
1927QDialog#QtSoftwareKeyboardDialog QPushButton#button_6:disabled,
1928QDialog#QtSoftwareKeyboardDialog QPushButton#button_7:disabled,
1929QDialog#QtSoftwareKeyboardDialog QPushButton#button_8:disabled,
1930QDialog#QtSoftwareKeyboardDialog QPushButton#button_9:disabled,
1931QDialog#QtSoftwareKeyboardDialog QPushButton#button_0:disabled,
1932QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
1933 color: rgba(144, 144, 144, 1);
1934}
1935
1936QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
1937QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
1938QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
1939 background-image: url(:/overlay/osk_button_plus_dark_disabled.png);
1940}
1941
1942QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
1943QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
1944QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
1945 background-image: url(:/overlay/osk_button_B_dark_disabled.png);
1946}
1947
1948QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
1949QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
1950 background-image: url(:/overlay/osk_button_Y_dark_disabled.png);
1951}
1952
1953QDialog#QtSoftwareKeyboardDialog QFrame,
1954QDialog#QtSoftwareKeyboardDialog QFrame[frameShape="0"],
1955QDialog#OverlayDialog QFrame,
1956QDialog#OverlayDialog QFrame[frameShape="0"] {
1957 border-radius: 0px;
1958 border: none;
1566} 1959}
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
index a64037455..64e1ecbcc 100644
--- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
@@ -1,10 +1,10 @@
1/* --------------------------------------------------------------------------- 1/* ---------------------------------------------------------------------------
2 2
3 Created by the qtsass compiler v0.1.1 3 Created by the qtsass compiler v0.1.1
4 4
5 The definitions are in the "qdarkstyle.qss._styles.scss" module 5 The definitions are in the "qdarkstyle.qss._styles.scss" module
6 6
7 WARNING! All changes made in this file will be lost! 7 WARNING! All changes made in this file will be lost!
8 8
9--------------------------------------------------------------------------- */ 9--------------------------------------------------------------------------- */
10/* QDarkStyleSheet ----------------------------------------------------------- 10/* QDarkStyleSheet -----------------------------------------------------------
@@ -15,34 +15,34 @@ It is based on three selecting colors, three greyish (background) colors
15plus three whitish (foreground) colors. Each set of widgets of the same 15plus three whitish (foreground) colors. Each set of widgets of the same
16type have a header like this: 16type have a header like this:
17 17
18 ------------------ 18 ------------------
19 GroupName -------- 19 GroupName --------
20 ------------------ 20 ------------------
21 21
22And each widget is separated with a header like this: 22And each widget is separated with a header like this:
23 23
24 QWidgetName ------ 24 QWidgetName ------
25 25
26This makes more easy to find and change some css field. The basic 26This makes more easy to find and change some css field. The basic
27configuration is described bellow. 27configuration is described bellow.
28 28
29 BACKGROUND ----------- 29 BACKGROUND -----------
30 30
31 Light (unpressed) 31 Light (unpressed)
32 Normal (border, disabled, pressed, checked, toolbars, menus) 32 Normal (border, disabled, pressed, checked, toolbars, menus)
33 Dark (background) 33 Dark (background)
34 34
35 FOREGROUND ----------- 35 FOREGROUND -----------
36 36
37 Light (texts/labels) 37 Light (texts/labels)
38 Normal (not used yet) 38 Normal (not used yet)
39 Dark (disabled texts) 39 Dark (disabled texts)
40 40
41 SELECTION ------------ 41 SELECTION ------------
42 42
43 Light (selection/hover/active) 43 Light (selection/hover/active)
44 Normal (selected) 44 Normal (selected)
45 Dark (selected disabled) 45 Dark (selected disabled)
46 46
47If a stranger configuration is required because of a bugfix or anything 47If a stranger configuration is required because of a bugfix or anything
48else, keep the comment on the line above so nobody changes it, including the 48else, keep the comment on the line above so nobody changes it, including the
@@ -2483,3 +2483,404 @@ QWidget#controllerPlayer7,
2483QWidget#controllerPlayer8 { 2483QWidget#controllerPlayer8 {
2484 background: transparent; 2484 background: transparent;
2485} 2485}
2486
2487QDialog#QtSoftwareKeyboardDialog,
2488QStackedWidget#topOSK {
2489 background: rgba(15, 25, 34, .9);
2490}
2491
2492QDialog#OverlayDialog,
2493QStackedWidget#stackedDialog {
2494 background: rgba(15, 25, 34, .7);
2495}
2496
2497QWidget#boxOSK,
2498QWidget#lineOSK,
2499QWidget#richDialog,
2500QWidget#lineDialog {
2501 background: transparent;
2502}
2503
2504QStackedWidget#bottomOSK,
2505QWidget#contentDialog,
2506QWidget#contentRichDialog {
2507 background: rgba(31, 41, 51, 1);
2508}
2509
2510QWidget#contentDialog,
2511QWidget#contentRichDialog {
2512 margin: 5px;
2513 border-radius: 6px;
2514}
2515
2516QWidget#buttonsDialog,
2517QWidget#buttonsRichDialog {
2518 margin: 5px;
2519 border-top: 2px solid rgba(255, 255, 255, .9);
2520}
2521
2522QWidget#legendOSKnum {
2523 border-top: 1px solid rgba(255, 255, 255, 1);
2524}
2525
2526QStackedWidget#stackedDialog QTextBrowser QWidget {
2527 background: transparent;
2528}
2529
2530QStackedWidget#stackedDialog QTextBrowser QScrollBar {
2531 background: #19232d;
2532 border: none;
2533}
2534
2535QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-line,
2536QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-line {
2537 border-image: none;
2538}
2539
2540QWidget#mainOSK QStackedWidget,
2541QDialog#OverlayDialog QStackedWidget {
2542 border: none;
2543 padding: 0px;
2544}
2545
2546QWidget#inputOSK {
2547 border-bottom: 3px solid rgba(255, 255, 255, .9);
2548}
2549
2550QWidget#inputOSK QLineEdit {
2551 background: transparent;
2552 border: none;
2553 color: #ccc;
2554 padding: 0px;
2555}
2556
2557QWidget#inputBoxOSK {
2558 border: 2px solid rgba(255, 255, 255, .9);
2559}
2560
2561QWidget#inputBoxOSK QTextEdit {
2562 background: transparent;
2563 border: none;
2564 color: #ccc;
2565}
2566
2567QWidget#richDialog QTextBrowser {
2568 background: transparent;
2569 border: none;
2570 color: #fff;
2571 padding: 35px 65px;
2572}
2573
2574QWidget#lineOSK QLabel#label_header {
2575 color: #f0f0f0;
2576}
2577
2578QWidget#lineOSK QLabel#label_sub,
2579QWidget#lineOSK QLabel#label_characters,
2580QWidget#contentDialog QLabel#label_title,
2581QWidget#contentRichDialog QLabel#label_title_rich,
2582QWidget#boxOSK QLabel#label_characters_box {
2583 color: #ccc;
2584}
2585
2586QWidget#buttonsDialog,
2587QWidget#buttonsRichDialog,
2588QWidget#mainOSK,
2589QWidget#headerOSK,
2590QWidget#normalOSK,
2591QWidget#shiftOSK,
2592QWidget#numOSK,
2593QWidget#subOSK,
2594QWidget#inputOSK,
2595QWidget#inputBoxOSK,
2596QWidget#charactersOSK,
2597QWidget#charactersBoxOSK,
2598QWidget#legendOSK,
2599QWidget#legendOSK QWidget,
2600QWidget#legendOSKshift,
2601QWidget#legendOSKshift QWidget,
2602QWidget#legendOSKnum,
2603QWidget#legendOSKnum QWidget {
2604 background: transparent;
2605}
2606
2607QWidget#contentDialog QLabel,
2608QWidget#legendOSK QLabel,
2609QWidget#legendOSKshift QLabel,
2610QWidget#legendOSKnum QLabel {
2611 color: rgba(255, 255, 255, 1);
2612}
2613
2614QWidget#contentDialog QLabel#label_dialog {
2615 padding: 20px 65px;
2616}
2617
2618QWidget#contentDialog QLabel#label_title,
2619QWidget#contentRichDialog QLabel#label_title_rich {
2620 padding: 0px 65px;
2621}
2622
2623QDialog#OverlayDialog QPushButton {
2624 color: rgba(1, 253, 201, 1);
2625 background: transparent;
2626 border: none;
2627 padding: 0px;
2628 min-width: 0px;
2629}
2630
2631QDialog#OverlayDialog QPushButton:focus,
2632QDialog#OverlayDialog QPushButton:hover {
2633 color: rgba(1, 253, 201, 1);
2634 background: rgba(18, 33, 46, 1);
2635 border: 5px solid rgba(56, 189, 225, 1);
2636 border-radius: 6px;
2637 outline: none;
2638}
2639
2640QDialog#OverlayDialog QPushButton:pressed {
2641 color: rgba(240, 240, 240, 1);
2642 background: rgba(110, 122, 130, 1);
2643 border: 5px solid rgba(56, 189, 225, 1);
2644 border-radius: 6px;
2645 outline: none;
2646}
2647
2648QDialog#QtSoftwareKeyboardDialog QLabel {
2649 padding: 0px;
2650}
2651
2652QDialog#QtSoftwareKeyboardDialog QPushButton {
2653 color: rgba(255, 255, 255, 1);
2654 background: rgba(40, 51, 60, 1);
2655 border: 2px solid rgba(31, 41, 51, 1);
2656 border-radius: 0px;
2657 padding: 0px;
2658 min-width: 0px;
2659}
2660
2661QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift,
2662QDialog#QtSoftwareKeyboardDialog QPushButton#button_return,
2663QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
2664QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift,
2665QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift,
2666QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
2667 background: rgba(55, 66, 75, 1);
2668 border: 2px solid rgba(31, 41, 51, 1);
2669}
2670
2671QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
2672QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
2673QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
2674 color: rgba(240, 240, 240, 1);
2675 background: rgba(255, 255, 255, 1);
2676 border: 2px solid rgba(31, 41, 51, 1);
2677}
2678
2679QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
2680QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
2681QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
2682 color: rgba(0, 0, 0, 1);
2683 background: rgba(1, 253, 201, 1);
2684 border: 2px solid rgba(31, 41, 51, 1);
2685}
2686
2687QDialog#QtSoftwareKeyboardDialog QPushButton:focus,
2688QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:focus,
2689QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:focus,
2690QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:focus,
2691QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:focus,
2692QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:focus,
2693QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:focus,
2694QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:focus,
2695QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:focus,
2696QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:focus,
2697QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:focus,
2698QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:focus,
2699QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:focus,
2700
2701QDialog#QtSoftwareKeyboardDialog QPushButton:hover,
2702QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:hover,
2703QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:hover,
2704QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:hover,
2705QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:hover,
2706QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:hover,
2707QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:hover,
2708QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:hover,
2709QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:hover,
2710QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:hover,
2711QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:hover,
2712QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:hover,
2713QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:hover {
2714 color: rgba(255, 255, 255, 1);
2715 background: rgba(18, 33, 46, 1);
2716 border: 5px solid rgba(56, 189, 225, 1);
2717 border-radius: 6px;
2718 outline: none;
2719}
2720
2721QDialog#QtSoftwareKeyboardDialog QPushButton:pressed,
2722QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:pressed,
2723QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:pressed,
2724QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:pressed,
2725QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:pressed,
2726QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:pressed,
2727QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:pressed,
2728QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:pressed,
2729QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:pressed,
2730QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:pressed,
2731QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:pressed,
2732QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:pressed,
2733QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
2734 color: rgba(240, 240, 240, 1);
2735 background: rgba(110, 122, 130, 1);
2736 border: 5px solid rgba(56, 189, 225, 1);
2737 border-radius: 6px;
2738}
2739
2740QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
2741QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
2742QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
2743 background-position: right top;
2744 background-repeat: no-repeat;
2745 background-origin: content;
2746 background-image: url(:/overlay/osk_button_B_dark.png);
2747 qproperty-icon: url(:/overlay/osk_button_backspace_dark.png);
2748 qproperty-iconSize: 36px;
2749}
2750
2751QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
2752QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
2753 background-position: right top;
2754 background-repeat: no-repeat;
2755 background-origin: content;
2756 background-image: url(:/overlay/osk_button_Y_dark.png);
2757}
2758
2759QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
2760QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
2761QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
2762 color: rgba(44, 44, 44, 1);
2763 background-position: right top;
2764 background-repeat: no-repeat;
2765 background-origin: content;
2766 background-image: url(:/overlay/osk_button_plus_dark.png);
2767}
2768
2769QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
2770 background-position: left top;
2771 background-repeat: no-repeat;
2772 background-origin: content;
2773 background-image: url(:/overlay/osk_button_shift_lock_off.png);
2774 qproperty-icon: url(:/overlay/osk_button_shift_dark.png);
2775 qproperty-iconSize: 36px;
2776}
2777
2778QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
2779 background-position: left top;
2780 background-repeat: no-repeat;
2781 background-origin: content;
2782 background-image: url(:/overlay/osk_button_shift_lock_off.png);
2783 qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png);
2784 qproperty-iconSize: 36px;
2785}
2786
2787QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_bracket,
2788QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_bracket,
2789QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_parenthesis,
2790QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_parenthesis {
2791 padding-bottom: 7px;
2792}
2793
2794QDialog#QtSoftwareKeyboardDialog QWidget#titleOSK QLabel {
2795 background: transparent;
2796 color: #ccc;
2797}
2798
2799QDialog#QtSoftwareKeyboardDialog QWidget#button_L,
2800QDialog#QtSoftwareKeyboardDialog QWidget#button_L_shift,
2801QDialog#QtSoftwareKeyboardDialog QWidget#button_L_num {
2802 image: url(:/overlay/button_L_dark.png);
2803}
2804
2805QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left,
2806QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_shift,
2807QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_num {
2808 image: url(:/overlay/arrow_left_dark.png);
2809}
2810
2811QDialog#QtSoftwareKeyboardDialog QWidget#button_R,
2812QDialog#QtSoftwareKeyboardDialog QWidget#button_R_shift,
2813QDialog#QtSoftwareKeyboardDialog QWidget#button_R_num {
2814 image: url(:/overlay/button_R_dark.png);
2815}
2816
2817QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right,
2818QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_shift,
2819QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_num {
2820 image: url(:/overlay/arrow_right_dark.png);
2821}
2822
2823QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick,
2824QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick_shift {
2825 image: url(:/overlay/button_press_stick_dark.png);
2826}
2827
2828QDialog#QtSoftwareKeyboardDialog QWidget#button_X,
2829QDialog#QtSoftwareKeyboardDialog QWidget#button_X_shift,
2830QDialog#QtSoftwareKeyboardDialog QWidget#button_X_num {
2831 image: url(:/overlay/button_X_dark.png);
2832}
2833
2834QDialog#QtSoftwareKeyboardDialog QWidget#button_A,
2835QDialog#QtSoftwareKeyboardDialog QWidget#button_A_shift,
2836QDialog#QtSoftwareKeyboardDialog QWidget#button_A_num {
2837 image: url(:/overlay/button_A_dark.png);
2838}
2839
2840QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
2841QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
2842QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled,
2843QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
2844QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
2845QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled,
2846QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:disabled,
2847QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
2848QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled,
2849QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
2850 color: rgba(144, 144, 144, 1);
2851 background-color: rgba(55, 66, 75, 1);
2852}
2853
2854QDialog#QtSoftwareKeyboardDialog QPushButton#button_at:disabled,
2855QDialog#QtSoftwareKeyboardDialog QPushButton#button_slash:disabled,
2856QDialog#QtSoftwareKeyboardDialog QPushButton#button_percent:disabled,
2857QDialog#QtSoftwareKeyboardDialog QPushButton#button_1:disabled,
2858QDialog#QtSoftwareKeyboardDialog QPushButton#button_2:disabled,
2859QDialog#QtSoftwareKeyboardDialog QPushButton#button_3:disabled,
2860QDialog#QtSoftwareKeyboardDialog QPushButton#button_4:disabled,
2861QDialog#QtSoftwareKeyboardDialog QPushButton#button_5:disabled,
2862QDialog#QtSoftwareKeyboardDialog QPushButton#button_6:disabled,
2863QDialog#QtSoftwareKeyboardDialog QPushButton#button_7:disabled,
2864QDialog#QtSoftwareKeyboardDialog QPushButton#button_8:disabled,
2865QDialog#QtSoftwareKeyboardDialog QPushButton#button_9:disabled,
2866QDialog#QtSoftwareKeyboardDialog QPushButton#button_0:disabled,
2867QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
2868 color: rgba(144, 144, 144, 1);
2869}
2870
2871QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
2872QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
2873QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
2874 background-image: url(:/overlay/osk_button_plus_dark_disabled.png);
2875}
2876
2877QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
2878QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
2879QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
2880 background-image: url(:/overlay/osk_button_B_dark_disabled.png);
2881}
2882
2883QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
2884QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
2885 background-image: url(:/overlay/osk_button_Y_dark_disabled.png);
2886}
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
9namespace Core::Frontend { 11namespace Core::Frontend {
12
10SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default; 13SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default;
11 14
12void DefaultSoftwareKeyboardApplet::RequestText( 15DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default;
13 std::function<void(std::optional<std::u16string>)> out, 16
14 SoftwareKeyboardParameters parameters) const { 17void 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
65void 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
72void 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
78void 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); 107void DefaultSoftwareKeyboardApplet::HideInlineKeyboard() const {
108 LOG_WARNING(Service_AM,
109 "(STUBBED) called, backend requested to hide the inline software keyboard.");
19} 110}
20 111
21void DefaultSoftwareKeyboardApplet::SendTextCheckDialog( 112void 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
126void DefaultSoftwareKeyboardApplet::ExitKeyboard() const {
127 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to exit the software keyboard.");
28} 128}
129
130void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const {
131 submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text);
132}
133
134void 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
13namespace Core::Frontend { 14namespace Core::Frontend {
14struct SoftwareKeyboardParameters { 15
15 std::u16string submit_text; 16struct 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 }; 35struct 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
50struct InlineTextParameters {
51 std::u16string input_text;
52 s32 cursor_position;
34}; 53};
35 54
36class SoftwareKeyboardApplet { 55class SoftwareKeyboardApplet {
37public: 56public:
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
46class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet { 80class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet {
47public: 81public:
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
104private:
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
17InputInterpreter::~InputInterpreter() = default; 19InputInterpreter::~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
30void 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
28bool InputInterpreter::IsButtonPressed(HIDButton button) const { 41bool 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
622void AppletMessageQueue::RequestExit() {
623 PushMessage(AppletMessage::ExitRequested);
624}
625
626void AppletMessageQueue::FocusStateChanged() {
627 PushMessage(AppletMessage::FocusStateChanged);
628}
629
622void AppletMessageQueue::OperationModeChanged() { 630void 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
628void AppletMessageQueue::RequestExit() {
629 PushMessage(AppletMessage::ExitRequested);
630}
631
632ICommonStateGetter::ICommonStateGetter(Core::System& system_, 636ICommonStateGetter::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
1135void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { 1139void 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
1160void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { 1165void 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
1172void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { 1186void 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
1226void 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
67private: 68private:
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
259class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { 261class 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
28namespace Service::AM::Applets { 31namespace Service::AM::Applets {
29 32
30AppletDataBroker::AppletDataBroker(Kernel::KernelCore& kernel) { 33AppletDataBroker::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
115void AppletDataBroker::SignalStateChanged() const { 120void 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
119std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetNormalDataEvent() const { 145std::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
131Applet::Applet(Kernel::KernelCore& kernel_) : broker{kernel_} {} 157Applet::Applet(Core::System& system_, LibraryAppletMode applet_mode_)
158 : broker{system_, applet_mode_}, applet_mode{applet_mode_} {}
132 159
133Applet::~Applet() = default; 160Applet::~Applet() = default;
134 161
@@ -241,31 +268,31 @@ void AppletManager::ClearAll() {
241 frontend = {}; 268 frontend = {};
242} 269}
243 270
244std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const { 271std::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
65enum class LibraryAppletMode : u32 {
66 AllForeground = 0,
67 Background = 1,
68 NoUI = 2,
69 BackgroundIndirectDisplay = 3,
70 AllForegroundInitiallyHidden = 4,
71};
72
65class AppletDataBroker final { 73class AppletDataBroker final {
66public: 74public:
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
96private: 104private:
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
120class Applet { 131class Applet {
121public: 132public:
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
144protected: 159protected:
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
205private: 221private:
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
48Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_) 48Controller::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
51Controller::~Controller() = default; 52Controller::~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
107class Controller final : public Applet { 107class Controller final : public Applet {
108public: 108public:
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
89Error::Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_) 89Error::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
92Error::~Error() = default; 93Error::~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
26class Error final : public Applet { 26class Error final : public Applet {
27public: 27public:
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
40Auth::Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_) 40Auth::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
43Auth::~Auth() = default; 44Auth::~Auth() = default;
44 45
@@ -152,8 +153,9 @@ void Auth::AuthFinished(bool is_successful) {
152 broker.SignalStateChanged(); 153 broker.SignalStateChanged();
153} 154}
154 155
155PhotoViewer::PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_) 156PhotoViewer::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
158PhotoViewer::~PhotoViewer() = default; 160PhotoViewer::~PhotoViewer() = default;
159 161
@@ -202,8 +204,8 @@ void PhotoViewer::ViewFinished() {
202 broker.SignalStateChanged(); 204 broker.SignalStateChanged();
203} 205}
204 206
205StubApplet::StubApplet(Core::System& system_, AppletId id_) 207StubApplet::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
208StubApplet::~StubApplet() = default; 210StubApplet::~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
21class Auth final : public Applet { 21class Auth final : public Applet {
22public: 22public:
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
51class PhotoViewer final : public Applet { 52class PhotoViewer final : public Applet {
52public: 53public:
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
71class StubApplet final : public Applet { 73class StubApplet final : public Applet {
72public: 74public:
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
16constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1}; 16constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1};
17 17
18ProfileSelect::ProfileSelect(Core::System& system_, 18ProfileSelect::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
22ProfileSelect::~ProfileSelect() = default; 22ProfileSelect::~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
34class ProfileSelect final : public Applet { 34class ProfileSelect final : public Applet {
35public: 35public:
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
14namespace Service::AM::Applets { 11namespace Service::AM::Applets {
15 12
16namespace { 13namespace {
17enum 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, 16constexpr u32 DEFAULT_MAX_TEXT_LENGTH = 500;
20 SetCustomizeDic = 0x7, 17
21 Calc = 0xa, 18constexpr std::size_t REPLY_BASE_SIZE = sizeof(SwkbdState) + sizeof(SwkbdReplyType);
22 SetCustomizedDictionaries = 0xb, 19constexpr std::size_t REPLY_UTF8_SIZE = 0x7D4;
23 UnsetCustomizedDictionaries = 0xc, 20constexpr std::size_t REPLY_UTF16_SIZE = 0x3EC;
24 UnknownD = 0xd, 21
25 UnknownE = 0xe, 22constexpr const char* GetTextCheckResultName(SwkbdTextCheckResult text_check_result) {
26}; 23 switch (text_check_result) {
27constexpr std::size_t SWKBD_INLINE_INIT_SIZE = 0x8; 24 case SwkbdTextCheckResult::Success:
28constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8; 25 return "Success";
29constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4; 26 case SwkbdTextCheckResult::Failure:
30constexpr std::size_t DEFAULT_MAX_LENGTH = 500; 27 return "Failure";
31constexpr 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
38void 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
33static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( 44
34 KeyboardConfig config, std::u16string initial_text) { 45SoftwareKeyboard::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
54SoftwareKeyboard::SoftwareKeyboard(Core::System& system_,
55 const Core::Frontend::SoftwareKeyboardApplet& frontend_)
56 : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
57 48
58SoftwareKeyboard::~SoftwareKeyboard() = default; 49SoftwareKeyboard::~SoftwareKeyboard() = default;
59 50
60void SoftwareKeyboard::Initialize() { 51void 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
93bool SoftwareKeyboard::TransactionComplete() const { 80bool SoftwareKeyboard::TransactionComplete() const {
@@ -95,106 +82,996 @@ bool SoftwareKeyboard::TransactionComplete() const {
95} 82}
96 83
97ResultCode SoftwareKeyboard::GetStatus() const { 84ResultCode SoftwareKeyboard::GetStatus() const {
98 return RESULT_SUCCESS; 85 return status;
99} 86}
100 87
101void SoftwareKeyboard::ExecuteInteractive() { 88void 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
100void 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) { 112void 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
124void 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
140void SoftwareKeyboard::Execute() { 178void 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
244void 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
265void 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
154void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { 299void 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; 341void 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
368void 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
397void 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
457void SoftwareKeyboard::ChangeState(SwkbdState state) {
458 swkbd_state = state;
459
460 ReplyDefault();
461}
462
463void 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
587void SoftwareKeyboard::ShowNormalKeyboard() {
588 frontend.ShowNormalKeyboard();
589}
590
591void SoftwareKeyboard::ShowTextCheckDialog(SwkbdTextCheckResult text_check_result,
592 std::u16string text_check_message) {
593 frontend.ShowTextCheckDialog(text_check_result, text_check_message);
594}
595
596void 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
633void 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
645void 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
654void 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
665void 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
673void SoftwareKeyboard::RequestSetUserWordInfo(const std::vector<u8>& request_data) {
674 LOG_WARNING(Service_AM, "SetUserWordInfo is not implemented.");
675}
676
677void SoftwareKeyboard::RequestSetCustomizeDic(const std::vector<u8>& request_data) {
678 LOG_WARNING(Service_AM, "SetCustomizeDic is not implemented.");
679}
680
681void 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
736void SoftwareKeyboard::RequestSetCustomizedDictionaries(const std::vector<u8>& request_data) {
737 LOG_WARNING(Service_AM, "SetCustomizedDictionaries is not implemented.");
738}
739
740void SoftwareKeyboard::RequestUnsetCustomizedDictionaries(const std::vector<u8>& request_data) {
741 LOG_WARNING(Service_AM, "(STUBBED) Processing Request: UnsetCustomizedDictionaries");
742
743 ReplyUnsetCustomizedDictionaries();
744}
745
746void 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
754void 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
764void 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
774void 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
784void 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
806void 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
826void 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
846void 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
867void 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
879void 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
902void 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
923void 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
945void 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
955void 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
965void 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
975void 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
1001void 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
1025void 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
1052void 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"
17union ResultCode;
18 12
19namespace Core { 13namespace Core {
20class System; 14class System;
@@ -22,45 +16,10 @@ class System;
22 16
23namespace Service::AM::Applets { 17namespace Service::AM::Applets {
24 18
25enum class KeysetDisable : u32 {
26 Space = 0x02,
27 Address = 0x04,
28 Percent = 0x08,
29 Slashes = 0x10,
30 Numbers = 0x40,
31 DownloadCode = 0x80,
32};
33
34struct 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};
58static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect size.");
59
60class SoftwareKeyboard final : public Applet { 19class SoftwareKeyboard final : public Applet {
61public: 20public:
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
75private: 55private:
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
14namespace Service::AM::Applets {
15
16constexpr std::size_t MAX_OK_TEXT_LENGTH = 8;
17constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64;
18constexpr std::size_t MAX_SUB_TEXT_LENGTH = 128;
19constexpr std::size_t MAX_GUIDE_TEXT_LENGTH = 256;
20constexpr std::size_t STRING_BUFFER_SIZE = 0x7D4;
21
22enum 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
32enum class SwkbdType : u32 {
33 Normal,
34 NumberPad,
35 Qwerty,
36 Unknown3,
37 Latin,
38 SimplifiedChinese,
39 TraditionalChinese,
40 Korean,
41};
42
43enum class SwkbdInitialCursorPosition : u32 {
44 Start,
45 End,
46};
47
48enum class SwkbdPasswordMode : u32 {
49 Disabled,
50 Enabled,
51};
52
53enum class SwkbdTextDrawType : u32 {
54 Line,
55 Box,
56 DownloadCode,
57};
58
59enum class SwkbdResult : u32 {
60 Ok,
61 Cancel,
62};
63
64enum class SwkbdTextCheckResult : u32 {
65 Success,
66 Failure,
67 Confirm,
68 Silent,
69};
70
71enum class SwkbdState : u32 {
72 NotInitialized = 0x0,
73 InitializedIsHidden = 0x1,
74 InitializedIsAppearing = 0x2,
75 InitializedIsShown = 0x3,
76 InitializedIsDisappearing = 0x4,
77};
78
79enum 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
90enum 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
110struct 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};
124static_assert(sizeof(SwkbdKeyDisableFlags) == 0x4, "SwkbdKeyDisableFlags has incorrect size.");
125
126struct 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};
153static_assert(sizeof(SwkbdConfigCommon) == 0x3D4, "SwkbdConfigCommon has incorrect size.");
154
155#pragma pack(push, 4)
156// SwkbdAppletVersion 0x5, 0x10006
157struct SwkbdConfigOld {
158 INSERT_PADDING_WORDS(1);
159 VAddr text_check_callback{};
160};
161static_assert(sizeof(SwkbdConfigOld) == 0x3E0 - sizeof(SwkbdConfigCommon),
162 "SwkbdConfigOld has incorrect size.");
163
164// SwkbdAppletVersion 0x30007, 0x40008, 0x50009
165struct SwkbdConfigOld2 {
166 INSERT_PADDING_WORDS(1);
167 VAddr text_check_callback{};
168 std::array<u32, 8> text_grouping{};
169};
170static_assert(sizeof(SwkbdConfigOld2) == 0x400 - sizeof(SwkbdConfigCommon),
171 "SwkbdConfigOld2 has incorrect size.");
172
173// SwkbdAppletVersion 0x6000B, 0x8000D
174struct 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};
181static_assert(sizeof(SwkbdConfigNew) == 0x4C8 - sizeof(SwkbdConfigCommon),
182 "SwkbdConfigNew has incorrect size.");
183#pragma pack(pop)
184
185struct SwkbdTextCheck {
186 SwkbdTextCheckResult text_check_result{};
187 std::array<char16_t, STRING_BUFFER_SIZE / 2> text_check_message{};
188};
189static_assert(sizeof(SwkbdTextCheck) == 0x7D8, "SwkbdTextCheck has incorrect size.");
190
191struct 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};
209static_assert(sizeof(SwkbdCalcArgFlags) == 0x8, "SwkbdCalcArgFlags has incorrect size.");
210
211struct SwkbdInitializeArg {
212 u32 unknown{};
213 bool library_applet_mode_flag{};
214 bool is_above_hos_500{};
215 INSERT_PADDING_BYTES(2);
216};
217static_assert(sizeof(SwkbdInitializeArg) == 0x8, "SwkbdInitializeArg has incorrect size.");
218
219struct 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};
234static_assert(sizeof(SwkbdAppearArg) == 0x48, "SwkbdAppearArg has incorrect size.");
235
236struct 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};
268static_assert(sizeof(SwkbdCalcArg) == 0x4A0, "SwkbdCalcArg has incorrect size.");
269
270struct SwkbdChangedStringArg {
271 u32 text_length{};
272 s32 dictionary_start_cursor_position{};
273 s32 dictionary_end_cursor_position{};
274 s32 cursor_position{};
275};
276static_assert(sizeof(SwkbdChangedStringArg) == 0x10, "SwkbdChangedStringArg has incorrect size.");
277
278struct SwkbdMovedCursorArg {
279 u32 text_length{};
280 s32 cursor_position{};
281};
282static_assert(sizeof(SwkbdMovedCursorArg) == 0x8, "SwkbdMovedCursorArg has incorrect size.");
283
284struct SwkbdMovedTabArg {
285 u32 text_length{};
286 s32 cursor_position{};
287};
288static_assert(sizeof(SwkbdMovedTabArg) == 0x8, "SwkbdMovedTabArg has incorrect size.");
289
290struct SwkbdDecidedEnterArg {
291 u32 text_length{};
292};
293static_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
211WebBrowser::WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_) 211WebBrowser::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
214WebBrowser::~WebBrowser() = default; 215WebBrowser::~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
26class WebBrowser final : public Applet { 26class WebBrowser final : public Applet {
27public: 27public:
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
72void nvhost_nvdec::OnOpen(DeviceFD fd) {} 67void nvhost_nvdec::OnOpen(DeviceFD fd) {}
73void nvhost_nvdec::OnClose(DeviceFD fd) {} 68
69void 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
495void 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
499void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { 501void 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;
19void QtErrorDisplay::ShowError(ResultCode error, std::function<void()> finished) const { 19void 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
29void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, 29void 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
44void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_text, 45void 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
26signals: 26signals:
27 void MainWindowDisplayError(QString error) const; 27 void MainWindowDisplayError(QString error_code, QString error_text) const;
28 28
29private: 29private:
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
19namespace {
20
21using namespace Service::AM::Applets;
22
23constexpr float BASE_HEADER_FONT_SIZE = 23.0f;
24constexpr float BASE_SUB_FONT_SIZE = 17.0f;
25constexpr float BASE_EDITOR_FONT_SIZE = 26.0f;
26constexpr float BASE_CHAR_BUTTON_FONT_SIZE = 28.0f;
27constexpr float BASE_LABEL_BUTTON_FONT_SIZE = 18.0f;
28constexpr float BASE_ICON_BUTTON_SIZE = 36.0f;
29[[maybe_unused]] constexpr float BASE_WIDTH = 1280.0f;
30constexpr float BASE_HEIGHT = 720.0f;
31
32} // Anonymous namespace
33
34QtSoftwareKeyboardDialog::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
16QtSoftwareKeyboardValidator::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
20QValidator::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
364QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() {
365 StopInputThread();
366}
367
368void 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
384void 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
418void 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
447void QtSoftwareKeyboardDialog::HideInlineKeyboard() {
448 StopInputThread();
449 QDialog::hide();
450}
451
452void 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
460void QtSoftwareKeyboardDialog::ExitKeyboard() {
461 StopInputThread();
462 QDialog::done(QDialog::Accepted);
463}
464
465void 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
480void 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
490void 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
51QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog( 551void 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)); 561void 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
629void 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
663void 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
675void 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
809void 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
876void 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
934void 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
104QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default; 977bool 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
106void 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
111void QtSoftwareKeyboardDialog::reject() { 1023void 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
116std::u16string QtSoftwareKeyboardDialog::GetText() const { 1076void 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
1146void 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
1204void 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
1218void 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
1230template <HIDButton... T>
1231void 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
1241template <HIDButton... T>
1242void 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
1252void 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
1368void 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
1426void 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
1465void 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
1475void 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
1487void 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
120QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& main_window) { 1509QtSoftwareKeyboard::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
129QtSoftwareKeyboard::~QtSoftwareKeyboard() = default; 1530QtSoftwareKeyboard::~QtSoftwareKeyboard() = default;
130 1531
131void QtSoftwareKeyboard::RequestText(std::function<void(std::optional<std::u16string>)> out, 1532void 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
1577void QtSoftwareKeyboard::ShowNormalKeyboard() const {
1578 emit MainWindowShowNormalKeyboard();
1579}
1580
1581void 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
1587void 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
1613void QtSoftwareKeyboard::HideInlineKeyboard() const {
1614 emit MainWindowHideInlineKeyboard();
1615}
1616
1617void 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
137void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message, 1628void 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
143void QtSoftwareKeyboard::MainWindowFinishedText(std::optional<std::u16string> text) { 1632void 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
149void QtSoftwareKeyboard::MainWindowFinishedCheckDialog() { 1637void 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
11class GMainWindow; 17enum class HIDButton : u8;
12class QDialogButtonBox;
13class QLabel;
14class QLineEdit;
15class QVBoxLayout;
16class QtSoftwareKeyboard;
17 18
18class QtSoftwareKeyboardValidator final : public QValidator { 19class InputInterpreter;
19public:
20 explicit QtSoftwareKeyboardValidator(Core::Frontend::SoftwareKeyboardParameters parameters);
21 State validate(QString& input, int& pos) const override;
22 20
23private: 21namespace Core {
24 Core::Frontend::SoftwareKeyboardParameters parameters; 22class System;
25}; 23}
24
25namespace Ui {
26class QtSoftwareKeyboardDialog;
27}
28
29class GMainWindow;
26 30
27class QtSoftwareKeyboardDialog final : public QDialog { 31class QtSoftwareKeyboardDialog final : public QDialog {
28 Q_OBJECT 32 Q_OBJECT
29 33
30public: 34public:
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
53signals:
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
60public slots:
61 void open() override;
36 void reject() override; 62 void reject() override;
37 63
38 std::u16string GetText() const; 64protected:
65 /// We override the keyPressEvent for inputting text into the inline software keyboard.
66 void keyPressEvent(QKeyEvent* event) override;
39 67
40private: 68private:
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
54class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet { 228class 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
66signals: 256signals:
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
70private: 274private:
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>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
480&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
481p, li { white-space: pre-wrap; }
482&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:26pt; font-weight:400; font-style:normal;&quot;&gt;
483&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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">&quot;</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">&amp;&amp;</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">&lt;</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">&gt;</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
381void 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
378void GMainWindow::ControllerSelectorReconfigureControllers( 430void 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
417void GMainWindow::SoftwareKeyboardGetText( 469void 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
497void 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
433void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message) { 513void 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
524void 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
548void 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
557void 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
567void GMainWindow::SoftwareKeyboardExit() {
568 if (!software_keyboard) {
569 return;
570 }
571
572 software_keyboard->ExitKeyboard();
573
574 software_keyboard = nullptr;
436} 575}
437 576
438void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args, 577void 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
2247void GMainWindow::ErrorDisplayDisplayError(QString body) { 2381void 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;
37enum class InstalledEntryType; 37enum class InstalledEntryType;
38class GameListPlaceholder; 38class GameListPlaceholder;
39 39
40class QtSoftwareKeyboardDialog;
41
40namespace Core::Frontend { 42namespace Core::Frontend {
41struct ControllerParameters; 43struct ControllerParameters;
42struct SoftwareKeyboardParameters; 44struct InlineAppearParameters;
45struct InlineTextParameters;
46struct KeyboardInitializeParameters;
43} // namespace Core::Frontend 47} // namespace Core::Frontend
44 48
45namespace DiscordRPC { 49namespace DiscordRPC {
@@ -57,8 +61,11 @@ class InputSubsystem;
57} 61}
58 62
59namespace Service::AM::Applets { 63namespace Service::AM::Applets {
64enum class SwkbdResult : u32;
65enum class SwkbdTextCheckResult : u32;
66enum class SwkbdReplyType : u32;
60enum class WebExitReason : u32; 67enum class WebExitReason : u32;
61} 68} // namespace Service::AM::Applets
62 69
63enum class EmulatedDirectoryTarget { 70enum 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
150private: 166private:
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
337protected: 358protected:
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
13namespace {
14
15constexpr float BASE_TITLE_FONT_SIZE = 14.0f;
16constexpr float BASE_FONT_SIZE = 18.0f;
17constexpr float BASE_WIDTH = 1280.0f;
18constexpr float BASE_HEIGHT = 720.0f;
19
20} // Anonymous namespace
21
22OverlayDialog::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
52OverlayDialog::~OverlayDialog() {
53 StopInputThread();
54}
55
56void 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
102void 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
149void 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
182template <HIDButton... T>
183void 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
193void 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
222void 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
232void OverlayDialog::StopInputThread() {
233 input_thread_running = false;
234
235 if (input_thread.joinable()) {
236 input_thread.join();
237 }
238}
239
240void 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
16enum class HIDButton : u8;
17
18class InputInterpreter;
19
20namespace Core {
21class System;
22}
23
24namespace Ui {
25class 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 */
35class OverlayDialog final : public QDialog {
36 Q_OBJECT
37
38public:
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
45private:
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>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
314&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
315p, li { white-space: pre-wrap; }
316&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:18pt; font-weight:400; font-style:normal;&quot;&gt;
317&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>