summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dist/icons/controller/applet_dual_joycon.pngbin0 -> 3554 bytes
-rw-r--r--dist/icons/controller/applet_dual_joycon_dark.pngbin0 -> 3554 bytes
-rw-r--r--dist/icons/controller/applet_dual_joycon_dark_disabled.pngbin0 -> 3527 bytes
-rw-r--r--dist/icons/controller/applet_dual_joycon_disabled.pngbin0 -> 3314 bytes
-rw-r--r--dist/icons/controller/applet_dual_joycon_midnight.pngbin0 -> 3549 bytes
-rw-r--r--dist/icons/controller/applet_dual_joycon_midnight_disabled.pngbin0 -> 3584 bytes
-rw-r--r--dist/icons/controller/applet_handheld.pngbin0 -> 1671 bytes
-rw-r--r--dist/icons/controller/applet_handheld_dark.pngbin0 -> 1637 bytes
-rw-r--r--dist/icons/controller/applet_handheld_dark_disabled.pngbin0 -> 2642 bytes
-rw-r--r--dist/icons/controller/applet_handheld_disabled.pngbin0 -> 2221 bytes
-rw-r--r--dist/icons/controller/applet_handheld_midnight.pngbin0 -> 1644 bytes
-rw-r--r--dist/icons/controller/applet_handheld_midnight_disabled.pngbin0 -> 2634 bytes
-rw-r--r--dist/icons/controller/applet_pro_controller.pngbin0 -> 4382 bytes
-rw-r--r--dist/icons/controller/applet_pro_controller_dark.pngbin0 -> 4236 bytes
-rw-r--r--dist/icons/controller/applet_pro_controller_dark_disabled.pngbin0 -> 4477 bytes
-rw-r--r--dist/icons/controller/applet_pro_controller_disabled.pngbin0 -> 4173 bytes
-rw-r--r--dist/icons/controller/applet_pro_controller_midnight.pngbin0 -> 4376 bytes
-rw-r--r--dist/icons/controller/applet_pro_controller_midnight_disabled.pngbin0 -> 4459 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_left.pngbin0 -> 2083 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_left_dark.pngbin0 -> 2067 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_left_dark_disabled.pngbin0 -> 2520 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_left_disabled.pngbin0 -> 2179 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_left_midnight.pngbin0 -> 2065 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_left_midnight_disabled.pngbin0 -> 2529 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_right.pngbin0 -> 2150 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_right_dark.pngbin0 -> 2146 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_right_dark_disabled.pngbin0 -> 2556 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_right_disabled.pngbin0 -> 2212 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_right_midnight.pngbin0 -> 2150 bytes
-rw-r--r--dist/icons/controller/applet_single_joycon_right_midnight_disabled.pngbin0 -> 2611 bytes
-rw-r--r--dist/icons/controller/controller.qrc30
-rw-r--r--dist/qt_themes/default/style.qss206
-rw-r--r--dist/qt_themes/qdarkstyle/style.qss290
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/style.qss270
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/frontend/applets/controller.cpp40
-rw-r--r--src/core/frontend/applets/controller.h45
-rw-r--r--src/core/hle/service/am/applets/applets.cpp71
-rw-r--r--src/core/hle/service/am/applets/applets.h19
-rw-r--r--src/core/hle/service/am/applets/controller.cpp197
-rw-r--r--src/core/hle/service/am/applets/controller.h119
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp28
-rw-r--r--src/core/hle/service/hid/controllers/npad.h6
-rw-r--r--src/yuzu/CMakeLists.txt12
-rw-r--r--src/yuzu/applets/controller.cpp568
-rw-r--r--src/yuzu/applets/controller.h125
-rw-r--r--src/yuzu/applets/controller.ui2432
-rw-r--r--src/yuzu/configuration/configure_input.cpp21
-rw-r--r--src/yuzu/configuration/configure_input.h2
-rw-r--r--src/yuzu/configuration/configure_input_dialog.cpp37
-rw-r--r--src/yuzu/configuration/configure_input_dialog.h38
-rw-r--r--src/yuzu/configuration/configure_input_dialog.ui57
-rw-r--r--src/yuzu/main.cpp35
-rw-r--r--src/yuzu/main.h6
54 files changed, 4515 insertions, 143 deletions
diff --git a/dist/icons/controller/applet_dual_joycon.png b/dist/icons/controller/applet_dual_joycon.png
new file mode 100644
index 000000000..32e0a04ae
--- /dev/null
+++ b/dist/icons/controller/applet_dual_joycon.png
Binary files differ
diff --git a/dist/icons/controller/applet_dual_joycon_dark.png b/dist/icons/controller/applet_dual_joycon_dark.png
new file mode 100644
index 000000000..6adc66356
--- /dev/null
+++ b/dist/icons/controller/applet_dual_joycon_dark.png
Binary files differ
diff --git a/dist/icons/controller/applet_dual_joycon_dark_disabled.png b/dist/icons/controller/applet_dual_joycon_dark_disabled.png
new file mode 100644
index 000000000..208603ee7
--- /dev/null
+++ b/dist/icons/controller/applet_dual_joycon_dark_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_dual_joycon_disabled.png b/dist/icons/controller/applet_dual_joycon_disabled.png
new file mode 100644
index 000000000..43950618d
--- /dev/null
+++ b/dist/icons/controller/applet_dual_joycon_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_dual_joycon_midnight.png b/dist/icons/controller/applet_dual_joycon_midnight.png
new file mode 100644
index 000000000..c7edea8a3
--- /dev/null
+++ b/dist/icons/controller/applet_dual_joycon_midnight.png
Binary files differ
diff --git a/dist/icons/controller/applet_dual_joycon_midnight_disabled.png b/dist/icons/controller/applet_dual_joycon_midnight_disabled.png
new file mode 100644
index 000000000..ee1aafc85
--- /dev/null
+++ b/dist/icons/controller/applet_dual_joycon_midnight_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_handheld.png b/dist/icons/controller/applet_handheld.png
new file mode 100644
index 000000000..7f8dd2227
--- /dev/null
+++ b/dist/icons/controller/applet_handheld.png
Binary files differ
diff --git a/dist/icons/controller/applet_handheld_dark.png b/dist/icons/controller/applet_handheld_dark.png
new file mode 100644
index 000000000..41f6d7aea
--- /dev/null
+++ b/dist/icons/controller/applet_handheld_dark.png
Binary files differ
diff --git a/dist/icons/controller/applet_handheld_dark_disabled.png b/dist/icons/controller/applet_handheld_dark_disabled.png
new file mode 100644
index 000000000..5a136ddd1
--- /dev/null
+++ b/dist/icons/controller/applet_handheld_dark_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_handheld_disabled.png b/dist/icons/controller/applet_handheld_disabled.png
new file mode 100644
index 000000000..53f8ce7ad
--- /dev/null
+++ b/dist/icons/controller/applet_handheld_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_handheld_midnight.png b/dist/icons/controller/applet_handheld_midnight.png
new file mode 100644
index 000000000..7188b9154
--- /dev/null
+++ b/dist/icons/controller/applet_handheld_midnight.png
Binary files differ
diff --git a/dist/icons/controller/applet_handheld_midnight_disabled.png b/dist/icons/controller/applet_handheld_midnight_disabled.png
new file mode 100644
index 000000000..6ccfc3253
--- /dev/null
+++ b/dist/icons/controller/applet_handheld_midnight_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_pro_controller.png b/dist/icons/controller/applet_pro_controller.png
new file mode 100644
index 000000000..e32258855
--- /dev/null
+++ b/dist/icons/controller/applet_pro_controller.png
Binary files differ
diff --git a/dist/icons/controller/applet_pro_controller_dark.png b/dist/icons/controller/applet_pro_controller_dark.png
new file mode 100644
index 000000000..c122b7b11
--- /dev/null
+++ b/dist/icons/controller/applet_pro_controller_dark.png
Binary files differ
diff --git a/dist/icons/controller/applet_pro_controller_dark_disabled.png b/dist/icons/controller/applet_pro_controller_dark_disabled.png
new file mode 100644
index 000000000..416e1e2fb
--- /dev/null
+++ b/dist/icons/controller/applet_pro_controller_dark_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_pro_controller_disabled.png b/dist/icons/controller/applet_pro_controller_disabled.png
new file mode 100644
index 000000000..72a549ea9
--- /dev/null
+++ b/dist/icons/controller/applet_pro_controller_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_pro_controller_midnight.png b/dist/icons/controller/applet_pro_controller_midnight.png
new file mode 100644
index 000000000..622e57fa1
--- /dev/null
+++ b/dist/icons/controller/applet_pro_controller_midnight.png
Binary files differ
diff --git a/dist/icons/controller/applet_pro_controller_midnight_disabled.png b/dist/icons/controller/applet_pro_controller_midnight_disabled.png
new file mode 100644
index 000000000..2907f3be4
--- /dev/null
+++ b/dist/icons/controller/applet_pro_controller_midnight_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_left.png b/dist/icons/controller/applet_single_joycon_left.png
new file mode 100644
index 000000000..47c44d43a
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_left.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_left_dark.png b/dist/icons/controller/applet_single_joycon_left_dark.png
new file mode 100644
index 000000000..69530b69c
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_left_dark.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_left_dark_disabled.png b/dist/icons/controller/applet_single_joycon_left_dark_disabled.png
new file mode 100644
index 000000000..cfe4b1475
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_left_dark_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_left_disabled.png b/dist/icons/controller/applet_single_joycon_left_disabled.png
new file mode 100644
index 000000000..c0102dc20
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_left_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_left_midnight.png b/dist/icons/controller/applet_single_joycon_left_midnight.png
new file mode 100644
index 000000000..56522bccb
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_left_midnight.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_left_midnight_disabled.png b/dist/icons/controller/applet_single_joycon_left_midnight_disabled.png
new file mode 100644
index 000000000..62434c188
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_left_midnight_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_right.png b/dist/icons/controller/applet_single_joycon_right.png
new file mode 100644
index 000000000..b0d4fba90
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_right.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_right_dark.png b/dist/icons/controller/applet_single_joycon_right_dark.png
new file mode 100644
index 000000000..af26cce4b
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_right_dark.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_right_dark_disabled.png b/dist/icons/controller/applet_single_joycon_right_dark_disabled.png
new file mode 100644
index 000000000..b33efab42
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_right_dark_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_right_disabled.png b/dist/icons/controller/applet_single_joycon_right_disabled.png
new file mode 100644
index 000000000..01ca38322
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_right_disabled.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_right_midnight.png b/dist/icons/controller/applet_single_joycon_right_midnight.png
new file mode 100644
index 000000000..5bf70e21e
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_right_midnight.png
Binary files differ
diff --git a/dist/icons/controller/applet_single_joycon_right_midnight_disabled.png b/dist/icons/controller/applet_single_joycon_right_midnight_disabled.png
new file mode 100644
index 000000000..e6693b027
--- /dev/null
+++ b/dist/icons/controller/applet_single_joycon_right_midnight_disabled.png
Binary files differ
diff --git a/dist/icons/controller/controller.qrc b/dist/icons/controller/controller.qrc
index f44725d8f..76083a9ac 100644
--- a/dist/icons/controller/controller.qrc
+++ b/dist/icons/controller/controller.qrc
@@ -21,5 +21,35 @@
21 <file alias="single_joycon_right_vertical">single_joycon_right_vertical.png</file> 21 <file alias="single_joycon_right_vertical">single_joycon_right_vertical.png</file>
22 <file alias="single_joycon_right_vertical_dark">single_joycon_right_vertical_dark.png</file> 22 <file alias="single_joycon_right_vertical_dark">single_joycon_right_vertical_dark.png</file>
23 <file alias="single_joycon_right_vertical_midnight">single_joycon_right_vertical_midnight.png</file> 23 <file alias="single_joycon_right_vertical_midnight">single_joycon_right_vertical_midnight.png</file>
24 <file alias="applet_dual_joycon">applet_dual_joycon.png</file>
25 <file alias="applet_dual_joycon_dark">applet_dual_joycon_dark.png</file>
26 <file alias="applet_dual_joycon_midnight">applet_dual_joycon_midnight.png</file>
27 <file alias="applet_handheld">applet_handheld.png</file>
28 <file alias="applet_handheld_dark">applet_handheld_dark.png</file>
29 <file alias="applet_handheld_midnight">applet_handheld_midnight.png</file>
30 <file alias="applet_pro_controller">applet_pro_controller.png</file>
31 <file alias="applet_pro_controller_dark">applet_pro_controller_dark.png</file>
32 <file alias="applet_pro_controller_midnight">applet_pro_controller_midnight.png</file>
33 <file alias="applet_joycon_left">applet_single_joycon_left.png</file>
34 <file alias="applet_joycon_left_dark">applet_single_joycon_left_dark.png</file>
35 <file alias="applet_joycon_left_midnight">applet_single_joycon_left_midnight.png</file>
36 <file alias="applet_joycon_right">applet_single_joycon_right.png</file>
37 <file alias="applet_joycon_right_dark">applet_single_joycon_right_dark.png</file>
38 <file alias="applet_joycon_right_midnight">applet_single_joycon_right_midnight.png</file>
39 <file alias="applet_dual_joycon_disabled">applet_dual_joycon_disabled.png</file>
40 <file alias="applet_dual_joycon_dark_disabled">applet_dual_joycon_dark_disabled.png</file>
41 <file alias="applet_dual_joycon_midnight_disabled">applet_dual_joycon_midnight_disabled.png</file>
42 <file alias="applet_handheld_disabled">applet_handheld_disabled.png</file>
43 <file alias="applet_handheld_dark_disabled">applet_handheld_dark_disabled.png</file>
44 <file alias="applet_handheld_midnight_disabled">applet_handheld_midnight_disabled.png</file>
45 <file alias="applet_pro_controller_disabled">applet_pro_controller_disabled.png</file>
46 <file alias="applet_pro_controller_dark_disabled">applet_pro_controller_dark_disabled.png</file>
47 <file alias="applet_pro_controller_midnight_disabled">applet_pro_controller_midnight_disabled.png</file>
48 <file alias="applet_joycon_left_disabled">applet_single_joycon_left_disabled.png</file>
49 <file alias="applet_joycon_left_dark_disabled">applet_single_joycon_left_dark_disabled.png</file>
50 <file alias="applet_joycon_left_midnight_disabled">applet_single_joycon_left_midnight_disabled.png</file>
51 <file alias="applet_joycon_right_disabled">applet_single_joycon_right_disabled.png</file>
52 <file alias="applet_joycon_right_dark_disabled">applet_single_joycon_right_dark_disabled.png</file>
53 <file alias="applet_joycon_right_midnight_disabled">applet_single_joycon_right_midnight_disabled.png</file>
24 </qresource> 54 </qresource>
25</RCC> 55</RCC>
diff --git a/dist/qt_themes/default/style.qss b/dist/qt_themes/default/style.qss
index 5da56520b..5b05b436b 100644
--- a/dist/qt_themes/default/style.qss
+++ b/dist/qt_themes/default/style.qss
@@ -41,6 +41,99 @@ QPushButton#buttonRefreshDevices {
41 max-height: 20px; 41 max-height: 20px;
42} 42}
43 43
44QWidget#bottomPerGameInput,
45QWidget#topControllerApplet,
46QWidget#bottomControllerApplet,
47QGroupBox#groupPlayer1Connected:checked,
48QGroupBox#groupPlayer2Connected:checked,
49QGroupBox#groupPlayer3Connected:checked,
50QGroupBox#groupPlayer4Connected:checked,
51QGroupBox#groupPlayer5Connected:checked,
52QGroupBox#groupPlayer6Connected:checked,
53QGroupBox#groupPlayer7Connected:checked,
54QGroupBox#groupPlayer8Connected:checked {
55 background-color: #f5f5f5;
56}
57
58QWidget#topControllerApplet {
59 border-bottom: 1px solid #828790
60}
61
62QWidget#bottomPerGameInput,
63QWidget#bottomControllerApplet {
64 border-top: 1px solid #828790
65}
66
67QWidget#topPerGameInput,
68QWidget#middleControllerApplet {
69 background-color: #fff;
70}
71
72QWidget#topPerGameInput QComboBox,
73QWidget#middleControllerApplet QComboBox {
74 width: 123px;
75}
76
77QWidget#connectedControllers {
78 background: transparent;
79}
80
81QWidget#playersSupported,
82QWidget#controllersSupported,
83QWidget#controllerSupported1,
84QWidget#controllerSupported2,
85QWidget#controllerSupported3,
86QWidget#controllerSupported4,
87QWidget#controllerSupported5,
88QWidget#controllerSupported6 {
89 border: none;
90 background: transparent;
91}
92
93QGroupBox#groupPlayer1Connected,
94QGroupBox#groupPlayer2Connected,
95QGroupBox#groupPlayer3Connected,
96QGroupBox#groupPlayer4Connected,
97QGroupBox#groupPlayer5Connected,
98QGroupBox#groupPlayer6Connected,
99QGroupBox#groupPlayer7Connected,
100QGroupBox#groupPlayer8Connected {
101 border: 1px solid #828790;
102 border-radius: 3px;
103 padding: 0px;
104 min-height: 98px;
105 max-height: 98px;
106}
107
108QGroupBox#groupPlayer1Connected:unchecked,
109QGroupBox#groupPlayer2Connected:unchecked,
110QGroupBox#groupPlayer3Connected:unchecked,
111QGroupBox#groupPlayer4Connected:unchecked,
112QGroupBox#groupPlayer5Connected:unchecked,
113QGroupBox#groupPlayer6Connected:unchecked,
114QGroupBox#groupPlayer7Connected:unchecked,
115QGroupBox#groupPlayer8Connected:unchecked {
116 border: 1px solid #d9d9d9;
117}
118
119QGroupBox#groupPlayer1Connected::title,
120QGroupBox#groupPlayer2Connected::title,
121QGroupBox#groupPlayer3Connected::title,
122QGroupBox#groupPlayer4Connected::title,
123QGroupBox#groupPlayer5Connected::title,
124QGroupBox#groupPlayer6Connected::title,
125QGroupBox#groupPlayer7Connected::title,
126QGroupBox#groupPlayer8Connected::title {
127 subcontrol-origin: margin;
128 subcontrol-position: top left;
129 padding-left: 0px;
130 padding-right: 0px;
131 padding-top: 1px;
132 margin-left: 0px;
133 margin-right: -4px;
134 margin-bottom: 4px;
135}
136
44QCheckBox#checkboxPlayer1Connected, 137QCheckBox#checkboxPlayer1Connected,
45QCheckBox#checkboxPlayer2Connected, 138QCheckBox#checkboxPlayer2Connected,
46QCheckBox#checkboxPlayer3Connected, 139QCheckBox#checkboxPlayer3Connected,
@@ -49,7 +142,43 @@ QCheckBox#checkboxPlayer5Connected,
49QCheckBox#checkboxPlayer6Connected, 142QCheckBox#checkboxPlayer6Connected,
50QCheckBox#checkboxPlayer7Connected, 143QCheckBox#checkboxPlayer7Connected,
51QCheckBox#checkboxPlayer8Connected { 144QCheckBox#checkboxPlayer8Connected {
52 spacing: 0px; 145 spacing: 0px;
146}
147
148QWidget#Player1LEDs QCheckBox,
149QWidget#Player2LEDs QCheckBox,
150QWidget#Player3LEDs QCheckBox,
151QWidget#Player4LEDs QCheckBox,
152QWidget#Player5LEDs QCheckBox,
153QWidget#Player6LEDs QCheckBox,
154QWidget#Player7LEDs QCheckBox,
155QWidget#Player8LEDs QCheckBox {
156 spacing: 0px;
157}
158
159QWidget#Player1LEDs QCheckBox::indicator,
160QWidget#Player2LEDs QCheckBox::indicator,
161QWidget#Player3LEDs QCheckBox::indicator,
162QWidget#Player4LEDs QCheckBox::indicator,
163QWidget#Player5LEDs QCheckBox::indicator,
164QWidget#Player6LEDs QCheckBox::indicator,
165QWidget#Player7LEDs QCheckBox::indicator,
166QWidget#Player8LEDs QCheckBox::indicator {
167 width: 6px;
168 height: 6px;
169 margin-left: 0px;
170}
171
172QWidget#bottomPerGameInput QCheckBox#checkboxPlayer1Connected::indicator,
173QWidget#bottomPerGameInput QCheckBox#checkboxPlayer2Connected::indicator,
174QWidget#bottomPerGameInput QCheckBox#checkboxPlayer3Connected::indicator,
175QWidget#bottomPerGameInput QCheckBox#checkboxPlayer4Connected::indicator,
176QWidget#bottomPerGameInput QCheckBox#checkboxPlayer5Connected::indicator,
177QWidget#bottomPerGameInput QCheckBox#checkboxPlayer6Connected::indicator,
178QWidget#bottomPerGameInput QCheckBox#checkboxPlayer7Connected::indicator,
179QWidget#bottomPerGameInput QCheckBox#checkboxPlayer8Connected::indicator {
180 width: 12px;
181 height: 12px;
53} 182}
54 183
55QCheckBox#checkboxPlayer1Connected::indicator, 184QCheckBox#checkboxPlayer1Connected::indicator,
@@ -60,10 +189,38 @@ QCheckBox#checkboxPlayer5Connected::indicator,
60QCheckBox#checkboxPlayer6Connected::indicator, 189QCheckBox#checkboxPlayer6Connected::indicator,
61QCheckBox#checkboxPlayer7Connected::indicator, 190QCheckBox#checkboxPlayer7Connected::indicator,
62QCheckBox#checkboxPlayer8Connected::indicator { 191QCheckBox#checkboxPlayer8Connected::indicator {
63 width: 14px; 192 width: 14px;
64 height: 14px; 193 height: 14px;
65} 194}
66 195
196QGroupBox#groupPlayer1Connected::indicator,
197QGroupBox#groupPlayer2Connected::indicator,
198QGroupBox#groupPlayer3Connected::indicator,
199QGroupBox#groupPlayer4Connected::indicator,
200QGroupBox#groupPlayer5Connected::indicator,
201QGroupBox#groupPlayer6Connected::indicator,
202QGroupBox#groupPlayer7Connected::indicator,
203QGroupBox#groupPlayer8Connected::indicator {
204 width: 16px;
205 height: 16px;
206}
207
208QWidget#Player1LEDs QCheckBox::indicator:checked,
209QWidget#Player2LEDs QCheckBox::indicator:checked,
210QWidget#Player3LEDs QCheckBox::indicator:checked,
211QWidget#Player4LEDs QCheckBox::indicator:checked,
212QWidget#Player5LEDs QCheckBox::indicator:checked,
213QWidget#Player6LEDs QCheckBox::indicator:checked,
214QWidget#Player7LEDs QCheckBox::indicator:checked,
215QWidget#Player8LEDs QCheckBox::indicator:checked,
216QGroupBox#groupPlayer1Connected::indicator:checked,
217QGroupBox#groupPlayer2Connected::indicator:checked,
218QGroupBox#groupPlayer3Connected::indicator:checked,
219QGroupBox#groupPlayer4Connected::indicator:checked,
220QGroupBox#groupPlayer5Connected::indicator:checked,
221QGroupBox#groupPlayer6Connected::indicator:checked,
222QGroupBox#groupPlayer7Connected::indicator:checked,
223QGroupBox#groupPlayer8Connected::indicator:checked,
67QCheckBox#checkboxPlayer1Connected::indicator:checked, 224QCheckBox#checkboxPlayer1Connected::indicator:checked,
68QCheckBox#checkboxPlayer2Connected::indicator:checked, 225QCheckBox#checkboxPlayer2Connected::indicator:checked,
69QCheckBox#checkboxPlayer3Connected::indicator:checked, 226QCheckBox#checkboxPlayer3Connected::indicator:checked,
@@ -73,12 +230,28 @@ QCheckBox#checkboxPlayer6Connected::indicator:checked,
73QCheckBox#checkboxPlayer7Connected::indicator:checked, 230QCheckBox#checkboxPlayer7Connected::indicator:checked,
74QCheckBox#checkboxPlayer8Connected::indicator:checked, 231QCheckBox#checkboxPlayer8Connected::indicator:checked,
75QGroupBox#groupConnectedController::indicator:checked { 232QGroupBox#groupConnectedController::indicator:checked {
76 border-radius: 2px; 233 border-radius: 2px;
77 border: 1px solid black; 234 border: 1px solid #929192;
78 background: #39ff14; 235 background: #39ff14;
79 image: none; 236 image: none;
80} 237}
81 238
239QWidget#Player1LEDs QCheckBox::indicator:unchecked,
240QWidget#Player2LEDs QCheckBox::indicator:unchecked,
241QWidget#Player3LEDs QCheckBox::indicator:unchecked,
242QWidget#Player4LEDs QCheckBox::indicator:unchecked,
243QWidget#Player5LEDs QCheckBox::indicator:unchecked,
244QWidget#Player6LEDs QCheckBox::indicator:unchecked,
245QWidget#Player7LEDs QCheckBox::indicator:unchecked,
246QWidget#Player8LEDs QCheckBox::indicator:unchecked,
247QGroupBox#groupPlayer1Connected::indicator:unchecked,
248QGroupBox#groupPlayer2Connected::indicator:unchecked,
249QGroupBox#groupPlayer3Connected::indicator:unchecked,
250QGroupBox#groupPlayer4Connected::indicator:unchecked,
251QGroupBox#groupPlayer5Connected::indicator:unchecked,
252QGroupBox#groupPlayer6Connected::indicator:unchecked,
253QGroupBox#groupPlayer7Connected::indicator:unchecked,
254QGroupBox#groupPlayer8Connected::indicator:unchecked,
82QCheckBox#checkboxPlayer1Connected::indicator:unchecked, 255QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
83QCheckBox#checkboxPlayer2Connected::indicator:unchecked, 256QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
84QCheckBox#checkboxPlayer3Connected::indicator:unchecked, 257QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
@@ -88,8 +261,19 @@ QCheckBox#checkboxPlayer6Connected::indicator:unchecked,
88QCheckBox#checkboxPlayer7Connected::indicator:unchecked, 261QCheckBox#checkboxPlayer7Connected::indicator:unchecked,
89QCheckBox#checkboxPlayer8Connected::indicator:unchecked, 262QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
90QGroupBox#groupConnectedController::indicator:unchecked { 263QGroupBox#groupConnectedController::indicator:unchecked {
91 border-radius: 2px; 264 border-radius: 2px;
92 border: 1px solid black; 265 border: 1px solid #929192;
93 background: transparent; 266 background: transparent;
94 image: none; 267 image: none;
268}
269
270QWidget#controllerPlayer1,
271QWidget#controllerPlayer2,
272QWidget#controllerPlayer3,
273QWidget#controllerPlayer4,
274QWidget#controllerPlayer5,
275QWidget#controllerPlayer6,
276QWidget#controllerPlayer7,
277QWidget#controllerPlayer8 {
278 background: transparent;
95} 279}
diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss
index 16218f0c2..537558c1b 100644
--- a/dist/qt_themes/qdarkstyle/style.qss
+++ b/dist/qt_themes/qdarkstyle/style.qss
@@ -1284,6 +1284,135 @@ QPushButton#buttonRefreshDevices {
1284 padding: 0px 0px; 1284 padding: 0px 0px;
1285} 1285}
1286 1286
1287QSpinBox#spinboxLStickRange,
1288QSpinBox#spinboxRStickRange {
1289 padding: 4px 0px 5px 0px;
1290 min-width: 63px;
1291}
1292
1293QSpinBox#vibrationSpin {
1294 padding: 4px 0px 5px 0px;
1295 min-width: 63px;
1296}
1297
1298QSpinBox#spinboxLStickRange:up-button,
1299QSpinBox#spinboxRStickRange:up-button,
1300QSpinBox#vibrationSpin:up-button {
1301 left: -2px;
1302}
1303
1304QSpinBox#spinboxLStickRange:down-button,
1305QSpinBox#spinboxRStickRange:down-button,
1306QSpinBox#vibrationSpin:down-button {
1307 right: -1px;
1308}
1309
1310QGroupBox#motionGroup::indicator,
1311QGroupBox#vibrationGroup::indicator {
1312 margin-left: 0px;
1313}
1314
1315QGroupBox#motionGroup::title,
1316QGroupBox#vibrationGroup::title {
1317 spacing: 2px;
1318 padding-left: 1px;
1319 padding-right: 1px;
1320}
1321
1322QWidget#bottomPerGameInput,
1323QWidget#topControllerApplet,
1324QWidget#bottomControllerApplet,
1325QGroupBox#groupPlayer1Connected:checked,
1326QGroupBox#groupPlayer2Connected:checked,
1327QGroupBox#groupPlayer3Connected:checked,
1328QGroupBox#groupPlayer4Connected:checked,
1329QGroupBox#groupPlayer5Connected:checked,
1330QGroupBox#groupPlayer6Connected:checked,
1331QGroupBox#groupPlayer7Connected:checked,
1332QGroupBox#groupPlayer8Connected:checked {
1333 background-color: #232629;
1334}
1335
1336QWidget#topPerGameInput,
1337QWidget#middleControllerApplet {
1338 background-color: #31363b;
1339}
1340
1341QWidget#topPerGameInput QComboBox,
1342QWidget#middleControllerApplet QComboBox {
1343 width: 119px;
1344}
1345
1346QRadioButton#radioDocked {
1347 margin-left: -3px;
1348}
1349
1350
1351QRadioButton#radioUndocked {
1352 margin-right: 5px;
1353}
1354
1355QWidget#connectedControllers {
1356 background: transparent;
1357}
1358
1359QWidget#playersSupported,
1360QWidget#controllersSupported,
1361QWidget#controllerSupported1,
1362QWidget#controllerSupported2,
1363QWidget#controllerSupported3,
1364QWidget#controllerSupported4,
1365QWidget#controllerSupported5,
1366QWidget#controllerSupported6 {
1367 border: none;
1368 background: transparent;
1369}
1370
1371QGroupBox#groupPlayer1Connected,
1372QGroupBox#groupPlayer2Connected,
1373QGroupBox#groupPlayer3Connected,
1374QGroupBox#groupPlayer4Connected,
1375QGroupBox#groupPlayer5Connected,
1376QGroupBox#groupPlayer6Connected,
1377QGroupBox#groupPlayer7Connected,
1378QGroupBox#groupPlayer8Connected {
1379 border: 1px solid #76797c;
1380 border-radius: 3px;
1381 padding: 0px;
1382 min-height: 98px;
1383 max-height: 98px;
1384 margin-top: 0px;
1385}
1386
1387QGroupBox#groupPlayer1Connected:unchecked,
1388QGroupBox#groupPlayer2Connected:unchecked,
1389QGroupBox#groupPlayer3Connected:unchecked,
1390QGroupBox#groupPlayer4Connected:unchecked,
1391QGroupBox#groupPlayer5Connected:unchecked,
1392QGroupBox#groupPlayer6Connected:unchecked,
1393QGroupBox#groupPlayer7Connected:unchecked,
1394QGroupBox#groupPlayer8Connected:unchecked {
1395 border: 1px solid #54575b;
1396}
1397
1398QGroupBox#groupPlayer1Connected::title,
1399QGroupBox#groupPlayer2Connected::title,
1400QGroupBox#groupPlayer3Connected::title,
1401QGroupBox#groupPlayer4Connected::title,
1402QGroupBox#groupPlayer5Connected::title,
1403QGroupBox#groupPlayer6Connected::title,
1404QGroupBox#groupPlayer7Connected::title,
1405QGroupBox#groupPlayer8Connected::title {
1406 subcontrol-origin: margin;
1407 subcontrol-position: top left;
1408 padding-left: 0px;
1409 padding-right: 0px;
1410 padding-top: 1px;
1411 margin-left: -2px;
1412 margin-right: -4px;
1413 margin-bottom: 6px;
1414}
1415
1287QCheckBox#checkboxPlayer1Connected, 1416QCheckBox#checkboxPlayer1Connected,
1288QCheckBox#checkboxPlayer2Connected, 1417QCheckBox#checkboxPlayer2Connected,
1289QCheckBox#checkboxPlayer3Connected, 1418QCheckBox#checkboxPlayer3Connected,
@@ -1292,7 +1421,56 @@ QCheckBox#checkboxPlayer5Connected,
1292QCheckBox#checkboxPlayer6Connected, 1421QCheckBox#checkboxPlayer6Connected,
1293QCheckBox#checkboxPlayer7Connected, 1422QCheckBox#checkboxPlayer7Connected,
1294QCheckBox#checkboxPlayer8Connected { 1423QCheckBox#checkboxPlayer8Connected {
1295 spacing: 0px; 1424 spacing: 0px;
1425}
1426
1427QWidget#Player1LEDs,
1428QWidget#Player2LEDs,
1429QWidget#Player3LEDs,
1430QWidget#Player4LEDs,
1431QWidget#Player5LEDs,
1432QWidget#Player6LEDs,
1433QWidget#Player7LEDs,
1434QWidget#Player8LEDs {
1435 background: transparent;
1436}
1437
1438QWidget#Player1LEDs QCheckBox,
1439QWidget#Player2LEDs QCheckBox,
1440QWidget#Player3LEDs QCheckBox,
1441QWidget#Player4LEDs QCheckBox,
1442QWidget#Player5LEDs QCheckBox,
1443QWidget#Player6LEDs QCheckBox,
1444QWidget#Player7LEDs QCheckBox,
1445QWidget#Player8LEDs QCheckBox {
1446 spacing: 0px;
1447 margin-bottom: 0px;
1448 margin-right: 0px;
1449}
1450
1451QWidget#Player1LEDs QCheckBox::indicator,
1452QWidget#Player2LEDs QCheckBox::indicator,
1453QWidget#Player3LEDs QCheckBox::indicator,
1454QWidget#Player4LEDs QCheckBox::indicator,
1455QWidget#Player5LEDs QCheckBox::indicator,
1456QWidget#Player6LEDs QCheckBox::indicator,
1457QWidget#Player7LEDs QCheckBox::indicator,
1458QWidget#Player8LEDs QCheckBox::indicator {
1459 width: 6px;
1460 height: 6px;
1461 margin-left: 0px;
1462}
1463
1464QWidget#bottomPerGameInput QCheckBox#checkboxPlayer1Connected::indicator,
1465QWidget#bottomPerGameInput QCheckBox#checkboxPlayer2Connected::indicator,
1466QWidget#bottomPerGameInput QCheckBox#checkboxPlayer3Connected::indicator,
1467QWidget#bottomPerGameInput QCheckBox#checkboxPlayer4Connected::indicator,
1468QWidget#bottomPerGameInput QCheckBox#checkboxPlayer5Connected::indicator,
1469QWidget#bottomPerGameInput QCheckBox#checkboxPlayer6Connected::indicator,
1470QWidget#bottomPerGameInput QCheckBox#checkboxPlayer7Connected::indicator,
1471QWidget#bottomPerGameInput QCheckBox#checkboxPlayer8Connected::indicator {
1472 width: 12px;
1473 height: 12px;
1296} 1474}
1297 1475
1298QCheckBox#checkboxPlayer1Connected::indicator, 1476QCheckBox#checkboxPlayer1Connected::indicator,
@@ -1307,6 +1485,34 @@ QCheckBox#checkboxPlayer8Connected::indicator {
1307 height: 14px; 1485 height: 14px;
1308} 1486}
1309 1487
1488QGroupBox#groupPlayer1Connected::indicator,
1489QGroupBox#groupPlayer2Connected::indicator,
1490QGroupBox#groupPlayer3Connected::indicator,
1491QGroupBox#groupPlayer4Connected::indicator,
1492QGroupBox#groupPlayer5Connected::indicator,
1493QGroupBox#groupPlayer6Connected::indicator,
1494QGroupBox#groupPlayer7Connected::indicator,
1495QGroupBox#groupPlayer8Connected::indicator {
1496 width: 16px;
1497 height: 16px;
1498}
1499
1500QWidget#Player1LEDs QCheckBox::indicator:checked,
1501QWidget#Player2LEDs QCheckBox::indicator:checked,
1502QWidget#Player3LEDs QCheckBox::indicator:checked,
1503QWidget#Player4LEDs QCheckBox::indicator:checked,
1504QWidget#Player5LEDs QCheckBox::indicator:checked,
1505QWidget#Player6LEDs QCheckBox::indicator:checked,
1506QWidget#Player7LEDs QCheckBox::indicator:checked,
1507QWidget#Player8LEDs QCheckBox::indicator:checked,
1508QGroupBox#groupPlayer1Connected::indicator:checked,
1509QGroupBox#groupPlayer2Connected::indicator:checked,
1510QGroupBox#groupPlayer3Connected::indicator:checked,
1511QGroupBox#groupPlayer4Connected::indicator:checked,
1512QGroupBox#groupPlayer5Connected::indicator:checked,
1513QGroupBox#groupPlayer6Connected::indicator:checked,
1514QGroupBox#groupPlayer7Connected::indicator:checked,
1515QGroupBox#groupPlayer8Connected::indicator:checked,
1310QCheckBox#checkboxPlayer1Connected::indicator:checked, 1516QCheckBox#checkboxPlayer1Connected::indicator:checked,
1311QCheckBox#checkboxPlayer2Connected::indicator:checked, 1517QCheckBox#checkboxPlayer2Connected::indicator:checked,
1312QCheckBox#checkboxPlayer3Connected::indicator:checked, 1518QCheckBox#checkboxPlayer3Connected::indicator:checked,
@@ -1316,12 +1522,28 @@ QCheckBox#checkboxPlayer6Connected::indicator:checked,
1316QCheckBox#checkboxPlayer7Connected::indicator:checked, 1522QCheckBox#checkboxPlayer7Connected::indicator:checked,
1317QCheckBox#checkboxPlayer8Connected::indicator:checked, 1523QCheckBox#checkboxPlayer8Connected::indicator:checked,
1318QGroupBox#groupConnectedController::indicator:checked { 1524QGroupBox#groupConnectedController::indicator:checked {
1319 border-radius: 2px; 1525 border-radius: 2px;
1320 border: 1px solid #929192; 1526 border: 1px solid #929192;
1321 background: #39ff14; 1527 background: #39ff14;
1322 image: none; 1528 image: none;
1323} 1529}
1324 1530
1531QWidget#Player1LEDs QCheckBox::indicator:unchecked,
1532QWidget#Player2LEDs QCheckBox::indicator:unchecked,
1533QWidget#Player3LEDs QCheckBox::indicator:unchecked,
1534QWidget#Player4LEDs QCheckBox::indicator:unchecked,
1535QWidget#Player5LEDs QCheckBox::indicator:unchecked,
1536QWidget#Player6LEDs QCheckBox::indicator:unchecked,
1537QWidget#Player7LEDs QCheckBox::indicator:unchecked,
1538QWidget#Player8LEDs QCheckBox::indicator:unchecked,
1539QGroupBox#groupPlayer1Connected::indicator:unchecked,
1540QGroupBox#groupPlayer2Connected::indicator:unchecked,
1541QGroupBox#groupPlayer3Connected::indicator:unchecked,
1542QGroupBox#groupPlayer4Connected::indicator:unchecked,
1543QGroupBox#groupPlayer5Connected::indicator:unchecked,
1544QGroupBox#groupPlayer6Connected::indicator:unchecked,
1545QGroupBox#groupPlayer7Connected::indicator:unchecked,
1546QGroupBox#groupPlayer8Connected::indicator:unchecked,
1325QCheckBox#checkboxPlayer1Connected::indicator:unchecked, 1547QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
1326QCheckBox#checkboxPlayer2Connected::indicator:unchecked, 1548QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
1327QCheckBox#checkboxPlayer3Connected::indicator:unchecked, 1549QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
@@ -1331,45 +1553,21 @@ QCheckBox#checkboxPlayer6Connected::indicator:unchecked,
1331QCheckBox#checkboxPlayer7Connected::indicator:unchecked, 1553QCheckBox#checkboxPlayer7Connected::indicator:unchecked,
1332QCheckBox#checkboxPlayer8Connected::indicator:unchecked, 1554QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
1333QGroupBox#groupConnectedController::indicator:unchecked { 1555QGroupBox#groupConnectedController::indicator:unchecked {
1334 border-radius: 2px; 1556 border-radius: 2px;
1335 border: 1px solid #929192; 1557 border: 1px solid #929192;
1336 background: transparent; 1558 background: transparent;
1337 image: none; 1559 image: none;
1338} 1560}
1339 1561
1340QSpinBox#spinboxLStickRange, 1562QWidget#controllerPlayer1,
1341QSpinBox#spinboxRStickRange { 1563QWidget#controllerPlayer2,
1342 padding: 4px 0px 5px 0px; 1564QWidget#controllerPlayer3,
1343 min-width: 63px; 1565QWidget#controllerPlayer4,
1344} 1566QWidget#controllerPlayer5,
1345 1567QWidget#controllerPlayer6,
1346QSpinBox#vibrationSpin { 1568QWidget#controllerPlayer7,
1347 padding: 4px 0px 5px 0px; 1569QWidget#controllerPlayer8 {
1348 min-width: 63px; 1570 background: transparent;
1349}
1350
1351QSpinBox#spinboxLStickRange:up-button,
1352QSpinBox#spinboxRStickRange:up-button,
1353QSpinBox#vibrationSpin:up-button {
1354 left: -2px;
1355}
1356
1357QSpinBox#spinboxLStickRange:down-button,
1358QSpinBox#spinboxRStickRange:down-button,
1359QSpinBox#vibrationSpin:down-button {
1360 right: -1px;
1361}
1362
1363QGroupBox#motionGroup::indicator,
1364QGroupBox#vibrationGroup::indicator {
1365 margin-left: 0px;
1366}
1367
1368QGroupBox#motionGroup::title,
1369QGroupBox#vibrationGroup::title {
1370 spacing: 2px;
1371 padding-left: 1px;
1372 padding-right: 1px;
1373} 1571}
1374 1572
1375/* touchscreen mapping widget */ 1573/* touchscreen mapping widget */
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
index a714e1475..9f6a0ff1d 100644
--- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
@@ -2205,7 +2205,179 @@ QPushButton#buttonRefreshDevices {
2205 padding: 0px 0px; 2205 padding: 0px 0px;
2206} 2206}
2207 2207
2208QSpinBox#spinboxLStickRange,
2209QSpinBox#spinboxRStickRange {
2210 min-width: 38px;
2211}
2212
2213QGroupBox#motionGroup::indicator,
2214QGroupBox#vibrationGroup::indicator {
2215 margin-left: 0px;
2216}
2217
2218QWidget#bottomPerGameInput QGroupBox#motionGroup,
2219QWidget#bottomPerGameInput QGroupBox#vibrationGroup,
2220QWidget#bottomPerGameInput QGroupBox#inputConfigGroup {
2221 padding: 0px;
2222}
2223
2224QGroupBox#motionGroup::title,
2225QGroupBox#vibrationGroup::title {
2226 spacing: 2px;
2227 padding-left: 1px;
2228 padding-right: 1px;
2229}
2230
2231QListWidget#selectorList {
2232 background-color: #0f1922;
2233}
2234
2235QSpinBox,
2236QLineEdit,
2237QTreeView#hotkey_list,
2238QScrollArea#scrollArea QTreeView {
2239 background-color: #0f1922;
2240}
2241
2242QWidget#bottomPerGameInput,
2243QWidget#topControllerApplet,
2244QWidget#bottomControllerApplet,
2245QGroupBox#groupPlayer1Connected:checked,
2246QGroupBox#groupPlayer2Connected:checked,
2247QGroupBox#groupPlayer3Connected:checked,
2248QGroupBox#groupPlayer4Connected:checked,
2249QGroupBox#groupPlayer5Connected:checked,
2250QGroupBox#groupPlayer6Connected:checked,
2251QGroupBox#groupPlayer7Connected:checked,
2252QGroupBox#groupPlayer8Connected:checked {
2253 background-color: #0f1922;
2254}
2255
2256QWidget#topPerGameInput,
2257QWidget#middleControllerApplet {
2258 background-color: #19232d;
2259}
2260
2261QWidget#topPerGameInput QComboBox,
2262QWidget#middleControllerApplet QComboBox {
2263 padding-right: 2px;
2264 width: 127px;
2265}
2266
2267QGroupBox#handheldGroup {
2268 padding-left: 0px;
2269}
2270
2271QRadioButton#radioDocked {
2272 margin-left: -1px;
2273 padding-left: 0px;
2274}
2275
2276QRadioButton#radioDocked::indicator {
2277 margin-left: 0px;
2278}
2279
2280
2281QRadioButton#radioUndocked {
2282 margin-right: 2px;
2283}
2284
2285QWidget#connectedControllers {
2286 background: transparent;
2287}
2288
2289QWidget#playersSupported,
2290QWidget#controllersSupported,
2291QWidget#controllerSupported1,
2292QWidget#controllerSupported2,
2293QWidget#controllerSupported3,
2294QWidget#controllerSupported4,
2295QWidget#controllerSupported5,
2296QWidget#controllerSupported6 {
2297 border: none;
2298 background: transparent;
2299}
2300
2301QGroupBox#groupPlayer1Connected,
2302QGroupBox#groupPlayer2Connected,
2303QGroupBox#groupPlayer3Connected,
2304QGroupBox#groupPlayer4Connected,
2305QGroupBox#groupPlayer5Connected,
2306QGroupBox#groupPlayer6Connected,
2307QGroupBox#groupPlayer7Connected,
2308QGroupBox#groupPlayer8Connected {
2309 border: 1px solid #76797c;
2310 border-radius: 3px;
2311 padding: 0px;
2312 min-height: 98px;
2313 max-height: 98px;
2314 margin-top: 0px;
2315}
2316
2317
2318QGroupBox#groupPlayer1Connected:unchecked,
2319QGroupBox#groupPlayer2Connected:unchecked,
2320QGroupBox#groupPlayer3Connected:unchecked,
2321QGroupBox#groupPlayer4Connected:unchecked,
2322QGroupBox#groupPlayer5Connected:unchecked,
2323QGroupBox#groupPlayer6Connected:unchecked,
2324QGroupBox#groupPlayer7Connected:unchecked,
2325QGroupBox#groupPlayer8Connected:unchecked {
2326 border: 1px solid #32414b;
2327}
2328
2329QGroupBox#groupPlayer1Connected::title,
2330QGroupBox#groupPlayer2Connected::title,
2331QGroupBox#groupPlayer3Connected::title,
2332QGroupBox#groupPlayer4Connected::title,
2333QGroupBox#groupPlayer5Connected::title,
2334QGroupBox#groupPlayer6Connected::title,
2335QGroupBox#groupPlayer7Connected::title,
2336QGroupBox#groupPlayer8Connected::title {
2337 subcontrol-origin: margin;
2338 subcontrol-position: top left;
2339 padding-left: 0px;
2340 padding-right: 0px;
2341 padding-top: 1px;
2342 margin-left: -2px;
2343 margin-right: -4px;
2344 margin-bottom: 6px;
2345}
2346
2347QCheckBox#checkboxPlayer1Connected,
2348QCheckBox#checkboxPlayer2Connected,
2349QCheckBox#checkboxPlayer3Connected,
2350QCheckBox#checkboxPlayer4Connected,
2351QCheckBox#checkboxPlayer5Connected,
2352QCheckBox#checkboxPlayer6Connected,
2353QCheckBox#checkboxPlayer7Connected,
2354QCheckBox#checkboxPlayer8Connected {
2355 spacing: 0px;
2356}
2357
2358QWidget#connectedControllers QLabel {
2359 padding: 0px;
2360}
2361
2362QWidget#Player1LEDs,
2363QWidget#Player2LEDs,
2364QWidget#Player3LEDs,
2365QWidget#Player4LEDs,
2366QWidget#Player5LEDs,
2367QWidget#Player6LEDs,
2368QWidget#Player7LEDs,
2369QWidget#Player8LEDs {
2370 background: transparent;
2371}
2208 2372
2373QWidget#Player1LEDs QCheckBox,
2374QWidget#Player2LEDs QCheckBox,
2375QWidget#Player3LEDs QCheckBox,
2376QWidget#Player4LEDs QCheckBox,
2377QWidget#Player5LEDs QCheckBox,
2378QWidget#Player6LEDs QCheckBox,
2379QWidget#Player7LEDs QCheckBox,
2380QWidget#Player8LEDs QCheckBox,
2209QCheckBox#checkboxPlayer1Connected, 2381QCheckBox#checkboxPlayer1Connected,
2210QCheckBox#checkboxPlayer2Connected, 2382QCheckBox#checkboxPlayer2Connected,
2211QCheckBox#checkboxPlayer3Connected, 2383QCheckBox#checkboxPlayer3Connected,
@@ -2215,6 +2387,34 @@ QCheckBox#checkboxPlayer6Connected,
2215QCheckBox#checkboxPlayer7Connected, 2387QCheckBox#checkboxPlayer7Connected,
2216QCheckBox#checkboxPlayer8Connected { 2388QCheckBox#checkboxPlayer8Connected {
2217 spacing: 0px; 2389 spacing: 0px;
2390 padding-top: 0px;
2391 padding-bottom: 0px;
2392 background: transparent;
2393}
2394
2395QWidget#Player1LEDs QCheckBox::indicator,
2396QWidget#Player2LEDs QCheckBox::indicator,
2397QWidget#Player3LEDs QCheckBox::indicator,
2398QWidget#Player4LEDs QCheckBox::indicator,
2399QWidget#Player5LEDs QCheckBox::indicator,
2400QWidget#Player6LEDs QCheckBox::indicator,
2401QWidget#Player7LEDs QCheckBox::indicator,
2402QWidget#Player8LEDs QCheckBox::indicator {
2403 width: 6px;
2404 height: 6px;
2405 margin-left: 0px;
2406}
2407
2408QWidget#bottomPerGameInput QCheckBox#checkboxPlayer1Connected::indicator,
2409QWidget#bottomPerGameInput QCheckBox#checkboxPlayer2Connected::indicator,
2410QWidget#bottomPerGameInput QCheckBox#checkboxPlayer3Connected::indicator,
2411QWidget#bottomPerGameInput QCheckBox#checkboxPlayer4Connected::indicator,
2412QWidget#bottomPerGameInput QCheckBox#checkboxPlayer5Connected::indicator,
2413QWidget#bottomPerGameInput QCheckBox#checkboxPlayer6Connected::indicator,
2414QWidget#bottomPerGameInput QCheckBox#checkboxPlayer7Connected::indicator,
2415QWidget#bottomPerGameInput QCheckBox#checkboxPlayer8Connected::indicator {
2416 width: 12px;
2417 height: 12px;
2218} 2418}
2219 2419
2220QCheckBox#checkboxPlayer1Connected::indicator, 2420QCheckBox#checkboxPlayer1Connected::indicator,
@@ -2227,8 +2427,25 @@ QCheckBox#checkboxPlayer7Connected::indicator,
2227QCheckBox#checkboxPlayer8Connected::indicator { 2427QCheckBox#checkboxPlayer8Connected::indicator {
2228 width: 14px; 2428 width: 14px;
2229 height: 14px; 2429 height: 14px;
2430 margin-left: 2px;
2230} 2431}
2231 2432
2433QWidget#Player1LEDs QCheckBox::indicator:checked,
2434QWidget#Player2LEDs QCheckBox::indicator:checked,
2435QWidget#Player3LEDs QCheckBox::indicator:checked,
2436QWidget#Player4LEDs QCheckBox::indicator:checked,
2437QWidget#Player5LEDs QCheckBox::indicator:checked,
2438QWidget#Player6LEDs QCheckBox::indicator:checked,
2439QWidget#Player7LEDs QCheckBox::indicator:checked,
2440QWidget#Player8LEDs QCheckBox::indicator:checked,
2441QGroupBox#groupPlayer1Connected::indicator:checked,
2442QGroupBox#groupPlayer2Connected::indicator:checked,
2443QGroupBox#groupPlayer3Connected::indicator:checked,
2444QGroupBox#groupPlayer4Connected::indicator:checked,
2445QGroupBox#groupPlayer5Connected::indicator:checked,
2446QGroupBox#groupPlayer6Connected::indicator:checked,
2447QGroupBox#groupPlayer7Connected::indicator:checked,
2448QGroupBox#groupPlayer8Connected::indicator:checked,
2232QCheckBox#checkboxPlayer1Connected::indicator:checked, 2449QCheckBox#checkboxPlayer1Connected::indicator:checked,
2233QCheckBox#checkboxPlayer2Connected::indicator:checked, 2450QCheckBox#checkboxPlayer2Connected::indicator:checked,
2234QCheckBox#checkboxPlayer3Connected::indicator:checked, 2451QCheckBox#checkboxPlayer3Connected::indicator:checked,
@@ -2244,6 +2461,22 @@ QGroupBox#groupConnectedController::indicator:checked {
2244 image: none; 2461 image: none;
2245} 2462}
2246 2463
2464QWidget#Player1LEDs QCheckBox::indicator:unchecked,
2465QWidget#Player2LEDs QCheckBox::indicator:unchecked,
2466QWidget#Player3LEDs QCheckBox::indicator:unchecked,
2467QWidget#Player4LEDs QCheckBox::indicator:unchecked,
2468QWidget#Player5LEDs QCheckBox::indicator:unchecked,
2469QWidget#Player6LEDs QCheckBox::indicator:unchecked,
2470QWidget#Player7LEDs QCheckBox::indicator:unchecked,
2471QWidget#Player8LEDs QCheckBox::indicator:unchecked,
2472QGroupBox#groupPlayer1Connected::indicator:unchecked,
2473QGroupBox#groupPlayer2Connected::indicator:unchecked,
2474QGroupBox#groupPlayer3Connected::indicator:unchecked,
2475QGroupBox#groupPlayer4Connected::indicator:unchecked,
2476QGroupBox#groupPlayer5Connected::indicator:unchecked,
2477QGroupBox#groupPlayer6Connected::indicator:unchecked,
2478QGroupBox#groupPlayer7Connected::indicator:unchecked,
2479QGroupBox#groupPlayer8Connected::indicator:unchecked,
2247QCheckBox#checkboxPlayer1Connected::indicator:unchecked, 2480QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
2248QCheckBox#checkboxPlayer2Connected::indicator:unchecked, 2481QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
2249QCheckBox#checkboxPlayer3Connected::indicator:unchecked, 2482QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
@@ -2255,34 +2488,17 @@ QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
2255QGroupBox#groupConnectedController::indicator:unchecked { 2488QGroupBox#groupConnectedController::indicator:unchecked {
2256 border-radius: 2px; 2489 border-radius: 2px;
2257 border: 1px solid #929192; 2490 border: 1px solid #929192;
2258 background: transparent; 2491 background: #19232d;
2259 image: none; 2492 image: none;
2260} 2493}
2261 2494
2262QSpinBox#spinboxLStickRange, 2495QWidget#controllerPlayer1,
2263QSpinBox#spinboxRStickRange { 2496QWidget#controllerPlayer2,
2264 min-width: 38px; 2497QWidget#controllerPlayer3,
2265} 2498QWidget#controllerPlayer4,
2266 2499QWidget#controllerPlayer5,
2267QGroupBox#motionGroup::indicator, 2500QWidget#controllerPlayer6,
2268QGroupBox#vibrationGroup::indicator { 2501QWidget#controllerPlayer7,
2269 margin-left: 0px; 2502QWidget#controllerPlayer8 {
2270} 2503 background: transparent;
2271
2272QGroupBox#motionGroup::title,
2273QGroupBox#vibrationGroup::title {
2274spacing: 2px;
2275 padding-left: 1px;
2276 padding-right: 1px;
2277}
2278
2279QListWidget#selectorList {
2280 background-color: #0f1922;
2281} 2504}
2282
2283QSpinBox,
2284QLineEdit,
2285QTreeView#hotkey_list,
2286QScrollArea#scrollArea QTreeView {
2287 background-color: #0f1922;
2288} \ No newline at end of file
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c85c9485f..a39940e4c 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -126,6 +126,8 @@ add_library(core STATIC
126 file_sys/vfs_vector.h 126 file_sys/vfs_vector.h
127 file_sys/xts_archive.cpp 127 file_sys/xts_archive.cpp
128 file_sys/xts_archive.h 128 file_sys/xts_archive.h
129 frontend/applets/controller.cpp
130 frontend/applets/controller.h
129 frontend/applets/error.cpp 131 frontend/applets/error.cpp
130 frontend/applets/error.h 132 frontend/applets/error.h
131 frontend/applets/general_frontend.cpp 133 frontend/applets/general_frontend.cpp
@@ -244,6 +246,8 @@ add_library(core STATIC
244 hle/service/am/applet_oe.h 246 hle/service/am/applet_oe.h
245 hle/service/am/applets/applets.cpp 247 hle/service/am/applets/applets.cpp
246 hle/service/am/applets/applets.h 248 hle/service/am/applets/applets.h
249 hle/service/am/applets/controller.cpp
250 hle/service/am/applets/controller.h
247 hle/service/am/applets/error.cpp 251 hle/service/am/applets/error.cpp
248 hle/service/am/applets/error.h 252 hle/service/am/applets/error.h
249 hle/service/am/applets/general_backend.cpp 253 hle/service/am/applets/general_backend.cpp
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp
new file mode 100644
index 000000000..0fbc7932c
--- /dev/null
+++ b/src/core/frontend/applets/controller.cpp
@@ -0,0 +1,40 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/core.h"
6#include "core/frontend/applets/controller.h"
7#include "core/hle/service/hid/controllers/npad.h"
8#include "core/hle/service/hid/hid.h"
9#include "core/hle/service/sm/sm.h"
10
11namespace Core::Frontend {
12
13ControllerApplet::~ControllerApplet() = default;
14
15DefaultControllerApplet::~DefaultControllerApplet() = default;
16
17void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback,
18 ControllerParameters parameters) const {
19 LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
20
21 auto& npad =
22 Core::System::GetInstance()
23 .ServiceManager()
24 .GetService<Service::HID::Hid>("hid")
25 ->GetAppletResource()
26 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
27
28 auto& players = Settings::values.players;
29
30 // Deduce the best configuration based on the input parameters.
31 for (std::size_t index = 0; index < players.size(); ++index) {
32 // First, disconnect all controllers regardless of the value of keep_controllers_connected.
33 // This makes it easy to connect the desired controllers.
34 npad.DisconnectNPadAtIndex(index);
35 }
36
37 callback();
38}
39
40} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h
new file mode 100644
index 000000000..0908f2b69
--- /dev/null
+++ b/src/core/frontend/applets/controller.h
@@ -0,0 +1,45 @@
1// Copyright 2020 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 <functional>
8
9#include "common/common_types.h"
10
11namespace Core::Frontend {
12
13using BorderColor = std::array<u8, 4>;
14
15struct ControllerParameters {
16 s8 min_players{};
17 s8 max_players{};
18 bool keep_controllers_connected{};
19 bool enable_single_mode{};
20 bool enable_border_color{};
21 std::vector<BorderColor> border_colors{};
22 bool allow_pro_controller{};
23 bool allow_handheld{};
24 bool allow_dual_joycons{};
25 bool allow_left_joycon{};
26 bool allow_right_joycon{};
27};
28
29class ControllerApplet {
30public:
31 virtual ~ControllerApplet();
32
33 virtual void ReconfigureControllers(std::function<void()> callback,
34 ControllerParameters parameters) const = 0;
35};
36
37class DefaultControllerApplet final : public ControllerApplet {
38public:
39 ~DefaultControllerApplet() override;
40
41 void ReconfigureControllers(std::function<void()> callback,
42 ControllerParameters parameters) const override;
43};
44
45} // namespace Core::Frontend
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index c3261f3e6..4e0800f9a 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -5,6 +5,7 @@
5#include <cstring> 5#include <cstring>
6#include "common/assert.h" 6#include "common/assert.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/frontend/applets/controller.h"
8#include "core/frontend/applets/error.h" 9#include "core/frontend/applets/error.h"
9#include "core/frontend/applets/general_frontend.h" 10#include "core/frontend/applets/general_frontend.h"
10#include "core/frontend/applets/profile_select.h" 11#include "core/frontend/applets/profile_select.h"
@@ -15,6 +16,7 @@
15#include "core/hle/kernel/writable_event.h" 16#include "core/hle/kernel/writable_event.h"
16#include "core/hle/service/am/am.h" 17#include "core/hle/service/am/am.h"
17#include "core/hle/service/am/applets/applets.h" 18#include "core/hle/service/am/applets/applets.h"
19#include "core/hle/service/am/applets/controller.h"
18#include "core/hle/service/am/applets/error.h" 20#include "core/hle/service/am/applets/error.h"
19#include "core/hle/service/am/applets/general_backend.h" 21#include "core/hle/service/am/applets/general_backend.h"
20#include "core/hle/service/am/applets/profile_select.h" 22#include "core/hle/service/am/applets/profile_select.h"
@@ -140,14 +142,14 @@ void Applet::Initialize() {
140 142
141AppletFrontendSet::AppletFrontendSet() = default; 143AppletFrontendSet::AppletFrontendSet() = default;
142 144
143AppletFrontendSet::AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error, 145AppletFrontendSet::AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce,
146 ErrorApplet error, ParentalControlsApplet parental_controls,
144 PhotoViewer photo_viewer, ProfileSelect profile_select, 147 PhotoViewer photo_viewer, ProfileSelect profile_select,
145 SoftwareKeyboard software_keyboard, WebBrowser web_browser, 148 SoftwareKeyboard software_keyboard, WebBrowser web_browser)
146 ECommerceApplet e_commerce) 149 : controller{std::move(controller)}, e_commerce{std::move(e_commerce)}, error{std::move(error)},
147 : parental_controls{std::move(parental_controls)}, error{std::move(error)}, 150 parental_controls{std::move(parental_controls)}, photo_viewer{std::move(photo_viewer)},
148 photo_viewer{std::move(photo_viewer)}, profile_select{std::move(profile_select)}, 151 profile_select{std::move(profile_select)}, software_keyboard{std::move(software_keyboard)},
149 software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)}, 152 web_browser{std::move(web_browser)} {}
150 e_commerce{std::move(e_commerce)} {}
151 153
152AppletFrontendSet::~AppletFrontendSet() = default; 154AppletFrontendSet::~AppletFrontendSet() = default;
153 155
@@ -164,20 +166,37 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
164} 166}
165 167
166void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { 168void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
167 if (set.parental_controls != nullptr) 169 if (set.controller != nullptr) {
168 frontend.parental_controls = std::move(set.parental_controls); 170 frontend.controller = std::move(set.controller);
169 if (set.error != nullptr) 171 }
172
173 if (set.e_commerce != nullptr) {
174 frontend.e_commerce = std::move(set.e_commerce);
175 }
176
177 if (set.error != nullptr) {
170 frontend.error = std::move(set.error); 178 frontend.error = std::move(set.error);
171 if (set.photo_viewer != nullptr) 179 }
180
181 if (set.parental_controls != nullptr) {
182 frontend.parental_controls = std::move(set.parental_controls);
183 }
184
185 if (set.photo_viewer != nullptr) {
172 frontend.photo_viewer = std::move(set.photo_viewer); 186 frontend.photo_viewer = std::move(set.photo_viewer);
173 if (set.profile_select != nullptr) 187 }
188
189 if (set.profile_select != nullptr) {
174 frontend.profile_select = std::move(set.profile_select); 190 frontend.profile_select = std::move(set.profile_select);
175 if (set.software_keyboard != nullptr) 191 }
192
193 if (set.software_keyboard != nullptr) {
176 frontend.software_keyboard = std::move(set.software_keyboard); 194 frontend.software_keyboard = std::move(set.software_keyboard);
177 if (set.web_browser != nullptr) 195 }
196
197 if (set.web_browser != nullptr) {
178 frontend.web_browser = std::move(set.web_browser); 198 frontend.web_browser = std::move(set.web_browser);
179 if (set.e_commerce != nullptr) 199 }
180 frontend.e_commerce = std::move(set.e_commerce);
181} 200}
182 201
183void AppletManager::SetDefaultAppletFrontendSet() { 202void AppletManager::SetDefaultAppletFrontendSet() {
@@ -186,15 +205,23 @@ void AppletManager::SetDefaultAppletFrontendSet() {
186} 205}
187 206
188void AppletManager::SetDefaultAppletsIfMissing() { 207void AppletManager::SetDefaultAppletsIfMissing() {
189 if (frontend.parental_controls == nullptr) { 208 if (frontend.controller == nullptr) {
190 frontend.parental_controls = 209 frontend.controller = std::make_unique<Core::Frontend::DefaultControllerApplet>();
191 std::make_unique<Core::Frontend::DefaultParentalControlsApplet>(); 210 }
211
212 if (frontend.e_commerce == nullptr) {
213 frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
192 } 214 }
193 215
194 if (frontend.error == nullptr) { 216 if (frontend.error == nullptr) {
195 frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); 217 frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
196 } 218 }
197 219
220 if (frontend.parental_controls == nullptr) {
221 frontend.parental_controls =
222 std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
223 }
224
198 if (frontend.photo_viewer == nullptr) { 225 if (frontend.photo_viewer == nullptr) {
199 frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>(); 226 frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
200 } 227 }
@@ -211,10 +238,6 @@ void AppletManager::SetDefaultAppletsIfMissing() {
211 if (frontend.web_browser == nullptr) { 238 if (frontend.web_browser == nullptr) {
212 frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); 239 frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
213 } 240 }
214
215 if (frontend.e_commerce == nullptr) {
216 frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
217 }
218} 241}
219 242
220void AppletManager::ClearAll() { 243void AppletManager::ClearAll() {
@@ -225,6 +248,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
225 switch (id) { 248 switch (id) {
226 case AppletId::Auth: 249 case AppletId::Auth:
227 return std::make_shared<Auth>(system, *frontend.parental_controls); 250 return std::make_shared<Auth>(system, *frontend.parental_controls);
251 case AppletId::Controller:
252 return std::make_shared<Controller>(system, *frontend.controller);
228 case AppletId::Error: 253 case AppletId::Error:
229 return std::make_shared<Error>(system, *frontend.error); 254 return std::make_shared<Error>(system, *frontend.error);
230 case AppletId::ProfileSelect: 255 case AppletId::ProfileSelect:
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index e75be86a2..a1f4cf897 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -17,6 +17,7 @@ class System;
17} 17}
18 18
19namespace Core::Frontend { 19namespace Core::Frontend {
20class ControllerApplet;
20class ECommerceApplet; 21class ECommerceApplet;
21class ErrorApplet; 22class ErrorApplet;
22class ParentalControlsApplet; 23class ParentalControlsApplet;
@@ -155,19 +156,20 @@ protected:
155}; 156};
156 157
157struct AppletFrontendSet { 158struct AppletFrontendSet {
158 using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>; 159 using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
160 using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
159 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; 161 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
162 using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
160 using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>; 163 using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
161 using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>; 164 using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
162 using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>; 165 using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
163 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; 166 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
164 using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
165 167
166 AppletFrontendSet(); 168 AppletFrontendSet();
167 AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error, 169 AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce, ErrorApplet error,
168 PhotoViewer photo_viewer, ProfileSelect profile_select, 170 ParentalControlsApplet parental_controls, PhotoViewer photo_viewer,
169 SoftwareKeyboard software_keyboard, WebBrowser web_browser, 171 ProfileSelect profile_select, SoftwareKeyboard software_keyboard,
170 ECommerceApplet e_commerce); 172 WebBrowser web_browser);
171 ~AppletFrontendSet(); 173 ~AppletFrontendSet();
172 174
173 AppletFrontendSet(const AppletFrontendSet&) = delete; 175 AppletFrontendSet(const AppletFrontendSet&) = delete;
@@ -176,13 +178,14 @@ struct AppletFrontendSet {
176 AppletFrontendSet(AppletFrontendSet&&) noexcept; 178 AppletFrontendSet(AppletFrontendSet&&) noexcept;
177 AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; 179 AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
178 180
179 ParentalControlsApplet parental_controls; 181 ControllerApplet controller;
182 ECommerceApplet e_commerce;
180 ErrorApplet error; 183 ErrorApplet error;
184 ParentalControlsApplet parental_controls;
181 PhotoViewer photo_viewer; 185 PhotoViewer photo_viewer;
182 ProfileSelect profile_select; 186 ProfileSelect profile_select;
183 SoftwareKeyboard software_keyboard; 187 SoftwareKeyboard software_keyboard;
184 WebBrowser web_browser; 188 WebBrowser web_browser;
185 ECommerceApplet e_commerce;
186}; 189};
187 190
188class AppletManager { 191class AppletManager {
diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp
new file mode 100644
index 000000000..2a45a388f
--- /dev/null
+++ b/src/core/hle/service/am/applets/controller.cpp
@@ -0,0 +1,197 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6
7#include "common/string_util.h"
8#include "core/core.h"
9#include "core/frontend/applets/controller.h"
10#include "core/hle/service/am/am.h"
11#include "core/hle/service/am/applets/controller.h"
12#include "core/hle/service/hid/controllers/npad.h"
13
14namespace Service::AM::Applets {
15
16// This error code (0x183ACA) is thrown when the applet fails to initialize.
17[[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3101{ErrorModule::HID, 3101};
18// This error code (0x183CCA) is thrown when the u32 result in ControllerSupportResultInfo is 2.
19[[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3102{ErrorModule::HID, 3102};
20
21static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
22 ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header,
23 std::vector<IdentificationColor> identification_colors) {
24 HID::Controller_NPad::NPadType npad_style_set;
25 npad_style_set.raw = private_arg.style_set;
26
27 return {
28 .min_players = header.player_count_min,
29 .max_players = header.player_count_max,
30 .keep_controllers_connected = header.enable_take_over_connection,
31 .enable_single_mode = header.enable_single_mode,
32 .enable_border_color = header.enable_identification_color,
33 .border_colors = identification_colors,
34 .allow_pro_controller = npad_style_set.pro_controller == 1,
35 .allow_handheld = npad_style_set.handheld == 1,
36 .allow_dual_joycons = npad_style_set.joycon_dual == 1,
37 .allow_left_joycon = npad_style_set.joycon_left == 1,
38 .allow_right_joycon = npad_style_set.joycon_right == 1,
39 };
40}
41
42Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_)
43 : Applet{system_.Kernel()}, frontend(frontend_) {}
44
45Controller::~Controller() = default;
46
47void Controller::Initialize() {
48 Applet::Initialize();
49
50 LOG_INFO(Service_HID, "Initializing Controller Applet.");
51
52 LOG_DEBUG(Service_HID,
53 "Initializing Applet with common_args: arg_version={}, lib_version={}, "
54 "play_startup_sound={}, size={}, system_tick={}, theme_color={}",
55 common_args.arguments_version, common_args.library_version,
56 common_args.play_startup_sound, common_args.size, common_args.system_tick,
57 common_args.theme_color);
58
59 library_applet_version = LibraryAppletVersion{common_args.library_version};
60
61 const auto private_arg_storage = broker.PopNormalDataToApplet();
62 ASSERT(private_arg_storage != nullptr);
63
64 const auto& private_arg = private_arg_storage->GetData();
65 ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate));
66
67 std::memcpy(&controller_private_arg, private_arg.data(), sizeof(ControllerSupportArgPrivate));
68 ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate),
69 "Unknown ControllerSupportArgPrivate revision={} with size={}",
70 library_applet_version, controller_private_arg.arg_private_size);
71
72 switch (controller_private_arg.mode) {
73 case ControllerSupportMode::ShowControllerSupport: {
74 const auto user_arg_storage = broker.PopNormalDataToApplet();
75 ASSERT(user_arg_storage != nullptr);
76
77 const auto& user_arg = user_arg_storage->GetData();
78 switch (library_applet_version) {
79 case LibraryAppletVersion::Version3:
80 case LibraryAppletVersion::Version4:
81 case LibraryAppletVersion::Version5:
82 ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld));
83 std::memcpy(&controller_user_arg_old, user_arg.data(), sizeof(ControllerSupportArgOld));
84 break;
85 case LibraryAppletVersion::Version7:
86 ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew));
87 std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
88 break;
89 default:
90 UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}",
91 library_applet_version, controller_private_arg.arg_size);
92 ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew));
93 std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
94 break;
95 }
96 break;
97 }
98 case ControllerSupportMode::ShowControllerStrapGuide:
99 case ControllerSupportMode::ShowControllerFirmwareUpdate:
100 default: {
101 UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode);
102 break;
103 }
104 }
105}
106
107bool Controller::TransactionComplete() const {
108 return complete;
109}
110
111ResultCode Controller::GetStatus() const {
112 return status;
113}
114
115void Controller::ExecuteInteractive() {
116 UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet.");
117}
118
119void Controller::Execute() {
120 switch (controller_private_arg.mode) {
121 case ControllerSupportMode::ShowControllerSupport: {
122 const auto parameters = [this] {
123 switch (library_applet_version) {
124 case LibraryAppletVersion::Version3:
125 case LibraryAppletVersion::Version4:
126 case LibraryAppletVersion::Version5:
127 return ConvertToFrontendParameters(
128 controller_private_arg, controller_user_arg_old.header,
129 std::vector<IdentificationColor>(
130 controller_user_arg_old.identification_colors.begin(),
131 controller_user_arg_old.identification_colors.end()));
132 case LibraryAppletVersion::Version7:
133 default:
134 return ConvertToFrontendParameters(
135 controller_private_arg, controller_user_arg_new.header,
136 std::vector<IdentificationColor>(
137 controller_user_arg_new.identification_colors.begin(),
138 controller_user_arg_new.identification_colors.end()));
139 }
140 }();
141
142 is_single_mode = parameters.enable_single_mode;
143
144 LOG_DEBUG(
145 Service_HID,
146 "Controller Parameters: min_players={}, max_players={}, keep_controllers_connected={}, "
147 "enable_single_mode={}, enable_border_color={}, allow_pro_controller={}, "
148 "allow_handheld={}, allow_dual_joycons={}, allow_left_joycon={}, allow_right_joycon={}",
149 parameters.min_players, parameters.max_players, parameters.keep_controllers_connected,
150 parameters.enable_single_mode, parameters.enable_border_color,
151 parameters.allow_pro_controller, parameters.allow_handheld,
152 parameters.allow_dual_joycons, parameters.allow_left_joycon,
153 parameters.allow_right_joycon);
154
155 frontend.ReconfigureControllers([this] { ConfigurationComplete(); }, parameters);
156 break;
157 }
158 case ControllerSupportMode::ShowControllerStrapGuide:
159 case ControllerSupportMode::ShowControllerFirmwareUpdate:
160 default: {
161 ConfigurationComplete();
162 break;
163 }
164 }
165}
166
167void Controller::ConfigurationComplete() {
168 ControllerSupportResultInfo result_info{};
169
170 const auto& players = Settings::values.players;
171
172 // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
173 // Otherwise, only count connected players from P1-P8.
174 result_info.player_count =
175 is_single_mode ? 1
176 : static_cast<s8>(std::count_if(
177 players.begin(), players.end() - 2,
178 [](Settings::PlayerInput player) { return player.connected; }));
179
180 result_info.selected_id = HID::Controller_NPad::IndexToNPad(
181 std::distance(players.begin(),
182 std::find_if(players.begin(), players.end(),
183 [](Settings::PlayerInput player) { return player.connected; })));
184
185 result_info.result = 0;
186
187 LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}",
188 result_info.player_count, result_info.selected_id, result_info.result);
189
190 complete = true;
191 out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo));
192 std::memcpy(out_data.data(), &result_info, out_data.size());
193 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(out_data)));
194 broker.SignalStateChanged();
195}
196
197} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/controller.h b/src/core/hle/service/am/applets/controller.h
new file mode 100644
index 000000000..90a78d508
--- /dev/null
+++ b/src/core/hle/service/am/applets/controller.h
@@ -0,0 +1,119 @@
1// Copyright 2020 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 "core/hle/result.h"
10#include "core/hle/service/am/applets/applets.h"
11
12namespace Core {
13class System;
14}
15
16namespace Service::AM::Applets {
17
18using IdentificationColor = std::array<u8, 4>;
19
20enum class LibraryAppletVersion : u32_le {
21 Version3 = 0x3, // 1.0.0 - 2.3.0
22 Version4 = 0x4, // 3.0.0 - 5.1.0
23 Version5 = 0x5, // 6.0.0 - 7.0.1
24 Version7 = 0x7, // 8.0.0+
25};
26
27enum class ControllerSupportMode : u8 {
28 ShowControllerSupport = 0,
29 ShowControllerStrapGuide = 1,
30 ShowControllerFirmwareUpdate = 2,
31};
32
33enum class ControllerSupportCaller : u8 {
34 Application = 0,
35 System = 1,
36};
37
38struct ControllerSupportArgPrivate {
39 u32 arg_private_size{};
40 u32 arg_size{};
41 bool flag_0{};
42 bool flag_1{};
43 ControllerSupportMode mode{};
44 ControllerSupportCaller caller{};
45 u32 style_set{};
46 u32 joy_hold_type{};
47};
48static_assert(sizeof(ControllerSupportArgPrivate) == 0x14,
49 "ControllerSupportArgPrivate has incorrect size.");
50
51struct ControllerSupportArgHeader {
52 s8 player_count_min{};
53 s8 player_count_max{};
54 bool enable_take_over_connection{};
55 bool enable_left_justify{};
56 bool enable_permit_joy_dual{};
57 bool enable_single_mode{};
58 bool enable_identification_color{};
59};
60static_assert(sizeof(ControllerSupportArgHeader) == 0x7,
61 "ControllerSupportArgHeader has incorrect size.");
62
63// LibraryAppletVersion 0x3, 0x4, 0x5
64struct ControllerSupportArgOld {
65 ControllerSupportArgHeader header{};
66 std::array<IdentificationColor, 4> identification_colors{};
67 bool enable_explain_text{};
68 std::array<std::array<char, 0x81>, 4> explain_text{};
69};
70static_assert(sizeof(ControllerSupportArgOld) == 0x21C,
71 "ControllerSupportArgOld has incorrect size.");
72
73// LibraryAppletVersion 0x7
74struct ControllerSupportArgNew {
75 ControllerSupportArgHeader header{};
76 std::array<IdentificationColor, 8> identification_colors{};
77 bool enable_explain_text{};
78 std::array<std::array<char, 0x81>, 8> explain_text{};
79};
80static_assert(sizeof(ControllerSupportArgNew) == 0x430,
81 "ControllerSupportArgNew has incorrect size.");
82
83struct ControllerSupportResultInfo {
84 s8 player_count{};
85 INSERT_PADDING_BYTES(3);
86 u32 selected_id{};
87 u32 result{};
88};
89static_assert(sizeof(ControllerSupportResultInfo) == 0xC,
90 "ControllerSupportResultInfo has incorrect size.");
91
92class Controller final : public Applet {
93public:
94 explicit Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_);
95 ~Controller() override;
96
97 void Initialize() override;
98
99 bool TransactionComplete() const override;
100 ResultCode GetStatus() const override;
101 void ExecuteInteractive() override;
102 void Execute() override;
103
104 void ConfigurationComplete();
105
106private:
107 const Core::Frontend::ControllerApplet& frontend;
108
109 LibraryAppletVersion library_applet_version;
110 ControllerSupportArgPrivate controller_private_arg;
111 ControllerSupportArgOld controller_user_arg_old;
112 ControllerSupportArgNew controller_user_arg_new;
113 bool complete{false};
114 ResultCode status{RESULT_SUCCESS};
115 bool is_single_mode{false};
116 std::vector<u8> out_data;
117};
118
119} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 45fde8df2..efb953d93 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -193,7 +193,8 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
193 controller.battery_level[0] = BATTERY_FULL; 193 controller.battery_level[0] = BATTERY_FULL;
194 controller.battery_level[1] = BATTERY_FULL; 194 controller.battery_level[1] = BATTERY_FULL;
195 controller.battery_level[2] = BATTERY_FULL; 195 controller.battery_level[2] = BATTERY_FULL;
196 styleset_changed_events[controller_idx].writable->Signal(); 196
197 SignalStyleSetChangedEvent(IndexToNPad(controller_idx));
197} 198}
198 199
199void Controller_NPad::OnInit() { 200void Controller_NPad::OnInit() {
@@ -518,13 +519,17 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
518 last_processed_vibration = vibrations.back(); 519 last_processed_vibration = vibrations.back();
519} 520}
520 521
522Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
523 return last_processed_vibration;
524}
525
521std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const { 526std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
522 const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)]; 527 const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
523 return styleset_event.readable; 528 return styleset_event.readable;
524} 529}
525 530
526Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { 531void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const {
527 return last_processed_vibration; 532 styleset_changed_events[NPadIdToIndex(npad_id)].writable->Signal();
528} 533}
529 534
530void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { 535void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) {
@@ -534,7 +539,7 @@ void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::siz
534void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, 539void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,
535 bool connected) { 540 bool connected) {
536 if (!connected) { 541 if (!connected) {
537 DisconnectNPad(IndexToNPad(npad_index)); 542 DisconnectNPadAtIndex(npad_index);
538 return; 543 return;
539 } 544 }
540 545
@@ -554,16 +559,19 @@ void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::siz
554} 559}
555 560
556void Controller_NPad::DisconnectNPad(u32 npad_id) { 561void Controller_NPad::DisconnectNPad(u32 npad_id) {
557 const auto npad_index = NPadIdToIndex(npad_id); 562 DisconnectNPadAtIndex(NPadIdToIndex(npad_id));
558 connected_controllers[npad_index].is_connected = false; 563}
564
565void Controller_NPad::DisconnectNPadAtIndex(std::size_t npad_index) {
559 Settings::values.players[npad_index].connected = false; 566 Settings::values.players[npad_index].connected = false;
567 connected_controllers[npad_index].is_connected = false;
560 568
561 auto& controller = shared_memory_entries[npad_index]; 569 auto& controller = shared_memory_entries[npad_index];
562 controller.joy_styles.raw = 0; // Zero out 570 controller.joy_styles.raw = 0; // Zero out
563 controller.device_type.raw = 0; 571 controller.device_type.raw = 0;
564 controller.properties.raw = 0; 572 controller.properties.raw = 0;
565 573
566 styleset_changed_events[npad_index].writable->Signal(); 574 SignalStyleSetChangedEvent(IndexToNPad(npad_index));
567} 575}
568 576
569void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) { 577void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) {
@@ -650,13 +658,13 @@ void Controller_NPad::ClearAllConnectedControllers() {
650} 658}
651 659
652void Controller_NPad::DisconnectAllConnectedControllers() { 660void Controller_NPad::DisconnectAllConnectedControllers() {
653 for (ControllerHolder& controller : connected_controllers) { 661 for (auto& controller : connected_controllers) {
654 controller.is_connected = false; 662 controller.is_connected = false;
655 } 663 }
656} 664}
657 665
658void Controller_NPad::ConnectAllDisconnectedControllers() { 666void Controller_NPad::ConnectAllDisconnectedControllers() {
659 for (ControllerHolder& controller : connected_controllers) { 667 for (auto& controller : connected_controllers) {
660 if (controller.type != NPadControllerType::None && !controller.is_connected) { 668 if (controller.type != NPadControllerType::None && !controller.is_connected) {
661 controller.is_connected = true; 669 controller.is_connected = true;
662 } 670 }
@@ -664,7 +672,7 @@ void Controller_NPad::ConnectAllDisconnectedControllers() {
664} 672}
665 673
666void Controller_NPad::ClearAllControllers() { 674void Controller_NPad::ClearAllControllers() {
667 for (ControllerHolder& controller : connected_controllers) { 675 for (auto& controller : connected_controllers) {
668 controller.type = NPadControllerType::None; 676 controller.type = NPadControllerType::None;
669 controller.is_connected = false; 677 controller.is_connected = false;
670 } 678 }
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 75ce5b731..40c763376 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -115,15 +115,19 @@ public:
115 void VibrateController(const std::vector<u32>& controller_ids, 115 void VibrateController(const std::vector<u32>& controller_ids,
116 const std::vector<Vibration>& vibrations); 116 const std::vector<Vibration>& vibrations);
117 117
118 std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
119 Vibration GetLastVibration() const; 118 Vibration GetLastVibration() const;
120 119
120 std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
121 void SignalStyleSetChangedEvent(u32 npad_id) const;
122
121 // Adds a new controller at an index. 123 // Adds a new controller at an index.
122 void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index); 124 void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index);
123 // Adds a new controller at an index with connection status. 125 // Adds a new controller at an index with connection status.
124 void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected); 126 void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected);
125 127
126 void DisconnectNPad(u32 npad_id); 128 void DisconnectNPad(u32 npad_id);
129 void DisconnectNPadAtIndex(std::size_t index);
130
127 void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); 131 void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
128 GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; 132 GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
129 LedPattern GetLedPattern(u32 npad_id); 133 LedPattern GetLedPattern(u32 npad_id);
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 3ea4e5601..cc0291b15 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -9,6 +9,9 @@ add_executable(yuzu
9 about_dialog.cpp 9 about_dialog.cpp
10 about_dialog.h 10 about_dialog.h
11 aboutdialog.ui 11 aboutdialog.ui
12 applets/controller.cpp
13 applets/controller.h
14 applets/controller.ui
12 applets/error.cpp 15 applets/error.cpp
13 applets/error.h 16 applets/error.h
14 applets/profile_select.cpp 17 applets/profile_select.cpp
@@ -62,12 +65,15 @@ add_executable(yuzu
62 configuration/configure_input.cpp 65 configuration/configure_input.cpp
63 configuration/configure_input.h 66 configuration/configure_input.h
64 configuration/configure_input.ui 67 configuration/configure_input.ui
65 configuration/configure_input_player.cpp
66 configuration/configure_input_player.h
67 configuration/configure_input_player.ui
68 configuration/configure_input_advanced.cpp 68 configuration/configure_input_advanced.cpp
69 configuration/configure_input_advanced.h 69 configuration/configure_input_advanced.h
70 configuration/configure_input_advanced.ui 70 configuration/configure_input_advanced.ui
71 configuration/configure_input_dialog.cpp
72 configuration/configure_input_dialog.h
73 configuration/configure_input_dialog.ui
74 configuration/configure_input_player.cpp
75 configuration/configure_input_player.h
76 configuration/configure_input_player.ui
71 configuration/configure_motion_touch.cpp 77 configuration/configure_motion_touch.cpp
72 configuration/configure_motion_touch.h 78 configuration/configure_motion_touch.h
73 configuration/configure_motion_touch.ui 79 configuration/configure_motion_touch.ui
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp
new file mode 100644
index 000000000..8ccf61be0
--- /dev/null
+++ b/src/yuzu/applets/controller.cpp
@@ -0,0 +1,568 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6
7#include "core/core.h"
8#include "core/hle/lock.h"
9#include "core/hle/service/hid/controllers/npad.h"
10#include "core/hle/service/hid/hid.h"
11#include "core/hle/service/sm/sm.h"
12#include "ui_controller.h"
13#include "yuzu/applets/controller.h"
14#include "yuzu/configuration/configure_input_dialog.h"
15#include "yuzu/main.h"
16
17constexpr std::array<std::array<bool, 4>, 8> led_patterns = {{
18 {1, 0, 0, 0},
19 {1, 1, 0, 0},
20 {1, 1, 1, 0},
21 {1, 1, 1, 1},
22 {1, 0, 0, 1},
23 {1, 0, 1, 0},
24 {1, 0, 1, 1},
25 {0, 1, 1, 0},
26}};
27
28namespace {
29
30void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index,
31 bool connected) {
32 Core::System& system{Core::System::GetInstance()};
33
34 if (!system.IsPoweredOn()) {
35 return;
36 }
37
38 Service::SM::ServiceManager& sm = system.ServiceManager();
39
40 auto& npad =
41 sm.GetService<Service::HID::Hid>("hid")
42 ->GetAppletResource()
43 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
44
45 npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected);
46}
47
48bool IsControllerCompatible(Settings::ControllerType controller_type,
49 Core::Frontend::ControllerParameters parameters) {
50 switch (controller_type) {
51 case Settings::ControllerType::ProController:
52 return parameters.allow_pro_controller;
53 case Settings::ControllerType::DualJoyconDetached:
54 return parameters.allow_dual_joycons;
55 case Settings::ControllerType::LeftJoycon:
56 return parameters.allow_left_joycon;
57 case Settings::ControllerType::RightJoycon:
58 return parameters.allow_right_joycon;
59 case Settings::ControllerType::Handheld:
60 return parameters.enable_single_mode && parameters.allow_handheld;
61 default:
62 return false;
63 }
64}
65
66/// Maps the controller type combobox index to Controller Type enum
67constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) {
68 switch (index) {
69 case 0:
70 default:
71 return Settings::ControllerType::ProController;
72 case 1:
73 return Settings::ControllerType::DualJoyconDetached;
74 case 2:
75 return Settings::ControllerType::LeftJoycon;
76 case 3:
77 return Settings::ControllerType::RightJoycon;
78 case 4:
79 return Settings::ControllerType::Handheld;
80 }
81}
82
83/// Maps the Controller Type enum to controller type combobox index
84constexpr int GetIndexFromControllerType(Settings::ControllerType type) {
85 switch (type) {
86 case Settings::ControllerType::ProController:
87 default:
88 return 0;
89 case Settings::ControllerType::DualJoyconDetached:
90 return 1;
91 case Settings::ControllerType::LeftJoycon:
92 return 2;
93 case Settings::ControllerType::RightJoycon:
94 return 3;
95 case Settings::ControllerType::Handheld:
96 return 4;
97 }
98}
99
100} // namespace
101
102QtControllerSelectorDialog::QtControllerSelectorDialog(
103 QWidget* parent, Core::Frontend::ControllerParameters parameters_, InputCommon::InputSubsystem* input_subsystem_)
104 : QDialog(parent), ui(std::make_unique<Ui::QtControllerSelectorDialog>()),
105 parameters(std::move(parameters_)), input_subsystem(input_subsystem_) {
106 ui->setupUi(this);
107
108 player_widgets = {
109 ui->widgetPlayer1, ui->widgetPlayer2, ui->widgetPlayer3, ui->widgetPlayer4,
110 ui->widgetPlayer5, ui->widgetPlayer6, ui->widgetPlayer7, ui->widgetPlayer8,
111 };
112
113 player_groupboxes = {
114 ui->groupPlayer1Connected, ui->groupPlayer2Connected, ui->groupPlayer3Connected,
115 ui->groupPlayer4Connected, ui->groupPlayer5Connected, ui->groupPlayer6Connected,
116 ui->groupPlayer7Connected, ui->groupPlayer8Connected,
117 };
118
119 connected_controller_icons = {
120 ui->controllerPlayer1, ui->controllerPlayer2, ui->controllerPlayer3, ui->controllerPlayer4,
121 ui->controllerPlayer5, ui->controllerPlayer6, ui->controllerPlayer7, ui->controllerPlayer8,
122 };
123
124 led_patterns_boxes = {{
125 {ui->checkboxPlayer1LED1, ui->checkboxPlayer1LED2, ui->checkboxPlayer1LED3,
126 ui->checkboxPlayer1LED4},
127 {ui->checkboxPlayer2LED1, ui->checkboxPlayer2LED2, ui->checkboxPlayer2LED3,
128 ui->checkboxPlayer2LED4},
129 {ui->checkboxPlayer3LED1, ui->checkboxPlayer3LED2, ui->checkboxPlayer3LED3,
130 ui->checkboxPlayer3LED4},
131 {ui->checkboxPlayer4LED1, ui->checkboxPlayer4LED2, ui->checkboxPlayer4LED3,
132 ui->checkboxPlayer4LED4},
133 {ui->checkboxPlayer5LED1, ui->checkboxPlayer5LED2, ui->checkboxPlayer5LED3,
134 ui->checkboxPlayer5LED4},
135 {ui->checkboxPlayer6LED1, ui->checkboxPlayer6LED2, ui->checkboxPlayer6LED3,
136 ui->checkboxPlayer6LED4},
137 {ui->checkboxPlayer7LED1, ui->checkboxPlayer7LED2, ui->checkboxPlayer7LED3,
138 ui->checkboxPlayer7LED4},
139 {ui->checkboxPlayer8LED1, ui->checkboxPlayer8LED2, ui->checkboxPlayer8LED3,
140 ui->checkboxPlayer8LED4},
141 }};
142
143 emulated_controllers = {
144 ui->comboPlayer1Emulated, ui->comboPlayer2Emulated, ui->comboPlayer3Emulated,
145 ui->comboPlayer4Emulated, ui->comboPlayer5Emulated, ui->comboPlayer6Emulated,
146 ui->comboPlayer7Emulated, ui->comboPlayer8Emulated,
147 };
148
149 player_labels = {
150 ui->labelPlayer1, ui->labelPlayer2, ui->labelPlayer3, ui->labelPlayer4,
151 ui->labelPlayer5, ui->labelPlayer6, ui->labelPlayer7, ui->labelPlayer8,
152 };
153
154 connected_controller_labels = {
155 ui->labelConnectedPlayer1, ui->labelConnectedPlayer2, ui->labelConnectedPlayer3,
156 ui->labelConnectedPlayer4, ui->labelConnectedPlayer5, ui->labelConnectedPlayer6,
157 ui->labelConnectedPlayer7, ui->labelConnectedPlayer8,
158 };
159
160 connected_controller_checkboxes = {
161 ui->checkboxPlayer1Connected, ui->checkboxPlayer2Connected, ui->checkboxPlayer3Connected,
162 ui->checkboxPlayer4Connected, ui->checkboxPlayer5Connected, ui->checkboxPlayer6Connected,
163 ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected,
164 };
165
166 for (std::size_t i = 0; i < player_widgets.size(); ++i) {
167 connect(player_groupboxes[i], &QGroupBox::toggled, [this, i](bool checked) {
168 if (checked) {
169 for (std::size_t index = 0; index <= i; ++index) {
170 connected_controller_checkboxes[index]->setChecked(checked);
171 }
172 } else {
173 for (std::size_t index = i; index < player_widgets.size(); ++index) {
174 connected_controller_checkboxes[index]->setChecked(checked);
175 }
176 }
177 });
178
179 connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged),
180 [this, i](int) {
181 UpdateControllerIcon(i);
182 UpdateControllerState(i);
183 UpdateLEDPattern(i);
184 CheckIfParametersMet();
185 });
186
187 connect(connected_controller_checkboxes[i], &QCheckBox::stateChanged, [this, i](int state) {
188 player_groupboxes[i]->setChecked(state == Qt::Checked);
189 UpdateControllerIcon(i);
190 UpdateControllerState(i);
191 UpdateLEDPattern(i);
192 UpdateBorderColor(i);
193 CheckIfParametersMet();
194 });
195
196 if (i == 0) {
197 connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged),
198 [this](int index) {
199 UpdateDockedState(GetControllerTypeFromIndex(index) ==
200 Settings::ControllerType::Handheld);
201 });
202 }
203 }
204
205 connect(ui->inputConfigButton, &QPushButton::clicked, this,
206 &QtControllerSelectorDialog::CallConfigureInputDialog);
207
208 connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
209 &QtControllerSelectorDialog::ApplyConfiguration);
210
211 SetSupportedControllers();
212 DisableUnsupportedPlayers();
213 LoadConfiguration();
214
215 // If keep_controllers_connected is false, forcefully disconnect all controllers
216 if (!parameters.keep_controllers_connected) {
217 for (auto player : player_groupboxes) {
218 player->setChecked(false);
219 }
220 }
221
222 CheckIfParametersMet();
223
224 resize(0, 0);
225}
226
227QtControllerSelectorDialog::~QtControllerSelectorDialog() = default;
228
229void QtControllerSelectorDialog::ApplyConfiguration() {
230 const bool pre_docked_mode = Settings::values.use_docked_mode;
231 Settings::values.use_docked_mode = ui->radioDocked->isChecked();
232 OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
233
234 Settings::values.vibration_enabled = ui->vibrationGroup->isChecked();
235}
236
237void QtControllerSelectorDialog::CallConfigureInputDialog() {
238 const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
239
240 ConfigureInputDialog dialog(this, max_supported_players, input_subsystem);
241
242 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
243 Qt::WindowSystemMenuHint);
244 dialog.setWindowModality(Qt::WindowModal);
245 dialog.exec();
246
247 dialog.ApplyConfiguration();
248
249 LoadConfiguration();
250 CheckIfParametersMet();
251}
252
253void QtControllerSelectorDialog::CheckIfParametersMet() {
254 // Here, we check and validate the current configuration against all applicable parameters.
255 const auto& players = Settings::values.players;
256
257 const auto num_connected_players =
258 std::count_if(player_groupboxes.begin(), player_groupboxes.end(),
259 [this](const QGroupBox* player) { return player->isChecked(); });
260
261 const auto min_supported_players = parameters.enable_single_mode ? 1 : parameters.min_players;
262 const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
263
264 // First, check against the number of connected players.
265 if (num_connected_players < min_supported_players ||
266 num_connected_players > max_supported_players) {
267 parameters_met = false;
268 ui->buttonBox->setEnabled(parameters_met);
269 return;
270 }
271
272 // Next, check against all connected controllers.
273 const auto all_controllers_compatible = [this] {
274 for (std::size_t index = 0; index < player_widgets.size(); ++index) {
275 // Skip controllers that are not used, we only care about the currently connected ones.
276 if (!player_groupboxes[index]->isChecked() || !player_groupboxes[index]->isEnabled()) {
277 continue;
278 }
279
280 const auto compatible = IsControllerCompatible(
281 GetControllerTypeFromIndex(emulated_controllers[index]->currentIndex()),
282 parameters);
283
284 // If any controller is found to be incompatible, return false early.
285 if (!compatible) {
286 return false;
287 }
288 }
289
290 // Reaching here means all currently connected controllers are compatible.
291 return true;
292 }();
293
294 if (!all_controllers_compatible) {
295 parameters_met = false;
296 ui->buttonBox->setEnabled(parameters_met);
297 return;
298 }
299
300 parameters_met = true;
301 ui->buttonBox->setEnabled(parameters_met);
302}
303
304void QtControllerSelectorDialog::SetSupportedControllers() {
305 const QString theme = [this] {
306 if (QIcon::themeName().contains(QStringLiteral("dark"))) {
307 return QStringLiteral("_dark");
308 } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
309 return QStringLiteral("_midnight");
310 } else {
311 return QString{};
312 }
313 }();
314
315 if (parameters.enable_single_mode && parameters.allow_handheld) {
316 ui->controllerSupported1->setStyleSheet(
317 QStringLiteral("image: url(:/controller/applet_handheld%0); ").arg(theme));
318 } else {
319 ui->controllerSupported1->setStyleSheet(
320 QStringLiteral("image: url(:/controller/applet_handheld%0_disabled); ").arg(theme));
321 }
322
323 if (parameters.allow_dual_joycons) {
324 ui->controllerSupported2->setStyleSheet(
325 QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ").arg(theme));
326 } else {
327 ui->controllerSupported2->setStyleSheet(
328 QStringLiteral("image: url(:/controller/applet_dual_joycon%0_disabled); ").arg(theme));
329 }
330
331 if (parameters.allow_left_joycon) {
332 ui->controllerSupported3->setStyleSheet(
333 QStringLiteral("image: url(:/controller/applet_joycon_left%0); ").arg(theme));
334 } else {
335 ui->controllerSupported3->setStyleSheet(
336 QStringLiteral("image: url(:/controller/applet_joycon_left%0_disabled); ").arg(theme));
337 }
338
339 if (parameters.allow_right_joycon) {
340 ui->controllerSupported4->setStyleSheet(
341 QStringLiteral("image: url(:/controller/applet_joycon_right%0); ").arg(theme));
342 } else {
343 ui->controllerSupported4->setStyleSheet(
344 QStringLiteral("image: url(:/controller/applet_joycon_right%0_disabled); ").arg(theme));
345 }
346
347 if (parameters.allow_pro_controller) {
348 ui->controllerSupported5->setStyleSheet(
349 QStringLiteral("image: url(:/controller/applet_pro_controller%0); ").arg(theme));
350 } else {
351 ui->controllerSupported5->setStyleSheet(
352 QStringLiteral("image: url(:/controller/applet_pro_controller%0_disabled); ")
353 .arg(theme));
354 }
355
356 // enable_single_mode overrides min_players and max_players.
357 if (parameters.enable_single_mode) {
358 ui->numberSupportedLabel->setText(QStringLiteral("1"));
359 return;
360 }
361
362 if (parameters.min_players == parameters.max_players) {
363 ui->numberSupportedLabel->setText(QStringLiteral("%1").arg(parameters.max_players));
364 } else {
365 ui->numberSupportedLabel->setText(
366 QStringLiteral("%1 - %2").arg(parameters.min_players).arg(parameters.max_players));
367 }
368}
369
370void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) {
371 if (!player_groupboxes[player_index]->isChecked()) {
372 connected_controller_icons[player_index]->setStyleSheet(QString{});
373 player_labels[player_index]->show();
374 return;
375 }
376
377 const QString stylesheet = [this, player_index] {
378 switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex())) {
379 case Settings::ControllerType::ProController:
380 return QStringLiteral("image: url(:/controller/applet_pro_controller%0); ");
381 case Settings::ControllerType::DualJoyconDetached:
382 return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ");
383 case Settings::ControllerType::LeftJoycon:
384 return QStringLiteral("image: url(:/controller/applet_joycon_left%0); ");
385 case Settings::ControllerType::RightJoycon:
386 return QStringLiteral("image: url(:/controller/applet_joycon_right%0); ");
387 case Settings::ControllerType::Handheld:
388 return QStringLiteral("image: url(:/controller/applet_handheld%0); ");
389 default:
390 return QString{};
391 }
392 }();
393
394 const QString theme = [this] {
395 if (QIcon::themeName().contains(QStringLiteral("dark"))) {
396 return QStringLiteral("_dark");
397 } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
398 return QStringLiteral("_midnight");
399 } else {
400 return QString{};
401 }
402 }();
403
404 connected_controller_icons[player_index]->setStyleSheet(stylesheet.arg(theme));
405 player_labels[player_index]->hide();
406}
407
408void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) {
409 auto& player = Settings::values.players[player_index];
410
411 player.controller_type =
412 GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex());
413 player.connected = player_groupboxes[player_index]->isChecked();
414
415 // Player 2-8
416 if (player_index != 0) {
417 UpdateController(player.controller_type, player_index, player.connected);
418 return;
419 }
420
421 // Player 1 and Handheld
422 auto& handheld = Settings::values.players[8];
423 // If Handheld is selected, copy all the settings from Player 1 to Handheld.
424 if (player.controller_type == Settings::ControllerType::Handheld) {
425 handheld = player;
426 handheld.connected = player_groupboxes[player_index]->isChecked();
427 player.connected = false; // Disconnect Player 1
428 } else {
429 player.connected = player_groupboxes[player_index]->isChecked();
430 handheld.connected = false; // Disconnect Handheld
431 }
432
433 UpdateController(player.controller_type, player_index, player.connected);
434 UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected);
435}
436
437void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) {
438 if (!player_groupboxes[player_index]->isChecked() ||
439 GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex()) ==
440 Settings::ControllerType::Handheld) {
441 led_patterns_boxes[player_index][0]->setChecked(false);
442 led_patterns_boxes[player_index][1]->setChecked(false);
443 led_patterns_boxes[player_index][2]->setChecked(false);
444 led_patterns_boxes[player_index][3]->setChecked(false);
445 return;
446 }
447
448 led_patterns_boxes[player_index][0]->setChecked(led_patterns[player_index][0]);
449 led_patterns_boxes[player_index][1]->setChecked(led_patterns[player_index][1]);
450 led_patterns_boxes[player_index][2]->setChecked(led_patterns[player_index][2]);
451 led_patterns_boxes[player_index][3]->setChecked(led_patterns[player_index][3]);
452}
453
454void QtControllerSelectorDialog::UpdateBorderColor(std::size_t player_index) {
455 if (!parameters.enable_border_color || player_index >= parameters.max_players ||
456 player_groupboxes[player_index]->styleSheet().contains(QStringLiteral("QGroupBox"))) {
457 return;
458 }
459
460 player_groupboxes[player_index]->setStyleSheet(
461 player_groupboxes[player_index]->styleSheet().append(
462 QStringLiteral("QGroupBox#groupPlayer%1Connected:checked "
463 "{ border: 1px solid rgba(%2, %3, %4, %5); }")
464 .arg(player_index + 1)
465 .arg(parameters.border_colors[player_index][0])
466 .arg(parameters.border_colors[player_index][1])
467 .arg(parameters.border_colors[player_index][2])
468 .arg(parameters.border_colors[player_index][3])));
469}
470
471void QtControllerSelectorDialog::UpdateDockedState(bool is_handheld) {
472 // Disallow changing the console mode if the controller type is handheld.
473 ui->radioDocked->setEnabled(!is_handheld);
474 ui->radioUndocked->setEnabled(!is_handheld);
475
476 ui->radioDocked->setChecked(Settings::values.use_docked_mode);
477 ui->radioUndocked->setChecked(!Settings::values.use_docked_mode);
478
479 // Also force into undocked mode if the controller type is handheld.
480 if (is_handheld) {
481 ui->radioUndocked->setChecked(true);
482 }
483}
484
485void QtControllerSelectorDialog::DisableUnsupportedPlayers() {
486 const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
487
488 switch (max_supported_players) {
489 case 0:
490 default:
491 UNREACHABLE();
492 return;
493 case 1:
494 ui->widgetSpacer->hide();
495 ui->widgetSpacer2->hide();
496 ui->widgetSpacer3->hide();
497 ui->widgetSpacer4->hide();
498 break;
499 case 2:
500 ui->widgetSpacer->hide();
501 ui->widgetSpacer2->hide();
502 ui->widgetSpacer3->hide();
503 break;
504 case 3:
505 ui->widgetSpacer->hide();
506 ui->widgetSpacer2->hide();
507 break;
508 case 4:
509 ui->widgetSpacer->hide();
510 break;
511 case 5:
512 case 6:
513 case 7:
514 case 8:
515 break;
516 }
517
518 for (std::size_t index = max_supported_players; index < player_widgets.size(); ++index) {
519 // Disconnect any unsupported players here and disable or hide them if applicable.
520 Settings::values.players[index].connected = false;
521 UpdateController(Settings::values.players[index].controller_type, index, false);
522 // Hide the player widgets when max_supported_controllers is less than or equal to 4.
523 if (max_supported_players <= 4) {
524 player_widgets[index]->hide();
525 }
526
527 // Disable and hide the following to prevent these from interaction.
528 player_widgets[index]->setDisabled(true);
529 connected_controller_checkboxes[index]->setDisabled(true);
530 connected_controller_labels[index]->hide();
531 connected_controller_checkboxes[index]->hide();
532 }
533}
534
535void QtControllerSelectorDialog::LoadConfiguration() {
536 for (std::size_t index = 0; index < player_widgets.size(); ++index) {
537 const auto connected = Settings::values.players[index].connected ||
538 (index == 0 && Settings::values.players[8].connected);
539 player_groupboxes[index]->setChecked(connected);
540 emulated_controllers[index]->setCurrentIndex(
541 GetIndexFromControllerType(Settings::values.players[index].controller_type));
542 }
543
544 UpdateDockedState(Settings::values.players[8].connected);
545
546 ui->vibrationGroup->setChecked(Settings::values.vibration_enabled);
547}
548
549QtControllerSelector::QtControllerSelector(GMainWindow& parent) {
550 connect(this, &QtControllerSelector::MainWindowReconfigureControllers, &parent,
551 &GMainWindow::ControllerSelectorReconfigureControllers, Qt::QueuedConnection);
552 connect(&parent, &GMainWindow::ControllerSelectorReconfigureFinished, this,
553 &QtControllerSelector::MainWindowReconfigureFinished, Qt::QueuedConnection);
554}
555
556QtControllerSelector::~QtControllerSelector() = default;
557
558void QtControllerSelector::ReconfigureControllers(
559 std::function<void()> callback, Core::Frontend::ControllerParameters parameters) const {
560 this->callback = std::move(callback);
561 emit MainWindowReconfigureControllers(parameters);
562}
563
564void QtControllerSelector::MainWindowReconfigureFinished() {
565 // Acquire the HLE mutex
566 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
567 callback();
568}
diff --git a/src/yuzu/applets/controller.h b/src/yuzu/applets/controller.h
new file mode 100644
index 000000000..1ec290e6c
--- /dev/null
+++ b/src/yuzu/applets/controller.h
@@ -0,0 +1,125 @@
1// Copyright 2020 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 <memory>
9#include <QDialog>
10#include "core/frontend/applets/controller.h"
11
12class GMainWindow;
13class QCheckBox;
14class QComboBox;
15class QDialogButtonBox;
16class QGroupBox;
17class QLabel;
18
19namespace InputCommon {
20class InputSubsystem;
21}
22
23namespace Ui {
24class QtControllerSelectorDialog;
25}
26
27class QtControllerSelectorDialog final : public QDialog {
28 Q_OBJECT
29
30public:
31 explicit QtControllerSelectorDialog(QWidget* parent,
32 Core::Frontend::ControllerParameters parameters_,
33 InputCommon::InputSubsystem* input_subsystem_);
34 ~QtControllerSelectorDialog() override;
35
36private:
37 // Applies the current configuration.
38 void ApplyConfiguration();
39
40 // Initializes the "Configure Input" Dialog.
41 void CallConfigureInputDialog();
42
43 // Checks the current configuration against the given parameters and
44 // sets the value of parameters_met.
45 void CheckIfParametersMet();
46
47 // Sets the controller icons for "Supported Controller Types".
48 void SetSupportedControllers();
49
50 // Updates the controller icons per player.
51 void UpdateControllerIcon(std::size_t player_index);
52
53 // Updates the controller state (type and connection status) per player.
54 void UpdateControllerState(std::size_t player_index);
55
56 // Updates the LED pattern per player.
57 void UpdateLEDPattern(std::size_t player_index);
58
59 // Updates the border color per player.
60 void UpdateBorderColor(std::size_t player_index);
61
62 // Updates the console mode.
63 void UpdateDockedState(bool is_handheld);
64
65 // Disables and disconnects unsupported players based on the given parameters.
66 void DisableUnsupportedPlayers();
67
68 // Loads the current input configuration into the frontend applet.
69 void LoadConfiguration();
70
71 std::unique_ptr<Ui::QtControllerSelectorDialog> ui;
72
73 // Parameters sent in from the backend HLE applet.
74 Core::Frontend::ControllerParameters parameters;
75
76 InputCommon::InputSubsystem* input_subsystem;
77
78 // This is true if and only if all parameters are met. Otherwise, this is false.
79 // This determines whether the "Ok" button can be clicked to exit the applet.
80 bool parameters_met{false};
81
82 // Widgets encapsulating the groupboxes and comboboxes per player.
83 std::array<QWidget*, 8> player_widgets;
84
85 // Groupboxes encapsulating the controller icons and LED patterns per player.
86 std::array<QGroupBox*, 8> player_groupboxes;
87
88 // Icons for currently connected controllers/players.
89 std::array<QWidget*, 8> connected_controller_icons;
90
91 // Labels that represent the player numbers in place of the controller icons.
92 std::array<QLabel*, 8> player_labels;
93
94 // LED patterns for currently connected controllers/players.
95 std::array<std::array<QCheckBox*, 4>, 8> led_patterns_boxes;
96
97 // Comboboxes with a list of emulated controllers per player.
98 std::array<QComboBox*, 8> emulated_controllers;
99
100 // Labels representing the number of connected controllers
101 // above the "Connected Controllers" checkboxes.
102 std::array<QLabel*, 8> connected_controller_labels;
103
104 // Checkboxes representing the "Connected Controllers".
105 std::array<QCheckBox*, 8> connected_controller_checkboxes;
106};
107
108class QtControllerSelector final : public QObject, public Core::Frontend::ControllerApplet {
109 Q_OBJECT
110
111public:
112 explicit QtControllerSelector(GMainWindow& parent);
113 ~QtControllerSelector() override;
114
115 void ReconfigureControllers(std::function<void()> callback,
116 Core::Frontend::ControllerParameters parameters) const override;
117
118signals:
119 void MainWindowReconfigureControllers(Core::Frontend::ControllerParameters parameters) const;
120
121private:
122 void MainWindowReconfigureFinished();
123
124 mutable std::function<void()> callback;
125};
diff --git a/src/yuzu/applets/controller.ui b/src/yuzu/applets/controller.ui
new file mode 100644
index 000000000..d7db46613
--- /dev/null
+++ b/src/yuzu/applets/controller.ui
@@ -0,0 +1,2432 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>QtControllerSelectorDialog</class>
4 <widget class="QDialog" name="QtControllerSelectorDialog">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>839</width>
10 <height>630</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Controller Applet</string>
15 </property>
16 <property name="styleSheet">
17 <string notr="true"/>
18 </property>
19 <layout class="QVBoxLayout" name="verticalLayout" stretch="0">
20 <property name="leftMargin">
21 <number>0</number>
22 </property>
23 <property name="topMargin">
24 <number>0</number>
25 </property>
26 <property name="rightMargin">
27 <number>0</number>
28 </property>
29 <property name="bottomMargin">
30 <number>0</number>
31 </property>
32 <item>
33 <widget class="QWidget" name="mainControllerApplet" native="true">
34 <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,3,0">
35 <property name="spacing">
36 <number>0</number>
37 </property>
38 <property name="leftMargin">
39 <number>0</number>
40 </property>
41 <property name="topMargin">
42 <number>0</number>
43 </property>
44 <property name="rightMargin">
45 <number>0</number>
46 </property>
47 <property name="bottomMargin">
48 <number>0</number>
49 </property>
50 <item>
51 <widget class="QWidget" name="topControllerApplet" native="true">
52 <layout class="QHBoxLayout" name="horizontalLayout">
53 <property name="spacing">
54 <number>10</number>
55 </property>
56 <property name="leftMargin">
57 <number>0</number>
58 </property>
59 <property name="topMargin">
60 <number>10</number>
61 </property>
62 <property name="rightMargin">
63 <number>0</number>
64 </property>
65 <property name="bottomMargin">
66 <number>10</number>
67 </property>
68 <item>
69 <spacer name="controllerAppletHorizontalSpacer2">
70 <property name="orientation">
71 <enum>Qt::Horizontal</enum>
72 </property>
73 <property name="sizeHint" stdset="0">
74 <size>
75 <width>40</width>
76 <height>20</height>
77 </size>
78 </property>
79 </spacer>
80 </item>
81 <item>
82 <widget class="QWidget" name="controllersSupported" native="true">
83 <property name="minimumSize">
84 <size>
85 <width>70</width>
86 <height>70</height>
87 </size>
88 </property>
89 <property name="maximumSize">
90 <size>
91 <width>70</width>
92 <height>70</height>
93 </size>
94 </property>
95 <layout class="QVBoxLayout" name="verticalLayout_21">
96 <property name="leftMargin">
97 <number>0</number>
98 </property>
99 <property name="topMargin">
100 <number>0</number>
101 </property>
102 <property name="rightMargin">
103 <number>0</number>
104 </property>
105 <property name="bottomMargin">
106 <number>0</number>
107 </property>
108 <item>
109 <widget class="QLabel" name="controllersSupportedLabel">
110 <property name="minimumSize">
111 <size>
112 <width>70</width>
113 <height>70</height>
114 </size>
115 </property>
116 <property name="maximumSize">
117 <size>
118 <width>70</width>
119 <height>70</height>
120 </size>
121 </property>
122 <property name="font">
123 <font>
124 <weight>75</weight>
125 <bold>true</bold>
126 </font>
127 </property>
128 <property name="text">
129 <string>Supported Controller Types:</string>
130 </property>
131 <property name="alignment">
132 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
133 </property>
134 <property name="wordWrap">
135 <bool>true</bool>
136 </property>
137 </widget>
138 </item>
139 </layout>
140 </widget>
141 </item>
142 <item>
143 <widget class="QWidget" name="controllerSupported1" native="true">
144 <property name="sizePolicy">
145 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
146 <horstretch>0</horstretch>
147 <verstretch>0</verstretch>
148 </sizepolicy>
149 </property>
150 <property name="minimumSize">
151 <size>
152 <width>70</width>
153 <height>70</height>
154 </size>
155 </property>
156 <property name="maximumSize">
157 <size>
158 <width>70</width>
159 <height>70</height>
160 </size>
161 </property>
162 <property name="styleSheet">
163 <string notr="true"/>
164 </property>
165 </widget>
166 </item>
167 <item>
168 <widget class="QWidget" name="controllerSupported2" native="true">
169 <property name="minimumSize">
170 <size>
171 <width>70</width>
172 <height>70</height>
173 </size>
174 </property>
175 <property name="maximumSize">
176 <size>
177 <width>70</width>
178 <height>70</height>
179 </size>
180 </property>
181 <property name="styleSheet">
182 <string notr="true"/>
183 </property>
184 </widget>
185 </item>
186 <item>
187 <widget class="QWidget" name="controllerSupported3" native="true">
188 <property name="minimumSize">
189 <size>
190 <width>70</width>
191 <height>70</height>
192 </size>
193 </property>
194 <property name="maximumSize">
195 <size>
196 <width>70</width>
197 <height>70</height>
198 </size>
199 </property>
200 <property name="styleSheet">
201 <string notr="true"/>
202 </property>
203 </widget>
204 </item>
205 <item>
206 <widget class="QWidget" name="controllerSupported4" native="true">
207 <property name="minimumSize">
208 <size>
209 <width>70</width>
210 <height>70</height>
211 </size>
212 </property>
213 <property name="maximumSize">
214 <size>
215 <width>70</width>
216 <height>70</height>
217 </size>
218 </property>
219 <property name="styleSheet">
220 <string notr="true"/>
221 </property>
222 </widget>
223 </item>
224 <item>
225 <widget class="QWidget" name="controllerSupported5" native="true">
226 <property name="minimumSize">
227 <size>
228 <width>70</width>
229 <height>70</height>
230 </size>
231 </property>
232 <property name="maximumSize">
233 <size>
234 <width>70</width>
235 <height>70</height>
236 </size>
237 </property>
238 <property name="styleSheet">
239 <string notr="true"/>
240 </property>
241 </widget>
242 </item>
243 <item>
244 <widget class="QWidget" name="playersSupported" native="true">
245 <property name="minimumSize">
246 <size>
247 <width>70</width>
248 <height>70</height>
249 </size>
250 </property>
251 <property name="maximumSize">
252 <size>
253 <width>70</width>
254 <height>70</height>
255 </size>
256 </property>
257 <layout class="QVBoxLayout" name="verticalLayout_20">
258 <property name="spacing">
259 <number>0</number>
260 </property>
261 <property name="leftMargin">
262 <number>0</number>
263 </property>
264 <property name="topMargin">
265 <number>16</number>
266 </property>
267 <property name="rightMargin">
268 <number>14</number>
269 </property>
270 <property name="bottomMargin">
271 <number>16</number>
272 </property>
273 <item>
274 <widget class="QLabel" name="maxSupportedLabel">
275 <property name="font">
276 <font>
277 <weight>75</weight>
278 <bold>true</bold>
279 </font>
280 </property>
281 <property name="text">
282 <string>Players:</string>
283 </property>
284 <property name="alignment">
285 <set>Qt::AlignCenter</set>
286 </property>
287 <property name="wordWrap">
288 <bool>false</bool>
289 </property>
290 </widget>
291 </item>
292 <item>
293 <widget class="QLabel" name="numberSupportedLabel">
294 <property name="font">
295 <font>
296 <pointsize>14</pointsize>
297 </font>
298 </property>
299 <property name="text">
300 <string>1 - 8</string>
301 </property>
302 <property name="alignment">
303 <set>Qt::AlignCenter</set>
304 </property>
305 </widget>
306 </item>
307 </layout>
308 </widget>
309 </item>
310 <item>
311 <spacer name="controllerAppletHorizontalSpacer3">
312 <property name="orientation">
313 <enum>Qt::Horizontal</enum>
314 </property>
315 <property name="sizeHint" stdset="0">
316 <size>
317 <width>40</width>
318 <height>20</height>
319 </size>
320 </property>
321 </spacer>
322 </item>
323 </layout>
324 </widget>
325 </item>
326 <item>
327 <widget class="QWidget" name="middleControllerApplet" native="true">
328 <layout class="QVBoxLayout" name="verticalLayout_3">
329 <property name="spacing">
330 <number>0</number>
331 </property>
332 <property name="leftMargin">
333 <number>0</number>
334 </property>
335 <property name="topMargin">
336 <number>0</number>
337 </property>
338 <property name="rightMargin">
339 <number>0</number>
340 </property>
341 <property name="bottomMargin">
342 <number>0</number>
343 </property>
344 <item>
345 <layout class="QGridLayout" name="gridLayout">
346 <property name="spacing">
347 <number>5</number>
348 </property>
349 <item row="1" column="7">
350 <widget class="QWidget" name="widgetPlayer4" native="true">
351 <layout class="QVBoxLayout" name="verticalLayout_27">
352 <property name="spacing">
353 <number>5</number>
354 </property>
355 <property name="leftMargin">
356 <number>0</number>
357 </property>
358 <property name="topMargin">
359 <number>0</number>
360 </property>
361 <property name="rightMargin">
362 <number>0</number>
363 </property>
364 <property name="bottomMargin">
365 <number>0</number>
366 </property>
367 <item alignment="Qt::AlignHCenter">
368 <widget class="QGroupBox" name="groupPlayer4Connected">
369 <property name="minimumSize">
370 <size>
371 <width>100</width>
372 <height>100</height>
373 </size>
374 </property>
375 <property name="maximumSize">
376 <size>
377 <width>100</width>
378 <height>100</height>
379 </size>
380 </property>
381 <property name="title">
382 <string/>
383 </property>
384 <property name="checkable">
385 <bool>true</bool>
386 </property>
387 <property name="checked">
388 <bool>false</bool>
389 </property>
390 <layout class="QVBoxLayout" name="verticalLayout_7" stretch="1,0">
391 <property name="spacing">
392 <number>7</number>
393 </property>
394 <property name="leftMargin">
395 <number>14</number>
396 </property>
397 <property name="topMargin">
398 <number>7</number>
399 </property>
400 <property name="rightMargin">
401 <number>14</number>
402 </property>
403 <property name="bottomMargin">
404 <number>4</number>
405 </property>
406 <item>
407 <widget class="QWidget" name="controllerPlayer4" native="true">
408 <property name="styleSheet">
409 <string notr="true"/>
410 </property>
411 <layout class="QVBoxLayout" name="verticalLayout_15">
412 <property name="topMargin">
413 <number>16</number>
414 </property>
415 <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
416 <widget class="QLabel" name="labelPlayer4">
417 <property name="text">
418 <string>P4</string>
419 </property>
420 </widget>
421 </item>
422 </layout>
423 </widget>
424 </item>
425 <item alignment="Qt::AlignHCenter">
426 <widget class="QWidget" name="Player4LEDs" native="true">
427 <property name="enabled">
428 <bool>false</bool>
429 </property>
430 <property name="minimumSize">
431 <size>
432 <width>0</width>
433 <height>10</height>
434 </size>
435 </property>
436 <layout class="QHBoxLayout" name="horizontalLayout_10">
437 <property name="spacing">
438 <number>4</number>
439 </property>
440 <property name="leftMargin">
441 <number>0</number>
442 </property>
443 <property name="topMargin">
444 <number>0</number>
445 </property>
446 <property name="rightMargin">
447 <number>0</number>
448 </property>
449 <property name="bottomMargin">
450 <number>0</number>
451 </property>
452 <item>
453 <widget class="QCheckBox" name="checkboxPlayer4LED1"/>
454 </item>
455 <item>
456 <widget class="QCheckBox" name="checkboxPlayer4LED2"/>
457 </item>
458 <item>
459 <widget class="QCheckBox" name="checkboxPlayer4LED3"/>
460 </item>
461 <item>
462 <widget class="QCheckBox" name="checkboxPlayer4LED4"/>
463 </item>
464 </layout>
465 </widget>
466 </item>
467 </layout>
468 </widget>
469 </item>
470 <item>
471 <widget class="QWidget" name="fakeSpacerPlayer4" native="true">
472 <property name="minimumSize">
473 <size>
474 <width>0</width>
475 <height>10</height>
476 </size>
477 </property>
478 </widget>
479 </item>
480 <item>
481 <widget class="QComboBox" name="comboPlayer4Emulated">
482 <item>
483 <property name="text">
484 <string>Pro Controller</string>
485 </property>
486 </item>
487 <item>
488 <property name="text">
489 <string>Dual Joycons</string>
490 </property>
491 </item>
492 <item>
493 <property name="text">
494 <string>Left Joycon</string>
495 </property>
496 </item>
497 <item>
498 <property name="text">
499 <string>Right Joycon</string>
500 </property>
501 </item>
502 </widget>
503 </item>
504 <item>
505 <widget class="QComboBox" name="comboPlayer4Profile">
506 <item>
507 <property name="text">
508 <string>Use Current Config</string>
509 </property>
510 </item>
511 </widget>
512 </item>
513 </layout>
514 </widget>
515 </item>
516 <item row="1" column="3">
517 <widget class="QWidget" name="widgetPlayer2" native="true">
518 <layout class="QVBoxLayout" name="verticalLayout_29">
519 <property name="spacing">
520 <number>5</number>
521 </property>
522 <property name="leftMargin">
523 <number>0</number>
524 </property>
525 <property name="topMargin">
526 <number>0</number>
527 </property>
528 <property name="rightMargin">
529 <number>0</number>
530 </property>
531 <property name="bottomMargin">
532 <number>0</number>
533 </property>
534 <item alignment="Qt::AlignHCenter">
535 <widget class="QGroupBox" name="groupPlayer2Connected">
536 <property name="minimumSize">
537 <size>
538 <width>100</width>
539 <height>100</height>
540 </size>
541 </property>
542 <property name="maximumSize">
543 <size>
544 <width>100</width>
545 <height>100</height>
546 </size>
547 </property>
548 <property name="title">
549 <string/>
550 </property>
551 <property name="checkable">
552 <bool>true</bool>
553 </property>
554 <property name="checked">
555 <bool>false</bool>
556 </property>
557 <layout class="QVBoxLayout" name="verticalLayout_5" stretch="1,0">
558 <property name="spacing">
559 <number>7</number>
560 </property>
561 <property name="leftMargin">
562 <number>14</number>
563 </property>
564 <property name="topMargin">
565 <number>7</number>
566 </property>
567 <property name="rightMargin">
568 <number>14</number>
569 </property>
570 <property name="bottomMargin">
571 <number>4</number>
572 </property>
573 <item>
574 <widget class="QWidget" name="controllerPlayer2" native="true">
575 <property name="styleSheet">
576 <string notr="true"/>
577 </property>
578 <layout class="QVBoxLayout" name="verticalLayout_13">
579 <property name="topMargin">
580 <number>16</number>
581 </property>
582 <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
583 <widget class="QLabel" name="labelPlayer2">
584 <property name="text">
585 <string>P2</string>
586 </property>
587 </widget>
588 </item>
589 </layout>
590 </widget>
591 </item>
592 <item alignment="Qt::AlignHCenter">
593 <widget class="QWidget" name="Player2LEDs" native="true">
594 <property name="enabled">
595 <bool>false</bool>
596 </property>
597 <property name="minimumSize">
598 <size>
599 <width>0</width>
600 <height>10</height>
601 </size>
602 </property>
603 <layout class="QHBoxLayout" name="horizontalLayout_8">
604 <property name="spacing">
605 <number>4</number>
606 </property>
607 <property name="leftMargin">
608 <number>0</number>
609 </property>
610 <property name="topMargin">
611 <number>0</number>
612 </property>
613 <property name="rightMargin">
614 <number>0</number>
615 </property>
616 <property name="bottomMargin">
617 <number>0</number>
618 </property>
619 <item>
620 <widget class="QCheckBox" name="checkboxPlayer2LED1"/>
621 </item>
622 <item>
623 <widget class="QCheckBox" name="checkboxPlayer2LED2"/>
624 </item>
625 <item>
626 <widget class="QCheckBox" name="checkboxPlayer2LED3"/>
627 </item>
628 <item>
629 <widget class="QCheckBox" name="checkboxPlayer2LED4"/>
630 </item>
631 </layout>
632 </widget>
633 </item>
634 </layout>
635 </widget>
636 </item>
637 <item>
638 <widget class="QWidget" name="fakeSpacerPlayer2" native="true">
639 <property name="minimumSize">
640 <size>
641 <width>0</width>
642 <height>10</height>
643 </size>
644 </property>
645 </widget>
646 </item>
647 <item>
648 <widget class="QComboBox" name="comboPlayer2Emulated">
649 <item>
650 <property name="text">
651 <string>Pro Controller</string>
652 </property>
653 </item>
654 <item>
655 <property name="text">
656 <string>Dual Joycons</string>
657 </property>
658 </item>
659 <item>
660 <property name="text">
661 <string>Left Joycon</string>
662 </property>
663 </item>
664 <item>
665 <property name="text">
666 <string>Right Joycon</string>
667 </property>
668 </item>
669 </widget>
670 </item>
671 <item>
672 <widget class="QComboBox" name="comboPlayer2Profile">
673 <item>
674 <property name="text">
675 <string>Use Current Config</string>
676 </property>
677 </item>
678 </widget>
679 </item>
680 </layout>
681 </widget>
682 </item>
683 <item row="1" column="1">
684 <widget class="QWidget" name="widgetPlayer1" native="true">
685 <layout class="QVBoxLayout" name="verticalLayout_30">
686 <property name="spacing">
687 <number>5</number>
688 </property>
689 <property name="leftMargin">
690 <number>0</number>
691 </property>
692 <property name="topMargin">
693 <number>0</number>
694 </property>
695 <property name="rightMargin">
696 <number>0</number>
697 </property>
698 <property name="bottomMargin">
699 <number>0</number>
700 </property>
701 <item alignment="Qt::AlignHCenter">
702 <widget class="QGroupBox" name="groupPlayer1Connected">
703 <property name="minimumSize">
704 <size>
705 <width>100</width>
706 <height>100</height>
707 </size>
708 </property>
709 <property name="maximumSize">
710 <size>
711 <width>100</width>
712 <height>100</height>
713 </size>
714 </property>
715 <property name="title">
716 <string/>
717 </property>
718 <property name="checkable">
719 <bool>true</bool>
720 </property>
721 <property name="checked">
722 <bool>false</bool>
723 </property>
724 <layout class="QVBoxLayout" name="verticalLayout_4" stretch="1,0">
725 <property name="spacing">
726 <number>7</number>
727 </property>
728 <property name="leftMargin">
729 <number>14</number>
730 </property>
731 <property name="topMargin">
732 <number>7</number>
733 </property>
734 <property name="rightMargin">
735 <number>14</number>
736 </property>
737 <property name="bottomMargin">
738 <number>4</number>
739 </property>
740 <item>
741 <widget class="QWidget" name="controllerPlayer1" native="true">
742 <property name="styleSheet">
743 <string notr="true"/>
744 </property>
745 <layout class="QVBoxLayout" name="verticalLayout_12">
746 <property name="topMargin">
747 <number>16</number>
748 </property>
749 <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
750 <widget class="QLabel" name="labelPlayer1">
751 <property name="text">
752 <string>P1</string>
753 </property>
754 </widget>
755 </item>
756 </layout>
757 </widget>
758 </item>
759 <item alignment="Qt::AlignHCenter">
760 <widget class="QWidget" name="Player1LEDs" native="true">
761 <property name="enabled">
762 <bool>false</bool>
763 </property>
764 <property name="minimumSize">
765 <size>
766 <width>0</width>
767 <height>10</height>
768 </size>
769 </property>
770 <layout class="QHBoxLayout" name="horizontalLayout_2">
771 <property name="spacing">
772 <number>4</number>
773 </property>
774 <property name="leftMargin">
775 <number>0</number>
776 </property>
777 <property name="topMargin">
778 <number>0</number>
779 </property>
780 <property name="rightMargin">
781 <number>0</number>
782 </property>
783 <property name="bottomMargin">
784 <number>0</number>
785 </property>
786 <item>
787 <widget class="QCheckBox" name="checkboxPlayer1LED1">
788 <property name="layoutDirection">
789 <enum>Qt::LeftToRight</enum>
790 </property>
791 </widget>
792 </item>
793 <item>
794 <widget class="QCheckBox" name="checkboxPlayer1LED2"/>
795 </item>
796 <item>
797 <widget class="QCheckBox" name="checkboxPlayer1LED3"/>
798 </item>
799 <item>
800 <widget class="QCheckBox" name="checkboxPlayer1LED4"/>
801 </item>
802 </layout>
803 </widget>
804 </item>
805 </layout>
806 </widget>
807 </item>
808 <item>
809 <widget class="QWidget" name="fakeSpacerPlayer1" native="true">
810 <property name="minimumSize">
811 <size>
812 <width>0</width>
813 <height>10</height>
814 </size>
815 </property>
816 </widget>
817 </item>
818 <item>
819 <widget class="QComboBox" name="comboPlayer1Emulated">
820 <item>
821 <property name="text">
822 <string>Pro Controller</string>
823 </property>
824 </item>
825 <item>
826 <property name="text">
827 <string>Dual Joycons</string>
828 </property>
829 </item>
830 <item>
831 <property name="text">
832 <string>Left Joycon</string>
833 </property>
834 </item>
835 <item>
836 <property name="text">
837 <string>Right Joycon</string>
838 </property>
839 </item>
840 <item>
841 <property name="text">
842 <string>Handheld</string>
843 </property>
844 </item>
845 </widget>
846 </item>
847 <item>
848 <widget class="QComboBox" name="comboPlayer1Profile">
849 <item>
850 <property name="text">
851 <string>Use Current Config</string>
852 </property>
853 </item>
854 </widget>
855 </item>
856 </layout>
857 </widget>
858 </item>
859 <item row="1" column="8">
860 <widget class="QWidget" name="widgetSpacer2" native="true">
861 <property name="minimumSize">
862 <size>
863 <width>25</width>
864 <height>0</height>
865 </size>
866 </property>
867 <layout class="QVBoxLayout" name="verticalLayout_31">
868 <property name="spacing">
869 <number>0</number>
870 </property>
871 <property name="leftMargin">
872 <number>0</number>
873 </property>
874 <property name="topMargin">
875 <number>0</number>
876 </property>
877 <property name="rightMargin">
878 <number>0</number>
879 </property>
880 <property name="bottomMargin">
881 <number>0</number>
882 </property>
883 <item>
884 <spacer name="controllerAppletHorizontalSpacer8">
885 <property name="orientation">
886 <enum>Qt::Horizontal</enum>
887 </property>
888 <property name="sizeHint" stdset="0">
889 <size>
890 <width>25</width>
891 <height>20</height>
892 </size>
893 </property>
894 </spacer>
895 </item>
896 </layout>
897 </widget>
898 </item>
899 <item row="1" column="4">
900 <widget class="QWidget" name="widgetSpacer4" native="true">
901 <layout class="QVBoxLayout" name="verticalLayout_33">
902 <property name="spacing">
903 <number>0</number>
904 </property>
905 <property name="leftMargin">
906 <number>0</number>
907 </property>
908 <property name="topMargin">
909 <number>0</number>
910 </property>
911 <property name="rightMargin">
912 <number>0</number>
913 </property>
914 <property name="bottomMargin">
915 <number>0</number>
916 </property>
917 <item>
918 <spacer name="controllerAppletHorizontalSpacer6">
919 <property name="orientation">
920 <enum>Qt::Horizontal</enum>
921 </property>
922 <property name="sizeHint" stdset="0">
923 <size>
924 <width>0</width>
925 <height>20</height>
926 </size>
927 </property>
928 </spacer>
929 </item>
930 </layout>
931 </widget>
932 </item>
933 <item row="1" column="6">
934 <widget class="QWidget" name="widgetSpacer3" native="true">
935 <layout class="QVBoxLayout" name="verticalLayout_32">
936 <property name="spacing">
937 <number>0</number>
938 </property>
939 <property name="leftMargin">
940 <number>0</number>
941 </property>
942 <property name="topMargin">
943 <number>0</number>
944 </property>
945 <property name="rightMargin">
946 <number>0</number>
947 </property>
948 <property name="bottomMargin">
949 <number>0</number>
950 </property>
951 <item>
952 <spacer name="controllerAppletHorizontalSpacer7">
953 <property name="orientation">
954 <enum>Qt::Horizontal</enum>
955 </property>
956 <property name="sizeHint" stdset="0">
957 <size>
958 <width>0</width>
959 <height>20</height>
960 </size>
961 </property>
962 </spacer>
963 </item>
964 </layout>
965 </widget>
966 </item>
967 <item row="1" column="5">
968 <widget class="QWidget" name="widgetPlayer3" native="true">
969 <layout class="QVBoxLayout" name="verticalLayout_28">
970 <property name="spacing">
971 <number>5</number>
972 </property>
973 <property name="leftMargin">
974 <number>0</number>
975 </property>
976 <property name="topMargin">
977 <number>0</number>
978 </property>
979 <property name="rightMargin">
980 <number>0</number>
981 </property>
982 <property name="bottomMargin">
983 <number>0</number>
984 </property>
985 <item alignment="Qt::AlignHCenter">
986 <widget class="QGroupBox" name="groupPlayer3Connected">
987 <property name="minimumSize">
988 <size>
989 <width>100</width>
990 <height>100</height>
991 </size>
992 </property>
993 <property name="maximumSize">
994 <size>
995 <width>100</width>
996 <height>100</height>
997 </size>
998 </property>
999 <property name="title">
1000 <string/>
1001 </property>
1002 <property name="checkable">
1003 <bool>true</bool>
1004 </property>
1005 <property name="checked">
1006 <bool>false</bool>
1007 </property>
1008 <layout class="QVBoxLayout" name="verticalLayout_6" stretch="1,0">
1009 <property name="spacing">
1010 <number>7</number>
1011 </property>
1012 <property name="leftMargin">
1013 <number>14</number>
1014 </property>
1015 <property name="topMargin">
1016 <number>7</number>
1017 </property>
1018 <property name="rightMargin">
1019 <number>14</number>
1020 </property>
1021 <property name="bottomMargin">
1022 <number>4</number>
1023 </property>
1024 <item>
1025 <widget class="QWidget" name="controllerPlayer3" native="true">
1026 <property name="styleSheet">
1027 <string notr="true"/>
1028 </property>
1029 <layout class="QVBoxLayout" name="verticalLayout_14">
1030 <property name="topMargin">
1031 <number>16</number>
1032 </property>
1033 <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
1034 <widget class="QLabel" name="labelPlayer3">
1035 <property name="text">
1036 <string>P3</string>
1037 </property>
1038 </widget>
1039 </item>
1040 </layout>
1041 </widget>
1042 </item>
1043 <item alignment="Qt::AlignHCenter">
1044 <widget class="QWidget" name="Player3LEDs" native="true">
1045 <property name="enabled">
1046 <bool>false</bool>
1047 </property>
1048 <property name="minimumSize">
1049 <size>
1050 <width>0</width>
1051 <height>10</height>
1052 </size>
1053 </property>
1054 <layout class="QHBoxLayout" name="horizontalLayout_9">
1055 <property name="spacing">
1056 <number>4</number>
1057 </property>
1058 <property name="leftMargin">
1059 <number>0</number>
1060 </property>
1061 <property name="topMargin">
1062 <number>0</number>
1063 </property>
1064 <property name="rightMargin">
1065 <number>0</number>
1066 </property>
1067 <property name="bottomMargin">
1068 <number>0</number>
1069 </property>
1070 <item>
1071 <widget class="QCheckBox" name="checkboxPlayer3LED1"/>
1072 </item>
1073 <item>
1074 <widget class="QCheckBox" name="checkboxPlayer3LED2"/>
1075 </item>
1076 <item>
1077 <widget class="QCheckBox" name="checkboxPlayer3LED3"/>
1078 </item>
1079 <item>
1080 <widget class="QCheckBox" name="checkboxPlayer3LED4"/>
1081 </item>
1082 </layout>
1083 </widget>
1084 </item>
1085 </layout>
1086 </widget>
1087 </item>
1088 <item>
1089 <widget class="QWidget" name="fakeSpacerPlayer3" native="true">
1090 <property name="minimumSize">
1091 <size>
1092 <width>0</width>
1093 <height>10</height>
1094 </size>
1095 </property>
1096 </widget>
1097 </item>
1098 <item>
1099 <widget class="QComboBox" name="comboPlayer3Emulated">
1100 <property name="editable">
1101 <bool>false</bool>
1102 </property>
1103 <item>
1104 <property name="text">
1105 <string>Pro Controller</string>
1106 </property>
1107 </item>
1108 <item>
1109 <property name="text">
1110 <string>Dual Joycons</string>
1111 </property>
1112 </item>
1113 <item>
1114 <property name="text">
1115 <string>Left Joycon</string>
1116 </property>
1117 </item>
1118 <item>
1119 <property name="text">
1120 <string>Right Joycon</string>
1121 </property>
1122 </item>
1123 </widget>
1124 </item>
1125 <item>
1126 <widget class="QComboBox" name="comboPlayer3Profile">
1127 <item>
1128 <property name="text">
1129 <string>Use Current Config</string>
1130 </property>
1131 </item>
1132 </widget>
1133 </item>
1134 </layout>
1135 </widget>
1136 </item>
1137 <item row="0" column="1">
1138 <widget class="QWidget" name="widgetSpacer5" native="true">
1139 <property name="minimumSize">
1140 <size>
1141 <width>0</width>
1142 <height>25</height>
1143 </size>
1144 </property>
1145 <layout class="QVBoxLayout" name="verticalLayout_34">
1146 <property name="spacing">
1147 <number>0</number>
1148 </property>
1149 <property name="leftMargin">
1150 <number>0</number>
1151 </property>
1152 <property name="topMargin">
1153 <number>0</number>
1154 </property>
1155 <property name="rightMargin">
1156 <number>0</number>
1157 </property>
1158 <property name="bottomMargin">
1159 <number>0</number>
1160 </property>
1161 <item>
1162 <spacer name="controllerAppletVerticalSpacer3">
1163 <property name="orientation">
1164 <enum>Qt::Vertical</enum>
1165 </property>
1166 <property name="sizeHint" stdset="0">
1167 <size>
1168 <width>20</width>
1169 <height>25</height>
1170 </size>
1171 </property>
1172 </spacer>
1173 </item>
1174 </layout>
1175 </widget>
1176 </item>
1177 <item row="6" column="5">
1178 <widget class="QWidget" name="widgetPlayer7" native="true">
1179 <layout class="QVBoxLayout" name="verticalLayout_25">
1180 <property name="spacing">
1181 <number>5</number>
1182 </property>
1183 <property name="leftMargin">
1184 <number>0</number>
1185 </property>
1186 <property name="topMargin">
1187 <number>0</number>
1188 </property>
1189 <property name="rightMargin">
1190 <number>0</number>
1191 </property>
1192 <property name="bottomMargin">
1193 <number>0</number>
1194 </property>
1195 <item alignment="Qt::AlignHCenter">
1196 <widget class="QGroupBox" name="groupPlayer7Connected">
1197 <property name="minimumSize">
1198 <size>
1199 <width>100</width>
1200 <height>100</height>
1201 </size>
1202 </property>
1203 <property name="maximumSize">
1204 <size>
1205 <width>100</width>
1206 <height>100</height>
1207 </size>
1208 </property>
1209 <property name="title">
1210 <string/>
1211 </property>
1212 <property name="checkable">
1213 <bool>true</bool>
1214 </property>
1215 <property name="checked">
1216 <bool>false</bool>
1217 </property>
1218 <layout class="QVBoxLayout" name="verticalLayout_10" stretch="1,0">
1219 <property name="spacing">
1220 <number>7</number>
1221 </property>
1222 <property name="leftMargin">
1223 <number>14</number>
1224 </property>
1225 <property name="topMargin">
1226 <number>7</number>
1227 </property>
1228 <property name="rightMargin">
1229 <number>14</number>
1230 </property>
1231 <property name="bottomMargin">
1232 <number>4</number>
1233 </property>
1234 <item>
1235 <widget class="QWidget" name="controllerPlayer7" native="true">
1236 <property name="styleSheet">
1237 <string notr="true"/>
1238 </property>
1239 <layout class="QVBoxLayout" name="verticalLayout_18">
1240 <property name="topMargin">
1241 <number>16</number>
1242 </property>
1243 <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
1244 <widget class="QLabel" name="labelPlayer7">
1245 <property name="text">
1246 <string>P7</string>
1247 </property>
1248 </widget>
1249 </item>
1250 </layout>
1251 </widget>
1252 </item>
1253 <item alignment="Qt::AlignHCenter">
1254 <widget class="QWidget" name="Player7LEDs" native="true">
1255 <property name="enabled">
1256 <bool>false</bool>
1257 </property>
1258 <property name="minimumSize">
1259 <size>
1260 <width>0</width>
1261 <height>10</height>
1262 </size>
1263 </property>
1264 <layout class="QHBoxLayout" name="horizontalLayout_13">
1265 <property name="spacing">
1266 <number>4</number>
1267 </property>
1268 <property name="leftMargin">
1269 <number>0</number>
1270 </property>
1271 <property name="topMargin">
1272 <number>0</number>
1273 </property>
1274 <property name="rightMargin">
1275 <number>0</number>
1276 </property>
1277 <property name="bottomMargin">
1278 <number>0</number>
1279 </property>
1280 <item>
1281 <widget class="QCheckBox" name="checkboxPlayer7LED1"/>
1282 </item>
1283 <item>
1284 <widget class="QCheckBox" name="checkboxPlayer7LED2"/>
1285 </item>
1286 <item>
1287 <widget class="QCheckBox" name="checkboxPlayer7LED3"/>
1288 </item>
1289 <item>
1290 <widget class="QCheckBox" name="checkboxPlayer7LED4"/>
1291 </item>
1292 </layout>
1293 </widget>
1294 </item>
1295 </layout>
1296 </widget>
1297 </item>
1298 <item>
1299 <widget class="QWidget" name="fakeSpacerPlayer7" native="true">
1300 <property name="minimumSize">
1301 <size>
1302 <width>0</width>
1303 <height>10</height>
1304 </size>
1305 </property>
1306 </widget>
1307 </item>
1308 <item>
1309 <widget class="QComboBox" name="comboPlayer7Emulated">
1310 <item>
1311 <property name="text">
1312 <string>Pro Controller</string>
1313 </property>
1314 </item>
1315 <item>
1316 <property name="text">
1317 <string>Dual Joycons</string>
1318 </property>
1319 </item>
1320 <item>
1321 <property name="text">
1322 <string>Left Joycon</string>
1323 </property>
1324 </item>
1325 <item>
1326 <property name="text">
1327 <string>Right Joycon</string>
1328 </property>
1329 </item>
1330 </widget>
1331 </item>
1332 <item>
1333 <widget class="QComboBox" name="comboPlayer7Profile">
1334 <item>
1335 <property name="text">
1336 <string>Use Current Config</string>
1337 </property>
1338 </item>
1339 </widget>
1340 </item>
1341 </layout>
1342 </widget>
1343 </item>
1344 <item row="6" column="7">
1345 <widget class="QWidget" name="widgetPlayer8" native="true">
1346 <layout class="QVBoxLayout" name="verticalLayout_26">
1347 <property name="spacing">
1348 <number>5</number>
1349 </property>
1350 <property name="leftMargin">
1351 <number>0</number>
1352 </property>
1353 <property name="topMargin">
1354 <number>0</number>
1355 </property>
1356 <property name="rightMargin">
1357 <number>0</number>
1358 </property>
1359 <property name="bottomMargin">
1360 <number>0</number>
1361 </property>
1362 <item alignment="Qt::AlignHCenter">
1363 <widget class="QGroupBox" name="groupPlayer8Connected">
1364 <property name="minimumSize">
1365 <size>
1366 <width>100</width>
1367 <height>100</height>
1368 </size>
1369 </property>
1370 <property name="maximumSize">
1371 <size>
1372 <width>100</width>
1373 <height>100</height>
1374 </size>
1375 </property>
1376 <property name="title">
1377 <string/>
1378 </property>
1379 <property name="checkable">
1380 <bool>true</bool>
1381 </property>
1382 <property name="checked">
1383 <bool>false</bool>
1384 </property>
1385 <layout class="QVBoxLayout" name="verticalLayout_11" stretch="1,0">
1386 <property name="spacing">
1387 <number>7</number>
1388 </property>
1389 <property name="leftMargin">
1390 <number>14</number>
1391 </property>
1392 <property name="topMargin">
1393 <number>7</number>
1394 </property>
1395 <property name="rightMargin">
1396 <number>14</number>
1397 </property>
1398 <property name="bottomMargin">
1399 <number>4</number>
1400 </property>
1401 <item>
1402 <widget class="QWidget" name="controllerPlayer8" native="true">
1403 <property name="styleSheet">
1404 <string notr="true"/>
1405 </property>
1406 <layout class="QVBoxLayout" name="verticalLayout_19">
1407 <property name="topMargin">
1408 <number>16</number>
1409 </property>
1410 <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
1411 <widget class="QLabel" name="labelPlayer8">
1412 <property name="text">
1413 <string>P8</string>
1414 </property>
1415 </widget>
1416 </item>
1417 </layout>
1418 </widget>
1419 </item>
1420 <item alignment="Qt::AlignHCenter">
1421 <widget class="QWidget" name="Player8LEDs" native="true">
1422 <property name="enabled">
1423 <bool>false</bool>
1424 </property>
1425 <property name="minimumSize">
1426 <size>
1427 <width>0</width>
1428 <height>10</height>
1429 </size>
1430 </property>
1431 <layout class="QHBoxLayout" name="horizontalLayout_14">
1432 <property name="spacing">
1433 <number>4</number>
1434 </property>
1435 <property name="leftMargin">
1436 <number>0</number>
1437 </property>
1438 <property name="topMargin">
1439 <number>0</number>
1440 </property>
1441 <property name="rightMargin">
1442 <number>0</number>
1443 </property>
1444 <property name="bottomMargin">
1445 <number>0</number>
1446 </property>
1447 <item>
1448 <widget class="QCheckBox" name="checkboxPlayer8LED1"/>
1449 </item>
1450 <item>
1451 <widget class="QCheckBox" name="checkboxPlayer8LED2"/>
1452 </item>
1453 <item>
1454 <widget class="QCheckBox" name="checkboxPlayer8LED3"/>
1455 </item>
1456 <item>
1457 <widget class="QCheckBox" name="checkboxPlayer8LED4"/>
1458 </item>
1459 </layout>
1460 </widget>
1461 </item>
1462 </layout>
1463 </widget>
1464 </item>
1465 <item>
1466 <widget class="QWidget" name="fakeSpacerPlayer8" native="true">
1467 <property name="minimumSize">
1468 <size>
1469 <width>0</width>
1470 <height>10</height>
1471 </size>
1472 </property>
1473 </widget>
1474 </item>
1475 <item>
1476 <widget class="QComboBox" name="comboPlayer8Emulated">
1477 <item>
1478 <property name="text">
1479 <string>Pro Controller</string>
1480 </property>
1481 </item>
1482 <item>
1483 <property name="text">
1484 <string>Dual Joycons</string>
1485 </property>
1486 </item>
1487 <item>
1488 <property name="text">
1489 <string>Left Joycon</string>
1490 </property>
1491 </item>
1492 <item>
1493 <property name="text">
1494 <string>Right Joycon</string>
1495 </property>
1496 </item>
1497 </widget>
1498 </item>
1499 <item>
1500 <widget class="QComboBox" name="comboPlayer8Profile">
1501 <item>
1502 <property name="text">
1503 <string>Use Current Config</string>
1504 </property>
1505 </item>
1506 </widget>
1507 </item>
1508 </layout>
1509 </widget>
1510 </item>
1511 <item row="6" column="1">
1512 <widget class="QWidget" name="widgetPlayer5" native="true">
1513 <layout class="QVBoxLayout" name="verticalLayout_23">
1514 <property name="spacing">
1515 <number>5</number>
1516 </property>
1517 <property name="leftMargin">
1518 <number>0</number>
1519 </property>
1520 <property name="topMargin">
1521 <number>0</number>
1522 </property>
1523 <property name="rightMargin">
1524 <number>0</number>
1525 </property>
1526 <property name="bottomMargin">
1527 <number>0</number>
1528 </property>
1529 <item alignment="Qt::AlignHCenter">
1530 <widget class="QGroupBox" name="groupPlayer5Connected">
1531 <property name="minimumSize">
1532 <size>
1533 <width>100</width>
1534 <height>100</height>
1535 </size>
1536 </property>
1537 <property name="maximumSize">
1538 <size>
1539 <width>100</width>
1540 <height>100</height>
1541 </size>
1542 </property>
1543 <property name="title">
1544 <string/>
1545 </property>
1546 <property name="checkable">
1547 <bool>true</bool>
1548 </property>
1549 <property name="checked">
1550 <bool>false</bool>
1551 </property>
1552 <layout class="QVBoxLayout" name="verticalLayout_8" stretch="1,0">
1553 <property name="spacing">
1554 <number>7</number>
1555 </property>
1556 <property name="leftMargin">
1557 <number>14</number>
1558 </property>
1559 <property name="topMargin">
1560 <number>7</number>
1561 </property>
1562 <property name="rightMargin">
1563 <number>14</number>
1564 </property>
1565 <property name="bottomMargin">
1566 <number>4</number>
1567 </property>
1568 <item>
1569 <widget class="QWidget" name="controllerPlayer5" native="true">
1570 <property name="styleSheet">
1571 <string notr="true"/>
1572 </property>
1573 <layout class="QVBoxLayout" name="verticalLayout_16">
1574 <property name="topMargin">
1575 <number>16</number>
1576 </property>
1577 <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
1578 <widget class="QLabel" name="labelPlayer5">
1579 <property name="text">
1580 <string>P5</string>
1581 </property>
1582 </widget>
1583 </item>
1584 </layout>
1585 </widget>
1586 </item>
1587 <item alignment="Qt::AlignHCenter">
1588 <widget class="QWidget" name="Player5LEDs" native="true">
1589 <property name="enabled">
1590 <bool>false</bool>
1591 </property>
1592 <property name="minimumSize">
1593 <size>
1594 <width>0</width>
1595 <height>10</height>
1596 </size>
1597 </property>
1598 <layout class="QHBoxLayout" name="horizontalLayout_11">
1599 <property name="spacing">
1600 <number>4</number>
1601 </property>
1602 <property name="leftMargin">
1603 <number>0</number>
1604 </property>
1605 <property name="topMargin">
1606 <number>0</number>
1607 </property>
1608 <property name="rightMargin">
1609 <number>0</number>
1610 </property>
1611 <property name="bottomMargin">
1612 <number>0</number>
1613 </property>
1614 <item>
1615 <widget class="QCheckBox" name="checkboxPlayer5LED1">
1616 <property name="layoutDirection">
1617 <enum>Qt::LeftToRight</enum>
1618 </property>
1619 </widget>
1620 </item>
1621 <item>
1622 <widget class="QCheckBox" name="checkboxPlayer5LED2"/>
1623 </item>
1624 <item>
1625 <widget class="QCheckBox" name="checkboxPlayer5LED3"/>
1626 </item>
1627 <item>
1628 <widget class="QCheckBox" name="checkboxPlayer5LED4"/>
1629 </item>
1630 </layout>
1631 </widget>
1632 </item>
1633 </layout>
1634 </widget>
1635 </item>
1636 <item>
1637 <widget class="QWidget" name="fakeSpacerPlayer5" native="true">
1638 <property name="minimumSize">
1639 <size>
1640 <width>0</width>
1641 <height>10</height>
1642 </size>
1643 </property>
1644 </widget>
1645 </item>
1646 <item>
1647 <widget class="QComboBox" name="comboPlayer5Emulated">
1648 <item>
1649 <property name="text">
1650 <string>Pro Controller</string>
1651 </property>
1652 </item>
1653 <item>
1654 <property name="text">
1655 <string>Dual Joycons</string>
1656 </property>
1657 </item>
1658 <item>
1659 <property name="text">
1660 <string>Left Joycon</string>
1661 </property>
1662 </item>
1663 <item>
1664 <property name="text">
1665 <string>Right Joycon</string>
1666 </property>
1667 </item>
1668 </widget>
1669 </item>
1670 <item>
1671 <widget class="QComboBox" name="comboPlayer5Profile">
1672 <item>
1673 <property name="text">
1674 <string>Use Current Config</string>
1675 </property>
1676 </item>
1677 </widget>
1678 </item>
1679 </layout>
1680 </widget>
1681 </item>
1682 <item row="6" column="3">
1683 <widget class="QWidget" name="widgetPlayer6" native="true">
1684 <layout class="QVBoxLayout" name="verticalLayout_24">
1685 <property name="spacing">
1686 <number>5</number>
1687 </property>
1688 <property name="leftMargin">
1689 <number>0</number>
1690 </property>
1691 <property name="topMargin">
1692 <number>0</number>
1693 </property>
1694 <property name="rightMargin">
1695 <number>0</number>
1696 </property>
1697 <property name="bottomMargin">
1698 <number>0</number>
1699 </property>
1700 <item alignment="Qt::AlignHCenter">
1701 <widget class="QGroupBox" name="groupPlayer6Connected">
1702 <property name="minimumSize">
1703 <size>
1704 <width>100</width>
1705 <height>100</height>
1706 </size>
1707 </property>
1708 <property name="maximumSize">
1709 <size>
1710 <width>100</width>
1711 <height>100</height>
1712 </size>
1713 </property>
1714 <property name="title">
1715 <string/>
1716 </property>
1717 <property name="checkable">
1718 <bool>true</bool>
1719 </property>
1720 <property name="checked">
1721 <bool>false</bool>
1722 </property>
1723 <layout class="QVBoxLayout" name="verticalLayout_9" stretch="1,0">
1724 <property name="spacing">
1725 <number>7</number>
1726 </property>
1727 <property name="leftMargin">
1728 <number>14</number>
1729 </property>
1730 <property name="topMargin">
1731 <number>7</number>
1732 </property>
1733 <property name="rightMargin">
1734 <number>14</number>
1735 </property>
1736 <property name="bottomMargin">
1737 <number>4</number>
1738 </property>
1739 <item>
1740 <widget class="QWidget" name="controllerPlayer6" native="true">
1741 <property name="styleSheet">
1742 <string notr="true"/>
1743 </property>
1744 <layout class="QVBoxLayout" name="verticalLayout_17">
1745 <property name="topMargin">
1746 <number>16</number>
1747 </property>
1748 <item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
1749 <widget class="QLabel" name="labelPlayer6">
1750 <property name="text">
1751 <string>P6</string>
1752 </property>
1753 </widget>
1754 </item>
1755 </layout>
1756 </widget>
1757 </item>
1758 <item alignment="Qt::AlignHCenter">
1759 <widget class="QWidget" name="Player6LEDs" native="true">
1760 <property name="enabled">
1761 <bool>false</bool>
1762 </property>
1763 <property name="minimumSize">
1764 <size>
1765 <width>0</width>
1766 <height>10</height>
1767 </size>
1768 </property>
1769 <layout class="QHBoxLayout" name="horizontalLayout_12">
1770 <property name="spacing">
1771 <number>4</number>
1772 </property>
1773 <property name="leftMargin">
1774 <number>0</number>
1775 </property>
1776 <property name="topMargin">
1777 <number>0</number>
1778 </property>
1779 <property name="rightMargin">
1780 <number>0</number>
1781 </property>
1782 <property name="bottomMargin">
1783 <number>0</number>
1784 </property>
1785 <item>
1786 <widget class="QCheckBox" name="checkboxPlayer6LED1"/>
1787 </item>
1788 <item>
1789 <widget class="QCheckBox" name="checkboxPlayer6LED2"/>
1790 </item>
1791 <item>
1792 <widget class="QCheckBox" name="checkboxPlayer6LED3"/>
1793 </item>
1794 <item>
1795 <widget class="QCheckBox" name="checkboxPlayer6LED4"/>
1796 </item>
1797 </layout>
1798 </widget>
1799 </item>
1800 </layout>
1801 </widget>
1802 </item>
1803 <item>
1804 <widget class="QWidget" name="fakeSpacerPlayer6" native="true">
1805 <property name="minimumSize">
1806 <size>
1807 <width>0</width>
1808 <height>10</height>
1809 </size>
1810 </property>
1811 </widget>
1812 </item>
1813 <item>
1814 <widget class="QComboBox" name="comboPlayer6Emulated">
1815 <item>
1816 <property name="text">
1817 <string>Pro Controller</string>
1818 </property>
1819 </item>
1820 <item>
1821 <property name="text">
1822 <string>Dual Joycons</string>
1823 </property>
1824 </item>
1825 <item>
1826 <property name="text">
1827 <string>Left Joycon</string>
1828 </property>
1829 </item>
1830 <item>
1831 <property name="text">
1832 <string>Right Joycon</string>
1833 </property>
1834 </item>
1835 </widget>
1836 </item>
1837 <item>
1838 <widget class="QComboBox" name="comboPlayer6Profile">
1839 <item>
1840 <property name="text">
1841 <string>Use Current Config</string>
1842 </property>
1843 </item>
1844 </widget>
1845 </item>
1846 </layout>
1847 </widget>
1848 </item>
1849 <item row="10" column="1">
1850 <widget class="QWidget" name="widgetSpacer" native="true">
1851 <property name="minimumSize">
1852 <size>
1853 <width>0</width>
1854 <height>25</height>
1855 </size>
1856 </property>
1857 <layout class="QVBoxLayout" name="verticalLayout_22">
1858 <property name="spacing">
1859 <number>0</number>
1860 </property>
1861 <property name="leftMargin">
1862 <number>0</number>
1863 </property>
1864 <property name="topMargin">
1865 <number>0</number>
1866 </property>
1867 <property name="rightMargin">
1868 <number>0</number>
1869 </property>
1870 <property name="bottomMargin">
1871 <number>0</number>
1872 </property>
1873 <item>
1874 <spacer name="controllerAppletVerticalSpacer">
1875 <property name="orientation">
1876 <enum>Qt::Vertical</enum>
1877 </property>
1878 <property name="sizeHint" stdset="0">
1879 <size>
1880 <width>20</width>
1881 <height>25</height>
1882 </size>
1883 </property>
1884 </spacer>
1885 </item>
1886 </layout>
1887 </widget>
1888 </item>
1889 <item row="1" column="2">
1890 <widget class="QWidget" name="widgetSpacer6" native="true">
1891 <layout class="QHBoxLayout" name="horizontalLayout_15">
1892 <property name="spacing">
1893 <number>0</number>
1894 </property>
1895 <property name="leftMargin">
1896 <number>0</number>
1897 </property>
1898 <property name="topMargin">
1899 <number>0</number>
1900 </property>
1901 <property name="rightMargin">
1902 <number>0</number>
1903 </property>
1904 <property name="bottomMargin">
1905 <number>0</number>
1906 </property>
1907 <item>
1908 <spacer name="controllerAppletHorizontalSpacer5">
1909 <property name="orientation">
1910 <enum>Qt::Horizontal</enum>
1911 </property>
1912 <property name="sizeHint" stdset="0">
1913 <size>
1914 <width>0</width>
1915 <height>20</height>
1916 </size>
1917 </property>
1918 </spacer>
1919 </item>
1920 </layout>
1921 </widget>
1922 </item>
1923 <item row="1" column="0">
1924 <widget class="QWidget" name="widgetSpacer7" native="true">
1925 <property name="minimumSize">
1926 <size>
1927 <width>25</width>
1928 <height>0</height>
1929 </size>
1930 </property>
1931 <layout class="QHBoxLayout" name="horizontalLayout_16">
1932 <property name="spacing">
1933 <number>0</number>
1934 </property>
1935 <property name="leftMargin">
1936 <number>0</number>
1937 </property>
1938 <property name="topMargin">
1939 <number>0</number>
1940 </property>
1941 <property name="rightMargin">
1942 <number>0</number>
1943 </property>
1944 <property name="bottomMargin">
1945 <number>0</number>
1946 </property>
1947 <item>
1948 <spacer name="controllerAppletHorizontalSpacer4">
1949 <property name="orientation">
1950 <enum>Qt::Horizontal</enum>
1951 </property>
1952 <property name="sizeHint" stdset="0">
1953 <size>
1954 <width>25</width>
1955 <height>20</height>
1956 </size>
1957 </property>
1958 </spacer>
1959 </item>
1960 </layout>
1961 </widget>
1962 </item>
1963 <item row="2" column="1">
1964 <widget class="QWidget" name="widgetSpacer9" native="true">
1965 <property name="minimumSize">
1966 <size>
1967 <width>0</width>
1968 <height>25</height>
1969 </size>
1970 </property>
1971 <layout class="QHBoxLayout" name="horizontalLayout_17">
1972 <property name="spacing">
1973 <number>0</number>
1974 </property>
1975 <property name="leftMargin">
1976 <number>0</number>
1977 </property>
1978 <property name="topMargin">
1979 <number>0</number>
1980 </property>
1981 <property name="rightMargin">
1982 <number>0</number>
1983 </property>
1984 <property name="bottomMargin">
1985 <number>0</number>
1986 </property>
1987 <item>
1988 <spacer name="controllerAppletVerticalSpacer2">
1989 <property name="orientation">
1990 <enum>Qt::Vertical</enum>
1991 </property>
1992 <property name="sizeHint" stdset="0">
1993 <size>
1994 <width>20</width>
1995 <height>25</height>
1996 </size>
1997 </property>
1998 </spacer>
1999 </item>
2000 </layout>
2001 </widget>
2002 </item>
2003 </layout>
2004 </item>
2005 </layout>
2006 </widget>
2007 </item>
2008 <item>
2009 <widget class="QWidget" name="bottomControllerApplet" native="true">
2010 <layout class="QHBoxLayout" name="horizontalLayout_6">
2011 <property name="spacing">
2012 <number>15</number>
2013 </property>
2014 <property name="leftMargin">
2015 <number>15</number>
2016 </property>
2017 <property name="topMargin">
2018 <number>8</number>
2019 </property>
2020 <property name="rightMargin">
2021 <number>15</number>
2022 </property>
2023 <property name="bottomMargin">
2024 <number>15</number>
2025 </property>
2026 <item>
2027 <widget class="QGroupBox" name="handheldGroup">
2028 <property name="maximumSize">
2029 <size>
2030 <width>16777215</width>
2031 <height>16777215</height>
2032 </size>
2033 </property>
2034 <property name="title">
2035 <string>Console Mode</string>
2036 </property>
2037 <layout class="QHBoxLayout" name="horizontalLayout_3">
2038 <property name="spacing">
2039 <number>6</number>
2040 </property>
2041 <property name="leftMargin">
2042 <number>6</number>
2043 </property>
2044 <property name="topMargin">
2045 <number>6</number>
2046 </property>
2047 <property name="rightMargin">
2048 <number>3</number>
2049 </property>
2050 <property name="bottomMargin">
2051 <number>6</number>
2052 </property>
2053 <item>
2054 <widget class="QRadioButton" name="radioDocked">
2055 <property name="text">
2056 <string>Docked</string>
2057 </property>
2058 <property name="checked">
2059 <bool>true</bool>
2060 </property>
2061 </widget>
2062 </item>
2063 <item>
2064 <widget class="QRadioButton" name="radioUndocked">
2065 <property name="text">
2066 <string>Undocked</string>
2067 </property>
2068 </widget>
2069 </item>
2070 </layout>
2071 </widget>
2072 </item>
2073 <item>
2074 <widget class="QGroupBox" name="vibrationGroup">
2075 <property name="title">
2076 <string>Vibration</string>
2077 </property>
2078 <property name="checkable">
2079 <bool>true</bool>
2080 </property>
2081 <layout class="QHBoxLayout" name="horizontalLayout_5">
2082 <property name="leftMargin">
2083 <number>3</number>
2084 </property>
2085 <property name="topMargin">
2086 <number>3</number>
2087 </property>
2088 <property name="rightMargin">
2089 <number>3</number>
2090 </property>
2091 <property name="bottomMargin">
2092 <number>3</number>
2093 </property>
2094 <item>
2095 <widget class="QSpinBox" name="vibrationSpin">
2096 <property name="minimumSize">
2097 <size>
2098 <width>65</width>
2099 <height>0</height>
2100 </size>
2101 </property>
2102 <property name="maximumSize">
2103 <size>
2104 <width>65</width>
2105 <height>16777215</height>
2106 </size>
2107 </property>
2108 <property name="suffix">
2109 <string>%</string>
2110 </property>
2111 <property name="minimum">
2112 <number>1</number>
2113 </property>
2114 <property name="maximum">
2115 <number>200</number>
2116 </property>
2117 <property name="value">
2118 <number>100</number>
2119 </property>
2120 </widget>
2121 </item>
2122 </layout>
2123 </widget>
2124 </item>
2125 <item>
2126 <widget class="QGroupBox" name="motionGroup">
2127 <property name="title">
2128 <string>Motion</string>
2129 </property>
2130 <property name="checkable">
2131 <bool>true</bool>
2132 </property>
2133 <layout class="QHBoxLayout" name="horizontalLayout_4">
2134 <property name="leftMargin">
2135 <number>3</number>
2136 </property>
2137 <property name="topMargin">
2138 <number>3</number>
2139 </property>
2140 <property name="rightMargin">
2141 <number>3</number>
2142 </property>
2143 <property name="bottomMargin">
2144 <number>3</number>
2145 </property>
2146 <item>
2147 <widget class="QPushButton" name="motionButton">
2148 <property name="minimumSize">
2149 <size>
2150 <width>57</width>
2151 <height>0</height>
2152 </size>
2153 </property>
2154 <property name="maximumSize">
2155 <size>
2156 <width>55</width>
2157 <height>16777215</height>
2158 </size>
2159 </property>
2160 <property name="styleSheet">
2161 <string notr="true">min-width: 55px;</string>
2162 </property>
2163 <property name="text">
2164 <string>Configure</string>
2165 </property>
2166 </widget>
2167 </item>
2168 </layout>
2169 </widget>
2170 </item>
2171 <item>
2172 <widget class="QGroupBox" name="inputConfigGroup">
2173 <property name="title">
2174 <string>Input Config</string>
2175 </property>
2176 <layout class="QHBoxLayout" name="horizontalLayout_7">
2177 <property name="leftMargin">
2178 <number>3</number>
2179 </property>
2180 <property name="topMargin">
2181 <number>3</number>
2182 </property>
2183 <property name="rightMargin">
2184 <number>3</number>
2185 </property>
2186 <property name="bottomMargin">
2187 <number>3</number>
2188 </property>
2189 <item>
2190 <widget class="QPushButton" name="inputConfigButton">
2191 <property name="maximumSize">
2192 <size>
2193 <width>65</width>
2194 <height>16777215</height>
2195 </size>
2196 </property>
2197 <property name="styleSheet">
2198 <string notr="true">min-width: 55px;</string>
2199 </property>
2200 <property name="text">
2201 <string>Open</string>
2202 </property>
2203 </widget>
2204 </item>
2205 </layout>
2206 </widget>
2207 </item>
2208 <item>
2209 <widget class="QWidget" name="connectedControllers" native="true">
2210 <layout class="QGridLayout" name="gridLayout_2">
2211 <property name="leftMargin">
2212 <number>5</number>
2213 </property>
2214 <property name="topMargin">
2215 <number>0</number>
2216 </property>
2217 <property name="rightMargin">
2218 <number>0</number>
2219 </property>
2220 <property name="bottomMargin">
2221 <number>0</number>
2222 </property>
2223 <property name="spacing">
2224 <number>3</number>
2225 </property>
2226 <item row="1" column="4">
2227 <widget class="QCheckBox" name="checkboxPlayer4Connected">
2228 <property name="text">
2229 <string/>
2230 </property>
2231 </widget>
2232 </item>
2233 <item row="1" column="0">
2234 <widget class="QLabel" name="labelControllers">
2235 <property name="text">
2236 <string>Controllers</string>
2237 </property>
2238 </widget>
2239 </item>
2240 <item row="1" column="2">
2241 <widget class="QCheckBox" name="checkboxPlayer2Connected">
2242 <property name="text">
2243 <string/>
2244 </property>
2245 </widget>
2246 </item>
2247 <item row="0" column="1">
2248 <widget class="QLabel" name="labelConnectedPlayer1">
2249 <property name="text">
2250 <string>1</string>
2251 </property>
2252 <property name="alignment">
2253 <set>Qt::AlignCenter</set>
2254 </property>
2255 </widget>
2256 </item>
2257 <item row="1" column="3">
2258 <widget class="QCheckBox" name="checkboxPlayer3Connected">
2259 <property name="text">
2260 <string/>
2261 </property>
2262 </widget>
2263 </item>
2264 <item row="1" column="1">
2265 <widget class="QCheckBox" name="checkboxPlayer1Connected">
2266 <property name="layoutDirection">
2267 <enum>Qt::LeftToRight</enum>
2268 </property>
2269 <property name="checked">
2270 <bool>false</bool>
2271 </property>
2272 </widget>
2273 </item>
2274 <item row="0" column="2">
2275 <widget class="QLabel" name="labelConnectedPlayer2">
2276 <property name="text">
2277 <string>2</string>
2278 </property>
2279 <property name="alignment">
2280 <set>Qt::AlignCenter</set>
2281 </property>
2282 </widget>
2283 </item>
2284 <item row="0" column="4">
2285 <widget class="QLabel" name="labelConnectedPlayer4">
2286 <property name="text">
2287 <string>4</string>
2288 </property>
2289 <property name="alignment">
2290 <set>Qt::AlignCenter</set>
2291 </property>
2292 </widget>
2293 </item>
2294 <item row="0" column="3">
2295 <widget class="QLabel" name="labelConnectedPlayer3">
2296 <property name="text">
2297 <string>3</string>
2298 </property>
2299 <property name="alignment">
2300 <set>Qt::AlignCenter</set>
2301 </property>
2302 </widget>
2303 </item>
2304 <item row="0" column="0">
2305 <widget class="QLabel" name="labelConnected">
2306 <property name="text">
2307 <string>Connected</string>
2308 </property>
2309 </widget>
2310 </item>
2311 <item row="1" column="7">
2312 <widget class="QCheckBox" name="checkboxPlayer7Connected">
2313 <property name="text">
2314 <string/>
2315 </property>
2316 </widget>
2317 </item>
2318 <item row="0" column="5">
2319 <widget class="QLabel" name="labelConnectedPlayer5">
2320 <property name="text">
2321 <string>5</string>
2322 </property>
2323 <property name="alignment">
2324 <set>Qt::AlignCenter</set>
2325 </property>
2326 </widget>
2327 </item>
2328 <item row="1" column="6">
2329 <widget class="QCheckBox" name="checkboxPlayer6Connected">
2330 <property name="text">
2331 <string/>
2332 </property>
2333 </widget>
2334 </item>
2335 <item row="0" column="7">
2336 <widget class="QLabel" name="labelConnectedPlayer7">
2337 <property name="text">
2338 <string>7</string>
2339 </property>
2340 <property name="alignment">
2341 <set>Qt::AlignCenter</set>
2342 </property>
2343 </widget>
2344 </item>
2345 <item row="1" column="5">
2346 <widget class="QCheckBox" name="checkboxPlayer5Connected">
2347 <property name="text">
2348 <string/>
2349 </property>
2350 </widget>
2351 </item>
2352 <item row="0" column="6">
2353 <widget class="QLabel" name="labelConnectedPlayer6">
2354 <property name="text">
2355 <string>6</string>
2356 </property>
2357 <property name="alignment">
2358 <set>Qt::AlignCenter</set>
2359 </property>
2360 </widget>
2361 </item>
2362 <item row="0" column="8">
2363 <widget class="QLabel" name="labelConnectedPlayer8">
2364 <property name="text">
2365 <string>8</string>
2366 </property>
2367 <property name="alignment">
2368 <set>Qt::AlignCenter</set>
2369 </property>
2370 </widget>
2371 </item>
2372 <item row="1" column="8">
2373 <widget class="QCheckBox" name="checkboxPlayer8Connected">
2374 <property name="text">
2375 <string/>
2376 </property>
2377 </widget>
2378 </item>
2379 </layout>
2380 </widget>
2381 </item>
2382 <item>
2383 <spacer name="controllerAppletHorizontalSpacer">
2384 <property name="orientation">
2385 <enum>Qt::Horizontal</enum>
2386 </property>
2387 <property name="sizeHint" stdset="0">
2388 <size>
2389 <width>0</width>
2390 <height>20</height>
2391 </size>
2392 </property>
2393 </spacer>
2394 </item>
2395 <item alignment="Qt::AlignBottom">
2396 <widget class="QDialogButtonBox" name="buttonBox">
2397 <property name="enabled">
2398 <bool>false</bool>
2399 </property>
2400 <property name="standardButtons">
2401 <set>QDialogButtonBox::Ok</set>
2402 </property>
2403 </widget>
2404 </item>
2405 </layout>
2406 </widget>
2407 </item>
2408 </layout>
2409 </widget>
2410 </item>
2411 </layout>
2412 </widget>
2413 <resources/>
2414 <connections>
2415 <connection>
2416 <sender>buttonBox</sender>
2417 <signal>accepted()</signal>
2418 <receiver>QtControllerSelectorDialog</receiver>
2419 <slot>accept()</slot>
2420 <hints>
2421 <hint type="sourcelabel">
2422 <x>20</x>
2423 <y>20</y>
2424 </hint>
2425 <hint type="destinationlabel">
2426 <x>20</x>
2427 <y>20</y>
2428 </hint>
2429 </hints>
2430 </connection>
2431 </connections>
2432</ui>
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index ae3e31762..3befcc739 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -70,7 +70,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
70 70
71ConfigureInput::~ConfigureInput() = default; 71ConfigureInput::~ConfigureInput() = default;
72 72
73void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem) { 73void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, std::size_t max_players) {
74 player_controllers = { 74 player_controllers = {
75 new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem), 75 new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem),
76 new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem), 76 new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem),
@@ -93,6 +93,11 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem) {
93 ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected, 93 ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected,
94 }; 94 };
95 95
96 std::array<QLabel*, 8> player_connected_labels = {
97 ui->label, ui->label_3, ui->label_4, ui->label_5,
98 ui->label_6, ui->label_7, ui->label_8, ui->label_9,
99 };
100
96 for (std::size_t i = 0; i < player_tabs.size(); ++i) { 101 for (std::size_t i = 0; i < player_tabs.size(); ++i) {
97 player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i])); 102 player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i]));
98 player_tabs[i]->layout()->addWidget(player_controllers[i]); 103 player_tabs[i]->layout()->addWidget(player_controllers[i]);
@@ -112,6 +117,13 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem) {
112 connect(player_connected[i], &QCheckBox::stateChanged, [this, i](int state) { 117 connect(player_connected[i], &QCheckBox::stateChanged, [this, i](int state) {
113 player_controllers[i]->ConnectPlayer(state == Qt::Checked); 118 player_controllers[i]->ConnectPlayer(state == Qt::Checked);
114 }); 119 });
120
121 // Remove/hide all the elements that exceed max_players, if applicable.
122 if (i >= max_players) {
123 ui->tabWidget->removeTab(static_cast<int>(max_players));
124 player_connected[i]->hide();
125 player_connected_labels[i]->hide();
126 }
115 } 127 }
116 // Only the first player can choose handheld mode so connect the signal just to player 1 128 // Only the first player can choose handheld mode so connect the signal just to player 1
117 connect(player_controllers[0], &ConfigureInputPlayer::HandheldStateChanged, 129 connect(player_controllers[0], &ConfigureInputPlayer::HandheldStateChanged,
@@ -175,8 +187,7 @@ void ConfigureInput::RetranslateUI() {
175 187
176void ConfigureInput::LoadConfiguration() { 188void ConfigureInput::LoadConfiguration() {
177 LoadPlayerControllerIndices(); 189 LoadPlayerControllerIndices();
178 UpdateDockedState(Settings::values.players[0].controller_type == 190 UpdateDockedState(Settings::values.players[8].connected);
179 Settings::ControllerType::Handheld);
180 191
181 ui->vibrationGroup->setChecked(Settings::values.vibration_enabled); 192 ui->vibrationGroup->setChecked(Settings::values.vibration_enabled);
182} 193}
@@ -208,14 +219,14 @@ void ConfigureInput::RestoreDefaults() {
208} 219}
209 220
210void ConfigureInput::UpdateDockedState(bool is_handheld) { 221void ConfigureInput::UpdateDockedState(bool is_handheld) {
211 // If the controller type is handheld only, disallow changing docked mode 222 // Disallow changing the console mode if the controller type is handheld.
212 ui->radioDocked->setEnabled(!is_handheld); 223 ui->radioDocked->setEnabled(!is_handheld);
213 ui->radioUndocked->setEnabled(!is_handheld); 224 ui->radioUndocked->setEnabled(!is_handheld);
214 225
215 ui->radioDocked->setChecked(Settings::values.use_docked_mode); 226 ui->radioDocked->setChecked(Settings::values.use_docked_mode);
216 ui->radioUndocked->setChecked(!Settings::values.use_docked_mode); 227 ui->radioUndocked->setChecked(!Settings::values.use_docked_mode);
217 228
218 // If its handheld only, force docked mode off (since you can't play handheld in a dock) 229 // Also force into undocked mode if the controller type is handheld.
219 if (is_handheld) { 230 if (is_handheld) {
220 ui->radioUndocked->setChecked(true); 231 ui->radioUndocked->setChecked(true);
221 } 232 }
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index d08a24f96..0e8b2fd4e 100644
--- a/src/yuzu/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
@@ -37,7 +37,7 @@ public:
37 ~ConfigureInput() override; 37 ~ConfigureInput() override;
38 38
39 /// Initializes the input dialog with the given input subsystem. 39 /// Initializes the input dialog with the given input subsystem.
40 void Initialize(InputCommon::InputSubsystem* input_subsystem_); 40 void Initialize(InputCommon::InputSubsystem* input_subsystem_, std::size_t max_players = 8);
41 41
42 /// Save all button configurations to settings file. 42 /// Save all button configurations to settings file.
43 void ApplyConfiguration(); 43 void ApplyConfiguration();
diff --git a/src/yuzu/configuration/configure_input_dialog.cpp b/src/yuzu/configuration/configure_input_dialog.cpp
new file mode 100644
index 000000000..1866003c2
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_dialog.cpp
@@ -0,0 +1,37 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "ui_configure_input_dialog.h"
6#include "yuzu/configuration/configure_input_dialog.h"
7
8ConfigureInputDialog::ConfigureInputDialog(QWidget* parent, std::size_t max_players,
9 InputCommon::InputSubsystem* input_subsystem)
10 : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputDialog>()),
11 input_widget(new ConfigureInput(this)) {
12 ui->setupUi(this);
13
14 input_widget->Initialize(input_subsystem, max_players);
15
16 ui->inputLayout->addWidget(input_widget);
17
18 RetranslateUI();
19}
20
21ConfigureInputDialog::~ConfigureInputDialog() = default;
22
23void ConfigureInputDialog::ApplyConfiguration() {
24 input_widget->ApplyConfiguration();
25}
26
27void ConfigureInputDialog::changeEvent(QEvent* event) {
28 if (event->type() == QEvent::LanguageChange) {
29 RetranslateUI();
30 }
31
32 QDialog::changeEvent(event);
33}
34
35void ConfigureInputDialog::RetranslateUI() {
36 ui->retranslateUi(this);
37}
diff --git a/src/yuzu/configuration/configure_input_dialog.h b/src/yuzu/configuration/configure_input_dialog.h
new file mode 100644
index 000000000..d1bd865f9
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_dialog.h
@@ -0,0 +1,38 @@
1// Copyright 2020 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 <memory>
8#include <QDialog>
9#include "yuzu/configuration/configure_input.h"
10
11class QPushButton;
12
13namespace InputCommon {
14class InputSubsystem;
15}
16
17namespace Ui {
18class ConfigureInputDialog;
19}
20
21class ConfigureInputDialog : public QDialog {
22 Q_OBJECT
23
24public:
25 explicit ConfigureInputDialog(QWidget* parent, std::size_t max_players,
26 InputCommon::InputSubsystem* input_subsystem);
27 ~ConfigureInputDialog() override;
28
29 void ApplyConfiguration();
30
31private:
32 void changeEvent(QEvent* event) override;
33 void RetranslateUI();
34
35 std::unique_ptr<Ui::ConfigureInputDialog> ui;
36
37 ConfigureInput* input_widget;
38};
diff --git a/src/yuzu/configuration/configure_input_dialog.ui b/src/yuzu/configuration/configure_input_dialog.ui
new file mode 100644
index 000000000..b92ddb200
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_dialog.ui
@@ -0,0 +1,57 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureInputDialog</class>
4 <widget class="QDialog" name="ConfigureInputDialog">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>70</width>
10 <height>540</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Configure Input</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <property name="spacing">
18 <number>2</number>
19 </property>
20 <property name="leftMargin">
21 <number>9</number>
22 </property>
23 <property name="topMargin">
24 <number>9</number>
25 </property>
26 <property name="rightMargin">
27 <number>9</number>
28 </property>
29 <property name="bottomMargin">
30 <number>9</number>
31 </property>
32 <item>
33 <layout class="QHBoxLayout" name="inputLayout"/>
34 </item>
35 <item>
36 <layout class="QHBoxLayout" name="horizontalLayout">
37 <item>
38 <widget class="QDialogButtonBox" name="buttonBox">
39 <property name="standardButtons">
40 <set>QDialogButtonBox::Ok</set>
41 </property>
42 </widget>
43 </item>
44 </layout>
45 </item>
46 </layout>
47 </widget>
48 <resources/>
49 <connections>
50 <connection>
51 <sender>buttonBox</sender>
52 <signal>accepted()</signal>
53 <receiver>ConfigureInputDialog</receiver>
54 <slot>accept()</slot>
55 </connection>
56 </connections>
57</ui>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index a1b61d119..2ac8344a3 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -11,6 +11,7 @@
11#endif 11#endif
12 12
13// VFS includes must be before glad as they will conflict with Windows file api, which uses defines. 13// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
14#include "applets/controller.h"
14#include "applets/error.h" 15#include "applets/error.h"
15#include "applets/profile_select.h" 16#include "applets/profile_select.h"
16#include "applets/software_keyboard.h" 17#include "applets/software_keyboard.h"
@@ -19,7 +20,9 @@
19#include "configuration/configure_per_game.h" 20#include "configuration/configure_per_game.h"
20#include "core/file_sys/vfs.h" 21#include "core/file_sys/vfs.h"
21#include "core/file_sys/vfs_real.h" 22#include "core/file_sys/vfs_real.h"
23#include "core/frontend/applets/controller.h"
22#include "core/frontend/applets/general_frontend.h" 24#include "core/frontend/applets/general_frontend.h"
25#include "core/frontend/applets/software_keyboard.h"
23#include "core/hle/service/acc/profile_manager.h" 26#include "core/hle/service/acc/profile_manager.h"
24#include "core/hle/service/am/applet_ae.h" 27#include "core/hle/service/am/applet_ae.h"
25#include "core/hle/service/am/applet_oe.h" 28#include "core/hle/service/am/applet_oe.h"
@@ -84,7 +87,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
84#include "core/file_sys/romfs.h" 87#include "core/file_sys/romfs.h"
85#include "core/file_sys/savedata_factory.h" 88#include "core/file_sys/savedata_factory.h"
86#include "core/file_sys/submission_package.h" 89#include "core/file_sys/submission_package.h"
87#include "core/frontend/applets/software_keyboard.h"
88#include "core/hle/kernel/process.h" 90#include "core/hle/kernel/process.h"
89#include "core/hle/service/am/am.h" 91#include "core/hle/service/am/am.h"
90#include "core/hle/service/filesystem/filesystem.h" 92#include "core/hle/service/filesystem/filesystem.h"
@@ -283,6 +285,19 @@ GMainWindow::~GMainWindow() {
283 delete render_window; 285 delete render_window;
284} 286}
285 287
288void GMainWindow::ControllerSelectorReconfigureControllers(
289 const Core::Frontend::ControllerParameters& parameters) {
290 QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get());
291 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
292 Qt::WindowSystemMenuHint);
293 dialog.setWindowModality(Qt::WindowModal);
294 dialog.exec();
295
296 emit ControllerSelectorReconfigureFinished();
297
298 UpdateStatusButtons();
299}
300
286void GMainWindow::ProfileSelectorSelectProfile() { 301void GMainWindow::ProfileSelectorSelectProfile() {
287 const Service::Account::ProfileManager manager; 302 const Service::Account::ProfileManager manager;
288 int index = 0; 303 int index = 0;
@@ -291,10 +306,12 @@ void GMainWindow::ProfileSelectorSelectProfile() {
291 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | 306 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
292 Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); 307 Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
293 dialog.setWindowModality(Qt::WindowModal); 308 dialog.setWindowModality(Qt::WindowModal);
309
294 if (dialog.exec() == QDialog::Rejected) { 310 if (dialog.exec() == QDialog::Rejected) {
295 emit ProfileSelectorFinishedSelection(std::nullopt); 311 emit ProfileSelectorFinishedSelection(std::nullopt);
296 return; 312 return;
297 } 313 }
314
298 index = dialog.GetIndex(); 315 index = dialog.GetIndex();
299 } 316 }
300 317
@@ -966,13 +983,14 @@ bool GMainWindow::LoadROM(const QString& filename) {
966 system.SetFilesystem(vfs); 983 system.SetFilesystem(vfs);
967 984
968 system.SetAppletFrontendSet({ 985 system.SetAppletFrontendSet({
969 nullptr, // Parental Controls 986 std::make_unique<QtControllerSelector>(*this), // Controller Selector
970 std::make_unique<QtErrorDisplay>(*this), // 987 nullptr, // E-Commerce
971 nullptr, // Photo Viewer 988 std::make_unique<QtErrorDisplay>(*this), // Error Display
972 std::make_unique<QtProfileSelector>(*this), // 989 nullptr, // Parental Controls
973 std::make_unique<QtSoftwareKeyboard>(*this), // 990 nullptr, // Photo Viewer
974 std::make_unique<QtWebBrowser>(*this), // 991 std::make_unique<QtProfileSelector>(*this), // Profile Selector
975 nullptr, // E-Commerce 992 std::make_unique<QtSoftwareKeyboard>(*this), // Software Keyboard
993 std::make_unique<QtWebBrowser>(*this), // Web Browser
976 }); 994 });
977 995
978 system.RegisterHostThread(); 996 system.RegisterHostThread();
@@ -2047,6 +2065,7 @@ void GMainWindow::OnStartGame() {
2047 2065
2048 emu_thread->SetRunning(true); 2066 emu_thread->SetRunning(true);
2049 2067
2068 qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
2050 qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>( 2069 qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>(
2051 "Core::Frontend::SoftwareKeyboardParameters"); 2070 "Core::Frontend::SoftwareKeyboardParameters");
2052 qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus"); 2071 qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 0ce66a1ca..afcfa68a9 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -37,6 +37,7 @@ enum class InstalledEntryType;
37class GameListPlaceholder; 37class GameListPlaceholder;
38 38
39namespace Core::Frontend { 39namespace Core::Frontend {
40struct ControllerParameters;
40struct SoftwareKeyboardParameters; 41struct SoftwareKeyboardParameters;
41} // namespace Core::Frontend 42} // namespace Core::Frontend
42 43
@@ -116,9 +117,12 @@ signals:
116 117
117 void UpdateInstallProgress(); 118 void UpdateInstallProgress();
118 119
120 void ControllerSelectorReconfigureFinished();
121
119 void ErrorDisplayFinished(); 122 void ErrorDisplayFinished();
120 123
121 void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid); 124 void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
125
122 void SoftwareKeyboardFinishedText(std::optional<std::u16string> text); 126 void SoftwareKeyboardFinishedText(std::optional<std::u16string> text);
123 void SoftwareKeyboardFinishedCheckDialog(); 127 void SoftwareKeyboardFinishedCheckDialog();
124 128
@@ -127,6 +131,8 @@ signals:
127 131
128public slots: 132public slots:
129 void OnLoadComplete(); 133 void OnLoadComplete();
134 void ControllerSelectorReconfigureControllers(
135 const Core::Frontend::ControllerParameters& parameters);
130 void ErrorDisplayDisplayError(QString body); 136 void ErrorDisplayDisplayError(QString body);
131 void ProfileSelectorSelectProfile(); 137 void ProfileSelectorSelectProfile();
132 void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); 138 void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);