summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/param_package.h2
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp213
-rw-r--r--src/core/hle/service/hid/controllers/npad.h11
-rw-r--r--src/core/hle/service/hid/hid.cpp14
-rw-r--r--src/core/settings.cpp50
-rw-r--r--src/core/settings.h339
-rw-r--r--src/input_common/CMakeLists.txt2
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp2
-rw-r--r--src/input_common/main.cpp50
-rw-r--r--src/input_common/main.h26
-rw-r--r--src/input_common/sdl/sdl.h19
-rw-r--r--src/input_common/sdl/sdl_impl.cpp403
-rw-r--r--src/input_common/sdl/sdl_impl.h8
-rw-r--r--src/input_common/settings.cpp33
-rw-r--r--src/input_common/settings.h335
-rw-r--r--src/input_common/udp/udp.cpp15
-rw-r--r--src/input_common/udp/udp.h7
-rw-r--r--src/yuzu/CMakeLists.txt9
-rw-r--r--src/yuzu/configuration/config.cpp58
-rw-r--r--src/yuzu/configuration/config.h5
-rw-r--r--src/yuzu/configuration/configure.ui59
-rw-r--r--src/yuzu/configuration/configure_debug_controller.cpp39
-rw-r--r--src/yuzu/configuration/configure_debug_controller.h33
-rw-r--r--src/yuzu/configuration/configure_debug_controller.ui97
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp8
-rw-r--r--src/yuzu/configuration/configure_input.cpp265
-rw-r--r--src/yuzu/configuration/configure_input.h22
-rw-r--r--src/yuzu/configuration/configure_input.ui1039
-rw-r--r--src/yuzu/configuration/configure_input_advanced.cpp169
-rw-r--r--src/yuzu/configuration/configure_input_advanced.h44
-rw-r--r--src/yuzu/configuration/configure_input_advanced.ui2688
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp733
-rw-r--r--src/yuzu/configuration/configure_input_player.h106
-rw-r--r--src/yuzu/configuration/configure_input_player.ui4019
-rw-r--r--src/yuzu/configuration/configure_input_simple.cpp152
-rw-r--r--src/yuzu/configuration/configure_input_simple.h43
-rw-r--r--src/yuzu/configuration/configure_input_simple.ui97
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.cpp8
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.ui252
-rw-r--r--src/yuzu/uisettings.cpp1
-rw-r--r--src/yuzu/uisettings.h5
-rw-r--r--src/yuzu_cmd/config.cpp2
-rw-r--r--src/yuzu_tester/config.cpp1
43 files changed, 8306 insertions, 3177 deletions
diff --git a/src/common/param_package.h b/src/common/param_package.h
index c8a70bfa9..c13e45479 100644
--- a/src/common/param_package.h
+++ b/src/common/param_package.h
@@ -19,7 +19,7 @@ public:
19 explicit ParamPackage(const std::string& serialized); 19 explicit ParamPackage(const std::string& serialized);
20 ParamPackage(std::initializer_list<DataType::value_type> list); 20 ParamPackage(std::initializer_list<DataType::value_type> list);
21 ParamPackage(const ParamPackage& other) = default; 21 ParamPackage(const ParamPackage& other) = default;
22 ParamPackage(ParamPackage&& other) = default; 22 ParamPackage(ParamPackage&& other) noexcept = default;
23 23
24 ParamPackage& operator=(const ParamPackage& other) = default; 24 ParamPackage& operator=(const ParamPackage& other) = default;
25 ParamPackage& operator=(ParamPackage&& other) = default; 25 ParamPackage& operator=(ParamPackage&& other) = default;
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 0e7794dc7..82e11b169 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -24,6 +24,7 @@ constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
24constexpr std::size_t NPAD_OFFSET = 0x9A00; 24constexpr std::size_t NPAD_OFFSET = 0x9A00;
25constexpr u32 BATTERY_FULL = 2; 25constexpr u32 BATTERY_FULL = 2;
26constexpr u32 MAX_NPAD_ID = 7; 26constexpr u32 MAX_NPAD_ID = 7;
27constexpr std::size_t HANDHELD_INDEX = 8;
27constexpr std::array<u32, 10> npad_id_list{ 28constexpr std::array<u32, 10> npad_id_list{
28 0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN, 29 0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN,
29}; 30};
@@ -33,19 +34,41 @@ enum class JoystickId : std::size_t {
33 Joystick_Right, 34 Joystick_Right,
34}; 35};
35 36
36static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type) { 37Controller_NPad::NPadControllerType Controller_NPad::MapSettingsTypeToNPad(
38 Settings::ControllerType type) {
37 switch (type) { 39 switch (type) {
38 case Settings::ControllerType::ProController: 40 case Settings::ControllerType::ProController:
39 return Controller_NPad::NPadControllerType::ProController; 41 return NPadControllerType::ProController;
40 case Settings::ControllerType::DualJoycon: 42 case Settings::ControllerType::DualJoyconDetached:
41 return Controller_NPad::NPadControllerType::JoyDual; 43 return NPadControllerType::JoyDual;
42 case Settings::ControllerType::LeftJoycon: 44 case Settings::ControllerType::LeftJoycon:
43 return Controller_NPad::NPadControllerType::JoyLeft; 45 return NPadControllerType::JoyLeft;
44 case Settings::ControllerType::RightJoycon: 46 case Settings::ControllerType::RightJoycon:
45 return Controller_NPad::NPadControllerType::JoyRight; 47 return NPadControllerType::JoyRight;
48 case Settings::ControllerType::Handheld:
49 return NPadControllerType::Handheld;
46 default: 50 default:
47 UNREACHABLE(); 51 UNREACHABLE();
48 return Controller_NPad::NPadControllerType::JoyDual; 52 return NPadControllerType::ProController;
53 }
54}
55
56Settings::ControllerType Controller_NPad::MapNPadToSettingsType(
57 Controller_NPad::NPadControllerType type) {
58 switch (type) {
59 case NPadControllerType::ProController:
60 return Settings::ControllerType::ProController;
61 case NPadControllerType::JoyDual:
62 return Settings::ControllerType::DualJoyconDetached;
63 case NPadControllerType::JoyLeft:
64 return Settings::ControllerType::LeftJoycon;
65 case NPadControllerType::JoyRight:
66 return Settings::ControllerType::RightJoycon;
67 case NPadControllerType::Handheld:
68 return Settings::ControllerType::Handheld;
69 default:
70 UNREACHABLE();
71 return Settings::ControllerType::ProController;
49 } 72 }
50} 73}
51 74
@@ -60,9 +83,9 @@ std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) {
60 case 6: 83 case 6:
61 case 7: 84 case 7:
62 return npad_id; 85 return npad_id;
63 case 8: 86 case HANDHELD_INDEX:
64 case NPAD_HANDHELD: 87 case NPAD_HANDHELD:
65 return 8; 88 return HANDHELD_INDEX;
66 case 9: 89 case 9:
67 case NPAD_UNKNOWN: 90 case NPAD_UNKNOWN:
68 return 9; 91 return 9;
@@ -83,7 +106,7 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
83 case 6: 106 case 6:
84 case 7: 107 case 7:
85 return static_cast<u32>(index); 108 return static_cast<u32>(index);
86 case 8: 109 case HANDHELD_INDEX:
87 return NPAD_HANDHELD; 110 return NPAD_HANDHELD;
88 case 9: 111 case 9:
89 return NPAD_UNKNOWN; 112 return NPAD_UNKNOWN;
@@ -96,25 +119,35 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
96Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {} 119Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {}
97Controller_NPad::~Controller_NPad() = default; 120Controller_NPad::~Controller_NPad() = default;
98 121
99void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { 122void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
100 const auto controller_type = connected_controllers[controller_idx].type; 123 const auto controller_type = connected_controllers[controller_idx].type;
101 auto& controller = shared_memory_entries[controller_idx]; 124 auto& controller = shared_memory_entries[controller_idx];
102 if (controller_type == NPadControllerType::None) { 125 if (controller_type == NPadControllerType::None) {
126 styleset_changed_events[controller_idx].writable->Signal();
103 return; 127 return;
104 } 128 }
105 controller.joy_styles.raw = 0; // Zero out 129 controller.joy_styles.raw = 0; // Zero out
106 controller.device_type.raw = 0; 130 controller.device_type.raw = 0;
131 controller.properties.raw = 0;
107 switch (controller_type) { 132 switch (controller_type) {
108 case NPadControllerType::None: 133 case NPadControllerType::None:
109 UNREACHABLE(); 134 UNREACHABLE();
110 break; 135 break;
136 case NPadControllerType::ProController:
137 controller.joy_styles.pro_controller.Assign(1);
138 controller.device_type.pro_controller.Assign(1);
139 controller.properties.is_vertical.Assign(1);
140 controller.properties.use_plus.Assign(1);
141 controller.properties.use_minus.Assign(1);
142 controller.pad_assignment = NPadAssignments::Single;
143 break;
111 case NPadControllerType::Handheld: 144 case NPadControllerType::Handheld:
112 controller.joy_styles.handheld.Assign(1); 145 controller.joy_styles.handheld.Assign(1);
113 controller.device_type.handheld.Assign(1); 146 controller.device_type.handheld.Assign(1);
114 controller.pad_assignment = NPadAssignments::Dual;
115 controller.properties.is_vertical.Assign(1); 147 controller.properties.is_vertical.Assign(1);
116 controller.properties.use_plus.Assign(1); 148 controller.properties.use_plus.Assign(1);
117 controller.properties.use_minus.Assign(1); 149 controller.properties.use_minus.Assign(1);
150 controller.pad_assignment = NPadAssignments::Dual;
118 break; 151 break;
119 case NPadControllerType::JoyDual: 152 case NPadControllerType::JoyDual:
120 controller.joy_styles.joycon_dual.Assign(1); 153 controller.joy_styles.joycon_dual.Assign(1);
@@ -144,14 +177,6 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
144 controller.device_type.pokeball.Assign(1); 177 controller.device_type.pokeball.Assign(1);
145 controller.pad_assignment = NPadAssignments::Single; 178 controller.pad_assignment = NPadAssignments::Single;
146 break; 179 break;
147 case NPadControllerType::ProController:
148 controller.joy_styles.pro_controller.Assign(1);
149 controller.device_type.pro_controller.Assign(1);
150 controller.properties.is_vertical.Assign(1);
151 controller.properties.use_plus.Assign(1);
152 controller.properties.use_minus.Assign(1);
153 controller.pad_assignment = NPadAssignments::Single;
154 break;
155 } 180 }
156 181
157 controller.single_color_error = ColorReadError::ReadOk; 182 controller.single_color_error = ColorReadError::ReadOk;
@@ -192,36 +217,25 @@ void Controller_NPad::OnInit() {
192 style.pokeball.Assign(1); 217 style.pokeball.Assign(1);
193 } 218 }
194 219
195 std::transform( 220 std::transform(Settings::values.players.begin(), Settings::values.players.end(),
196 Settings::values.players.begin(), Settings::values.players.end(), 221 connected_controllers.begin(), [](const Settings::PlayerInput& player) {
197 connected_controllers.begin(), [](const Settings::PlayerInput& player) { 222 return ControllerHolder{MapSettingsTypeToNPad(player.controller_type),
198 return ControllerHolder{MapSettingsTypeToNPad(player.type), player.connected}; 223 player.connected};
199 }); 224 });
200
201 std::stable_partition(connected_controllers.begin(), connected_controllers.begin() + 8,
202 [](const ControllerHolder& holder) { return holder.is_connected; });
203 225
204 // Account for handheld 226 // Account for handheld
205 if (connected_controllers[8].is_connected) 227 if (connected_controllers[HANDHELD_INDEX].is_connected) {
206 connected_controllers[8].type = NPadControllerType::Handheld; 228 connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld;
229 }
207 230
208 supported_npad_id_types.resize(npad_id_list.size()); 231 supported_npad_id_types.resize(npad_id_list.size());
209 std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), 232 std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
210 npad_id_list.size() * sizeof(u32)); 233 npad_id_list.size() * sizeof(u32));
211 234
212 // Add a default dual joycon controller if none are present.
213 if (std::none_of(connected_controllers.begin(), connected_controllers.end(),
214 [](const ControllerHolder& controller) { return controller.is_connected; })) {
215 supported_npad_id_types.resize(npad_id_list.size());
216 std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
217 npad_id_list.size() * sizeof(u32));
218 AddNewController(NPadControllerType::JoyDual);
219 }
220
221 for (std::size_t i = 0; i < connected_controllers.size(); ++i) { 235 for (std::size_t i = 0; i < connected_controllers.size(); ++i) {
222 const auto& controller = connected_controllers[i]; 236 const auto& controller = connected_controllers[i];
223 if (controller.is_connected) { 237 if (controller.is_connected) {
224 AddNewControllerAt(controller.type, IndexToNPad(i)); 238 AddNewControllerAt(controller.type, i);
225 } 239 }
226 } 240 }
227} 241}
@@ -309,8 +323,9 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
309 323
310void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 324void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
311 std::size_t data_len) { 325 std::size_t data_len) {
312 if (!IsControllerActivated()) 326 if (!IsControllerActivated()) {
313 return; 327 return;
328 }
314 for (std::size_t i = 0; i < shared_memory_entries.size(); i++) { 329 for (std::size_t i = 0; i < shared_memory_entries.size(); i++) {
315 auto& npad = shared_memory_entries[i]; 330 auto& npad = shared_memory_entries[i];
316 const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states, 331 const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states,
@@ -365,6 +380,14 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
365 case NPadControllerType::None: 380 case NPadControllerType::None:
366 UNREACHABLE(); 381 UNREACHABLE();
367 break; 382 break;
383 case NPadControllerType::ProController:
384 main_controller.connection_status.raw = 0;
385 main_controller.connection_status.IsConnected.Assign(1);
386 main_controller.connection_status.IsWired.Assign(1);
387 main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
388 main_controller.pad.l_stick = pad_state.l_stick;
389 main_controller.pad.r_stick = pad_state.r_stick;
390 break;
368 case NPadControllerType::Handheld: 391 case NPadControllerType::Handheld:
369 handheld_entry.connection_status.raw = 0; 392 handheld_entry.connection_status.raw = 0;
370 handheld_entry.connection_status.IsWired.Assign(1); 393 handheld_entry.connection_status.IsWired.Assign(1);
@@ -378,22 +401,19 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
378 break; 401 break;
379 case NPadControllerType::JoyDual: 402 case NPadControllerType::JoyDual:
380 dual_entry.connection_status.raw = 0; 403 dual_entry.connection_status.raw = 0;
381 404 dual_entry.connection_status.IsConnected.Assign(1);
382 dual_entry.connection_status.IsLeftJoyConnected.Assign(1); 405 dual_entry.connection_status.IsLeftJoyConnected.Assign(1);
383 dual_entry.connection_status.IsRightJoyConnected.Assign(1); 406 dual_entry.connection_status.IsRightJoyConnected.Assign(1);
384 dual_entry.connection_status.IsConnected.Assign(1);
385
386 libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
387 libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
388 libnx_entry.connection_status.IsConnected.Assign(1);
389
390 dual_entry.pad.pad_states.raw = pad_state.pad_states.raw; 407 dual_entry.pad.pad_states.raw = pad_state.pad_states.raw;
391 dual_entry.pad.l_stick = pad_state.l_stick; 408 dual_entry.pad.l_stick = pad_state.l_stick;
392 dual_entry.pad.r_stick = pad_state.r_stick; 409 dual_entry.pad.r_stick = pad_state.r_stick;
410
411 libnx_entry.connection_status.IsConnected.Assign(1);
412 libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
413 libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
393 break; 414 break;
394 case NPadControllerType::JoyLeft: 415 case NPadControllerType::JoyLeft:
395 left_entry.connection_status.raw = 0; 416 left_entry.connection_status.raw = 0;
396
397 left_entry.connection_status.IsConnected.Assign(1); 417 left_entry.connection_status.IsConnected.Assign(1);
398 left_entry.pad.pad_states.raw = pad_state.pad_states.raw; 418 left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
399 left_entry.pad.l_stick = pad_state.l_stick; 419 left_entry.pad.l_stick = pad_state.l_stick;
@@ -401,7 +421,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
401 break; 421 break;
402 case NPadControllerType::JoyRight: 422 case NPadControllerType::JoyRight:
403 right_entry.connection_status.raw = 0; 423 right_entry.connection_status.raw = 0;
404
405 right_entry.connection_status.IsConnected.Assign(1); 424 right_entry.connection_status.IsConnected.Assign(1);
406 right_entry.pad.pad_states.raw = pad_state.pad_states.raw; 425 right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
407 right_entry.pad.l_stick = pad_state.l_stick; 426 right_entry.pad.l_stick = pad_state.l_stick;
@@ -409,23 +428,12 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
409 break; 428 break;
410 case NPadControllerType::Pokeball: 429 case NPadControllerType::Pokeball:
411 pokeball_entry.connection_status.raw = 0; 430 pokeball_entry.connection_status.raw = 0;
412
413 pokeball_entry.connection_status.IsConnected.Assign(1); 431 pokeball_entry.connection_status.IsConnected.Assign(1);
414 pokeball_entry.connection_status.IsWired.Assign(1); 432 pokeball_entry.connection_status.IsWired.Assign(1);
415
416 pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw; 433 pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw;
417 pokeball_entry.pad.l_stick = pad_state.l_stick; 434 pokeball_entry.pad.l_stick = pad_state.l_stick;
418 pokeball_entry.pad.r_stick = pad_state.r_stick; 435 pokeball_entry.pad.r_stick = pad_state.r_stick;
419 break; 436 break;
420 case NPadControllerType::ProController:
421 main_controller.connection_status.raw = 0;
422
423 main_controller.connection_status.IsConnected.Assign(1);
424 main_controller.connection_status.IsWired.Assign(1);
425 main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
426 main_controller.pad.l_stick = pad_state.l_stick;
427 main_controller.pad.r_stick = pad_state.r_stick;
428 break;
429 } 437 }
430 438
431 // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate 439 // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
@@ -453,26 +461,6 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
453 supported_npad_id_types.clear(); 461 supported_npad_id_types.clear();
454 supported_npad_id_types.resize(length / sizeof(u32)); 462 supported_npad_id_types.resize(length / sizeof(u32));
455 std::memcpy(supported_npad_id_types.data(), data, length); 463 std::memcpy(supported_npad_id_types.data(), data, length);
456 for (std::size_t i = 0; i < connected_controllers.size(); i++) {
457 auto& controller = connected_controllers[i];
458 if (!controller.is_connected) {
459 continue;
460 }
461 const auto requested_controller =
462 i <= MAX_NPAD_ID ? MapSettingsTypeToNPad(Settings::values.players[i].type)
463 : NPadControllerType::Handheld;
464 if (!IsControllerSupported(requested_controller)) {
465 const auto is_handheld = requested_controller == NPadControllerType::Handheld;
466 if (is_handheld) {
467 controller.type = NPadControllerType::None;
468 controller.is_connected = false;
469 AddNewController(requested_controller);
470 } else {
471 controller.type = requested_controller;
472 InitNewlyAddedControler(i);
473 }
474 }
475 }
476} 464}
477 465
478void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { 466void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
@@ -504,7 +492,7 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
504 const std::vector<Vibration>& vibrations) { 492 const std::vector<Vibration>& vibrations) {
505 LOG_DEBUG(Service_HID, "(STUBBED) called"); 493 LOG_DEBUG(Service_HID, "(STUBBED) called");
506 494
507 if (!can_controllers_vibrate) { 495 if (!Settings::values.vibration_enabled || !can_controllers_vibrate) {
508 return; 496 return;
509 } 497 }
510 for (std::size_t i = 0; i < controller_ids.size(); i++) { 498 for (std::size_t i = 0; i < controller_ids.size(); i++) {
@@ -517,8 +505,6 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
517} 505}
518 506
519std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const { 507std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
520 // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
521 // be signalled at least once, and signaled after a new controller is connected?
522 const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)]; 508 const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
523 return styleset_event.readable; 509 return styleset_event.readable;
524} 510}
@@ -527,43 +513,43 @@ Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
527 return last_processed_vibration; 513 return last_processed_vibration;
528} 514}
529 515
530void Controller_NPad::AddNewController(NPadControllerType controller) { 516void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) {
531 controller = DecideBestController(controller); 517 UpdateControllerAt(controller, npad_index, true);
532 if (controller == NPadControllerType::Handheld) { 518}
533 connected_controllers[8] = {controller, true}; 519
534 InitNewlyAddedControler(8); 520void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,
535 return; 521 bool connected) {
536 } 522 if (!connected) {
537 const auto pos = 523 DisconnectNPad(IndexToNPad(npad_index));
538 std::find_if(connected_controllers.begin(), connected_controllers.end() - 2,
539 [](const ControllerHolder& holder) { return !holder.is_connected; });
540 if (pos == connected_controllers.end() - 2) {
541 LOG_ERROR(Service_HID, "Cannot connect any more controllers!");
542 return; 524 return;
543 } 525 }
544 const auto controller_id = std::distance(connected_controllers.begin(), pos);
545 connected_controllers[controller_id] = {controller, true};
546 InitNewlyAddedControler(controller_id);
547}
548 526
549void Controller_NPad::AddNewControllerAt(NPadControllerType controller, u32 npad_id) {
550 controller = DecideBestController(controller);
551 if (controller == NPadControllerType::Handheld) { 527 if (controller == NPadControllerType::Handheld) {
552 connected_controllers[NPadIdToIndex(NPAD_HANDHELD)] = {controller, true}; 528 Settings::values.players[HANDHELD_INDEX].controller_type =
553 InitNewlyAddedControler(NPadIdToIndex(NPAD_HANDHELD)); 529 MapNPadToSettingsType(controller);
530 Settings::values.players[HANDHELD_INDEX].connected = true;
531 connected_controllers[HANDHELD_INDEX] = {controller, true};
532 InitNewlyAddedController(HANDHELD_INDEX);
554 return; 533 return;
555 } 534 }
556 535
557 connected_controllers[NPadIdToIndex(npad_id)] = {controller, true}; 536 Settings::values.players[npad_index].controller_type = MapNPadToSettingsType(controller);
558 InitNewlyAddedControler(NPadIdToIndex(npad_id)); 537 Settings::values.players[npad_index].connected = true;
559} 538 connected_controllers[npad_index] = {controller, true};
560 539 InitNewlyAddedController(npad_index);
561void Controller_NPad::ConnectNPad(u32 npad_id) {
562 connected_controllers[NPadIdToIndex(npad_id)].is_connected = true;
563} 540}
564 541
565void Controller_NPad::DisconnectNPad(u32 npad_id) { 542void Controller_NPad::DisconnectNPad(u32 npad_id) {
566 connected_controllers[NPadIdToIndex(npad_id)].is_connected = false; 543 const auto npad_index = NPadIdToIndex(npad_id);
544 connected_controllers[npad_index].is_connected = false;
545 Settings::values.players[npad_index].connected = false;
546
547 auto& controller = shared_memory_entries[npad_index];
548 controller.joy_styles.raw = 0; // Zero out
549 controller.device_type.raw = 0;
550 controller.properties.raw = 0;
551
552 styleset_changed_events[npad_index].writable->Signal();
567} 553}
568 554
569void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) { 555void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) {
@@ -599,8 +585,8 @@ bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) {
599 585
600 std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type); 586 std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type);
601 587
602 InitNewlyAddedControler(npad_index_1); 588 AddNewControllerAt(connected_controllers[npad_index_1].type, npad_index_1);
603 InitNewlyAddedControler(npad_index_2); 589 AddNewControllerAt(connected_controllers[npad_index_2].type, npad_index_2);
604 590
605 return true; 591 return true;
606} 592}
@@ -628,7 +614,6 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
628 case 7: 614 case 7:
629 return LedPattern{0, 1, 1, 0}; 615 return LedPattern{0, 1, 1, 0};
630 default: 616 default:
631 UNIMPLEMENTED_MSG("Unhandled npad_id {}", npad_id);
632 return LedPattern{0, 0, 0, 0}; 617 return LedPattern{0, 0, 0, 0};
633 } 618 }
634} 619}
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 5d4c58a43..75ce5b731 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -118,10 +118,11 @@ public:
118 std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; 118 std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
119 Vibration GetLastVibration() const; 119 Vibration GetLastVibration() const;
120 120
121 void AddNewController(NPadControllerType controller); 121 // Adds a new controller at an index.
122 void AddNewControllerAt(NPadControllerType controller, u32 npad_id); 122 void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index);
123 // Adds a new controller at an index with connection status.
124 void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected);
123 125
124 void ConnectNPad(u32 npad_id);
125 void DisconnectNPad(u32 npad_id); 126 void DisconnectNPad(u32 npad_id);
126 void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); 127 void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
127 GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; 128 GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
@@ -141,6 +142,8 @@ public:
141 // Specifically for cheat engine and other features. 142 // Specifically for cheat engine and other features.
142 u32 GetAndResetPressState(); 143 u32 GetAndResetPressState();
143 144
145 static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type);
146 static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type);
144 static std::size_t NPadIdToIndex(u32 npad_id); 147 static std::size_t NPadIdToIndex(u32 npad_id);
145 static u32 IndexToNPad(std::size_t index); 148 static u32 IndexToNPad(std::size_t index);
146 149
@@ -309,7 +312,7 @@ private:
309 bool is_connected; 312 bool is_connected;
310 }; 313 };
311 314
312 void InitNewlyAddedControler(std::size_t controller_idx); 315 void InitNewlyAddedController(std::size_t controller_idx);
313 bool IsControllerSupported(NPadControllerType controller) const; 316 bool IsControllerSupported(NPadControllerType controller) const;
314 NPadControllerType DecideBestController(NPadControllerType priority) const; 317 NPadControllerType DecideBestController(NPadControllerType priority) const;
315 void RequestPadStateUpdate(u32 npad_id); 318 void RequestPadStateUpdate(u32 npad_id);
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 1e95b7580..33416b5dd 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -38,11 +38,9 @@
38namespace Service::HID { 38namespace Service::HID {
39 39
40// Updating period for each HID device. 40// Updating period for each HID device.
41// TODO(ogniK): Find actual polling rate of hid 41// HID is polled every 15ms, this value was derived from
42constexpr auto pad_update_ns = std::chrono::nanoseconds{1000000000 / 66}; 42// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet
43[[maybe_unused]] constexpr auto accelerometer_update_ns = 43constexpr auto pad_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.6Hz)
44 std::chrono::nanoseconds{1000000000 / 100};
45[[maybe_unused]] constexpr auto gyroscope_update_ticks = std::chrono::nanoseconds{1000000000 / 100};
46constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; 44constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
47 45
48IAppletResource::IAppletResource(Core::System& system) 46IAppletResource::IAppletResource(Core::System& system)
@@ -845,8 +843,7 @@ void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
845void Hid::PermitVibration(Kernel::HLERequestContext& ctx) { 843void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {
846 IPC::RequestParser rp{ctx}; 844 IPC::RequestParser rp{ctx};
847 const auto can_vibrate{rp.Pop<bool>()}; 845 const auto can_vibrate{rp.Pop<bool>()};
848 applet_resource->GetController<Controller_NPad>(HidController::NPad) 846 Settings::values.vibration_enabled = can_vibrate;
849 .SetVibrationEnabled(can_vibrate);
850 847
851 LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate); 848 LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
852 849
@@ -859,8 +856,7 @@ void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) {
859 856
860 IPC::ResponseBuilder rb{ctx, 3}; 857 IPC::ResponseBuilder rb{ctx, 3};
861 rb.Push(RESULT_SUCCESS); 858 rb.Push(RESULT_SUCCESS);
862 rb.Push( 859 rb.Push(Settings::values.vibration_enabled);
863 applet_resource->GetController<Controller_NPad>(HidController::NPad).IsVibrationEnabled());
864} 860}
865 861
866void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 862void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index d328fb8b7..28d3f9099 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -13,56 +13,6 @@
13 13
14namespace Settings { 14namespace Settings {
15 15
16namespace NativeButton {
17const std::array<const char*, NumButtons> mapping = {{
18 "button_a",
19 "button_b",
20 "button_x",
21 "button_y",
22 "button_lstick",
23 "button_rstick",
24 "button_l",
25 "button_r",
26 "button_zl",
27 "button_zr",
28 "button_plus",
29 "button_minus",
30 "button_dleft",
31 "button_dup",
32 "button_dright",
33 "button_ddown",
34 "button_lstick_left",
35 "button_lstick_up",
36 "button_lstick_right",
37 "button_lstick_down",
38 "button_rstick_left",
39 "button_rstick_up",
40 "button_rstick_right",
41 "button_rstick_down",
42 "button_sl",
43 "button_sr",
44 "button_home",
45 "button_screenshot",
46}};
47}
48
49namespace NativeAnalog {
50const std::array<const char*, NumAnalogs> mapping = {{
51 "lstick",
52 "rstick",
53}};
54}
55
56namespace NativeMouseButton {
57const std::array<const char*, NumMouseButtons> mapping = {{
58 "left",
59 "right",
60 "middle",
61 "forward",
62 "back",
63}};
64}
65
66Values values = {}; 16Values values = {};
67bool configuring_global = true; 17bool configuring_global = true;
68 18
diff --git a/src/core/settings.h b/src/core/settings.h
index 3681b5e9d..732c6a894 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -12,340 +12,10 @@
12#include <string> 12#include <string>
13#include <vector> 13#include <vector>
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "input_common/settings.h"
15 16
16namespace Settings { 17namespace Settings {
17 18
18namespace NativeButton {
19enum Values {
20 A,
21 B,
22 X,
23 Y,
24 LStick,
25 RStick,
26 L,
27 R,
28 ZL,
29 ZR,
30 Plus,
31 Minus,
32
33 DLeft,
34 DUp,
35 DRight,
36 DDown,
37
38 LStick_Left,
39 LStick_Up,
40 LStick_Right,
41 LStick_Down,
42
43 RStick_Left,
44 RStick_Up,
45 RStick_Right,
46 RStick_Down,
47
48 SL,
49 SR,
50
51 Home,
52 Screenshot,
53
54 NumButtons,
55};
56
57constexpr int BUTTON_HID_BEGIN = A;
58constexpr int BUTTON_NS_BEGIN = Home;
59
60constexpr int BUTTON_HID_END = BUTTON_NS_BEGIN;
61constexpr int BUTTON_NS_END = NumButtons;
62
63constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN;
64constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN;
65
66extern const std::array<const char*, NumButtons> mapping;
67
68} // namespace NativeButton
69
70namespace NativeAnalog {
71enum Values {
72 LStick,
73 RStick,
74
75 NumAnalogs,
76};
77
78constexpr int STICK_HID_BEGIN = LStick;
79constexpr int STICK_HID_END = NumAnalogs;
80constexpr int NUM_STICKS_HID = NumAnalogs;
81
82extern const std::array<const char*, NumAnalogs> mapping;
83} // namespace NativeAnalog
84
85namespace NativeMouseButton {
86enum Values {
87 Left,
88 Right,
89 Middle,
90 Forward,
91 Back,
92
93 NumMouseButtons,
94};
95
96constexpr int MOUSE_HID_BEGIN = Left;
97constexpr int MOUSE_HID_END = NumMouseButtons;
98constexpr int NUM_MOUSE_HID = NumMouseButtons;
99
100extern const std::array<const char*, NumMouseButtons> mapping;
101} // namespace NativeMouseButton
102
103namespace NativeKeyboard {
104enum Keys {
105 None,
106 Error,
107
108 A = 4,
109 B,
110 C,
111 D,
112 E,
113 F,
114 G,
115 H,
116 I,
117 J,
118 K,
119 L,
120 M,
121 N,
122 O,
123 P,
124 Q,
125 R,
126 S,
127 T,
128 U,
129 V,
130 W,
131 X,
132 Y,
133 Z,
134 N1,
135 N2,
136 N3,
137 N4,
138 N5,
139 N6,
140 N7,
141 N8,
142 N9,
143 N0,
144 Enter,
145 Escape,
146 Backspace,
147 Tab,
148 Space,
149 Minus,
150 Equal,
151 LeftBrace,
152 RightBrace,
153 Backslash,
154 Tilde,
155 Semicolon,
156 Apostrophe,
157 Grave,
158 Comma,
159 Dot,
160 Slash,
161 CapsLockKey,
162
163 F1,
164 F2,
165 F3,
166 F4,
167 F5,
168 F6,
169 F7,
170 F8,
171 F9,
172 F10,
173 F11,
174 F12,
175
176 SystemRequest,
177 ScrollLockKey,
178 Pause,
179 Insert,
180 Home,
181 PageUp,
182 Delete,
183 End,
184 PageDown,
185 Right,
186 Left,
187 Down,
188 Up,
189
190 NumLockKey,
191 KPSlash,
192 KPAsterisk,
193 KPMinus,
194 KPPlus,
195 KPEnter,
196 KP1,
197 KP2,
198 KP3,
199 KP4,
200 KP5,
201 KP6,
202 KP7,
203 KP8,
204 KP9,
205 KP0,
206 KPDot,
207
208 Key102,
209 Compose,
210 Power,
211 KPEqual,
212
213 F13,
214 F14,
215 F15,
216 F16,
217 F17,
218 F18,
219 F19,
220 F20,
221 F21,
222 F22,
223 F23,
224 F24,
225
226 Open,
227 Help,
228 Properties,
229 Front,
230 Stop,
231 Repeat,
232 Undo,
233 Cut,
234 Copy,
235 Paste,
236 Find,
237 Mute,
238 VolumeUp,
239 VolumeDown,
240 CapsLockActive,
241 NumLockActive,
242 ScrollLockActive,
243 KPComma,
244
245 KPLeftParenthesis,
246 KPRightParenthesis,
247
248 LeftControlKey = 0xE0,
249 LeftShiftKey,
250 LeftAltKey,
251 LeftMetaKey,
252 RightControlKey,
253 RightShiftKey,
254 RightAltKey,
255 RightMetaKey,
256
257 MediaPlayPause,
258 MediaStopCD,
259 MediaPrevious,
260 MediaNext,
261 MediaEject,
262 MediaVolumeUp,
263 MediaVolumeDown,
264 MediaMute,
265 MediaWebsite,
266 MediaBack,
267 MediaForward,
268 MediaStop,
269 MediaFind,
270 MediaScrollUp,
271 MediaScrollDown,
272 MediaEdit,
273 MediaSleep,
274 MediaCoffee,
275 MediaRefresh,
276 MediaCalculator,
277
278 NumKeyboardKeys,
279};
280
281static_assert(NumKeyboardKeys == 0xFC, "Incorrect number of keyboard keys.");
282
283enum Modifiers {
284 LeftControl,
285 LeftShift,
286 LeftAlt,
287 LeftMeta,
288 RightControl,
289 RightShift,
290 RightAlt,
291 RightMeta,
292 CapsLock,
293 ScrollLock,
294 NumLock,
295
296 NumKeyboardMods,
297};
298
299constexpr int KEYBOARD_KEYS_HID_BEGIN = None;
300constexpr int KEYBOARD_KEYS_HID_END = NumKeyboardKeys;
301constexpr int NUM_KEYBOARD_KEYS_HID = NumKeyboardKeys;
302
303constexpr int KEYBOARD_MODS_HID_BEGIN = LeftControl;
304constexpr int KEYBOARD_MODS_HID_END = NumKeyboardMods;
305constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;
306
307} // namespace NativeKeyboard
308
309using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
310using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;
311using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>;
312using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>;
313using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;
314
315constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
316constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
317constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
318constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
319
320enum class ControllerType {
321 ProController,
322 DualJoycon,
323 RightJoycon,
324 LeftJoycon,
325};
326
327struct PlayerInput {
328 bool connected;
329 ControllerType type;
330 ButtonsRaw buttons;
331 AnalogsRaw analogs;
332
333 u32 body_color_right;
334 u32 button_color_right;
335 u32 body_color_left;
336 u32 button_color_left;
337};
338
339struct TouchscreenInput {
340 bool enabled;
341 std::string device;
342
343 u32 finger;
344 u32 diameter_x;
345 u32 diameter_y;
346 u32 rotation_angle;
347};
348
349enum class RendererBackend { 19enum class RendererBackend {
350 OpenGL = 0, 20 OpenGL = 0,
351 Vulkan = 1, 21 Vulkan = 1,
@@ -461,6 +131,8 @@ struct Values {
461 // Controls 131 // Controls
462 std::array<PlayerInput, 10> players; 132 std::array<PlayerInput, 10> players;
463 133
134 bool use_docked_mode;
135
464 bool mouse_enabled; 136 bool mouse_enabled;
465 std::string mouse_device; 137 std::string mouse_device;
466 MouseButtonsRaw mouse_buttons; 138 MouseButtonsRaw mouse_buttons;
@@ -474,14 +146,15 @@ struct Values {
474 AnalogsRaw debug_pad_analogs; 146 AnalogsRaw debug_pad_analogs;
475 147
476 std::string motion_device; 148 std::string motion_device;
149
150 bool vibration_enabled;
151
477 TouchscreenInput touchscreen; 152 TouchscreenInput touchscreen;
478 std::atomic_bool is_device_reload_pending{true}; 153 std::atomic_bool is_device_reload_pending{true};
479 std::string udp_input_address; 154 std::string udp_input_address;
480 u16 udp_input_port; 155 u16 udp_input_port;
481 u8 udp_pad_index; 156 u8 udp_pad_index;
482 157
483 bool use_docked_mode;
484
485 // Data Storage 158 // Data Storage
486 bool use_virtual_sd; 159 bool use_virtual_sd;
487 bool gamecard_inserted; 160 bool gamecard_inserted;
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index 317c25bad..56267c8a8 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -7,6 +7,8 @@ add_library(input_common STATIC
7 main.h 7 main.h
8 motion_emu.cpp 8 motion_emu.cpp
9 motion_emu.h 9 motion_emu.h
10 settings.cpp
11 settings.h
10 gcadapter/gc_adapter.cpp 12 gcadapter/gc_adapter.cpp
11 gcadapter/gc_adapter.h 13 gcadapter/gc_adapter.h
12 gcadapter/gc_poller.cpp 14 gcadapter/gc_poller.cpp
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp
index b346fdf8e..85342bbe7 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -232,7 +232,7 @@ std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::Param
232 const int port = params.Get("port", 0); 232 const int port = params.Get("port", 0);
233 const int axis_x = params.Get("axis_x", 0); 233 const int axis_x = params.Get("axis_x", 0);
234 const int axis_y = params.Get("axis_y", 1); 234 const int axis_y = params.Get("axis_y", 1);
235 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); 235 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
236 const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f); 236 const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
237 237
238 return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get(), range); 238 return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get(), range);
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index b9d5d0ec3..b8725e9af 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -44,7 +44,6 @@ void Init() {
44#ifdef HAVE_SDL2 44#ifdef HAVE_SDL2
45 sdl = SDL::Init(); 45 sdl = SDL::Init();
46#endif 46#endif
47
48 udp = CemuhookUDP::Init(); 47 udp = CemuhookUDP::Init();
49} 48}
50 49
@@ -103,6 +102,55 @@ std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left,
103 return circle_pad_param.Serialize(); 102 return circle_pad_param.Serialize();
104} 103}
105 104
105std::vector<Common::ParamPackage> GetInputDevices() {
106 std::vector<Common::ParamPackage> devices = {
107 Common::ParamPackage{{"display", "Any"}, {"class", "any"}},
108 Common::ParamPackage{{"display", "Keyboard"}, {"class", "key"}},
109 };
110#ifdef HAVE_SDL2
111 auto sdl_devices = sdl->GetInputDevices();
112 devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end());
113#endif
114 auto udp_devices = udp->GetInputDevices();
115 devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
116 return devices;
117}
118
119std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage> GetButtonMappingForDevice(
120 const Common::ParamPackage& params) {
121 std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage> mappings{};
122 if (!params.Has("class") || params.Get("class", "") == "any") {
123 return mappings;
124 }
125 if (params.Get("class", "") == "key") {
126 // TODO consider returning the SDL key codes for the default keybindings
127 }
128#ifdef HAVE_SDL2
129 if (params.Get("class", "") == "sdl") {
130 return sdl->GetButtonMappingForDevice(params);
131 }
132#endif
133 return mappings;
134}
135
136std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage> GetAnalogMappingForDevice(
137 const Common::ParamPackage& params) {
138 std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage> mappings{};
139 if (!params.Has("class") || params.Get("class", "") == "any") {
140 return mappings;
141 }
142 if (params.Get("class", "") == "key") {
143 // TODO consider returning the SDL key codes for the default keybindings
144 return mappings;
145 }
146#ifdef HAVE_SDL2
147 if (params.Get("class", "") == "sdl") {
148 return sdl->GetAnalogMappingForDevice(params);
149 }
150#endif
151 return mappings;
152}
153
106namespace Polling { 154namespace Polling {
107 155
108std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) { 156std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) {
diff --git a/src/input_common/main.h b/src/input_common/main.h
index 0e32856f6..ebc7f9533 100644
--- a/src/input_common/main.h
+++ b/src/input_common/main.h
@@ -6,8 +6,10 @@
6 6
7#include <memory> 7#include <memory>
8#include <string> 8#include <string>
9#include <unordered_map>
9#include <vector> 10#include <vector>
10#include "input_common/gcadapter/gc_poller.h" 11#include "input_common/gcadapter/gc_poller.h"
12#include "input_common/settings.h"
11 13
12namespace Common { 14namespace Common {
13class ParamPackage; 15class ParamPackage;
@@ -42,9 +44,27 @@ std::string GenerateKeyboardParam(int key_code);
42std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, 44std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
43 int key_modifier, float modifier_scale); 45 int key_modifier, float modifier_scale);
44 46
47/**
48 * Return a list of available input devices that this Factory can create a new device with.
49 * Each returned Parampackage should have a `display` field used for display, a class field for
50 * backends to determine if this backend is meant to service the request and any other information
51 * needed to identify this in the backend later.
52 */
53std::vector<Common::ParamPackage> GetInputDevices();
54
55/**
56 * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default
57 * mapping for the device. This is currently only implemented for the sdl backend devices.
58 */
59using ButtonMapping = std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage>;
60using AnalogMapping = std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage>;
61
62ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage&);
63AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&);
64
45namespace Polling { 65namespace Polling {
46 66
47enum class DeviceType { Button, Analog }; 67enum class DeviceType { Button, AnalogPreferred };
48 68
49/** 69/**
50 * A class that can be used to get inputs from an input device like controllers without having to 70 * A class that can be used to get inputs from an input device like controllers without having to
@@ -54,7 +74,9 @@ class DevicePoller {
54public: 74public:
55 virtual ~DevicePoller() = default; 75 virtual ~DevicePoller() = default;
56 /// Setup and start polling for inputs, should be called before GetNextInput 76 /// Setup and start polling for inputs, should be called before GetNextInput
57 virtual void Start() = 0; 77 /// If a device_id is provided, events should be filtered to only include events from this
78 /// device id
79 virtual void Start(std::string device_id = "") = 0;
58 /// Stop polling 80 /// Stop polling
59 virtual void Stop() = 0; 81 virtual void Stop() = 0;
60 /** 82 /**
diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h
index 5306daa70..f3554be9a 100644
--- a/src/input_common/sdl/sdl.h
+++ b/src/input_common/sdl/sdl.h
@@ -6,6 +6,7 @@
6 6
7#include <memory> 7#include <memory>
8#include <vector> 8#include <vector>
9#include "common/param_package.h"
9#include "input_common/main.h" 10#include "input_common/main.h"
10 11
11namespace InputCommon::Polling { 12namespace InputCommon::Polling {
@@ -22,14 +23,24 @@ public:
22 /// Unregisters SDL device factories and shut them down. 23 /// Unregisters SDL device factories and shut them down.
23 virtual ~State() = default; 24 virtual ~State() = default;
24 25
25 virtual Pollers GetPollers(Polling::DeviceType type) = 0; 26 virtual Pollers GetPollers(Polling::DeviceType type) {
27 return {};
28 }
29
30 virtual std::vector<Common::ParamPackage> GetInputDevices() {
31 return {};
32 }
33
34 virtual ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage&) {
35 return {};
36 }
37 virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) {
38 return {};
39 }
26}; 40};
27 41
28class NullState : public State { 42class NullState : public State {
29public: 43public:
30 Pollers GetPollers(Polling::DeviceType type) override {
31 return {};
32 }
33}; 44};
34 45
35std::unique_ptr<State> Init(); 46std::unique_ptr<State> Init();
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index d76c279d3..35a9d45ec 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -7,6 +7,8 @@
7#include <cmath> 7#include <cmath>
8#include <functional> 8#include <functional>
9#include <mutex> 9#include <mutex>
10#include <optional>
11#include <sstream>
10#include <string> 12#include <string>
11#include <thread> 13#include <thread>
12#include <tuple> 14#include <tuple>
@@ -23,7 +25,8 @@
23 25
24namespace InputCommon::SDL { 26namespace InputCommon::SDL {
25 27
26static std::string GetGUID(SDL_Joystick* joystick) { 28namespace {
29std::string GetGUID(SDL_Joystick* joystick) {
27 const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); 30 const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
28 char guid_str[33]; 31 char guid_str[33];
29 SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); 32 SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
@@ -31,7 +34,8 @@ static std::string GetGUID(SDL_Joystick* joystick) {
31} 34}
32 35
33/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice 36/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice
34static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event); 37Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event);
38} // Anonymous namespace
35 39
36static int SDLEventWatcher(void* user_data, SDL_Event* event) { 40static int SDLEventWatcher(void* user_data, SDL_Event* event) {
37 auto* const sdl_state = static_cast<SDLState*>(user_data); 41 auto* const sdl_state = static_cast<SDLState*>(user_data);
@@ -48,8 +52,10 @@ static int SDLEventWatcher(void* user_data, SDL_Event* event) {
48 52
49class SDLJoystick { 53class SDLJoystick {
50public: 54public:
51 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick) 55 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
52 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose} {} 56 SDL_GameController* gamecontroller)
57 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
58 sdl_controller{gamecontroller, &SDL_GameControllerClose} {}
53 59
54 void SetButton(int button, bool value) { 60 void SetButton(int button, bool value) {
55 std::lock_guard lock{mutex}; 61 std::lock_guard lock{mutex};
@@ -115,10 +121,15 @@ public:
115 return sdl_joystick.get(); 121 return sdl_joystick.get();
116 } 122 }
117 123
118 void SetSDLJoystick(SDL_Joystick* joystick) { 124 void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
125 sdl_controller.reset(controller);
119 sdl_joystick.reset(joystick); 126 sdl_joystick.reset(joystick);
120 } 127 }
121 128
129 SDL_GameController* GetSDLGameController() const {
130 return sdl_controller.get();
131 }
132
122private: 133private:
123 struct State { 134 struct State {
124 std::unordered_map<int, bool> buttons; 135 std::unordered_map<int, bool> buttons;
@@ -128,6 +139,7 @@ private:
128 std::string guid; 139 std::string guid;
129 int port; 140 int port;
130 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; 141 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
142 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
131 mutable std::mutex mutex; 143 mutable std::mutex mutex;
132}; 144};
133 145
@@ -136,18 +148,19 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& g
136 const auto it = joystick_map.find(guid); 148 const auto it = joystick_map.find(guid);
137 if (it != joystick_map.end()) { 149 if (it != joystick_map.end()) {
138 while (it->second.size() <= static_cast<std::size_t>(port)) { 150 while (it->second.size() <= static_cast<std::size_t>(port)) {
139 auto joystick = 151 auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
140 std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()), nullptr); 152 nullptr, nullptr);
141 it->second.emplace_back(std::move(joystick)); 153 it->second.emplace_back(std::move(joystick));
142 } 154 }
143 return it->second[port]; 155 return it->second[port];
144 } 156 }
145 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr); 157 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
146 return joystick_map[guid].emplace_back(std::move(joystick)); 158 return joystick_map[guid].emplace_back(std::move(joystick));
147} 159}
148 160
149std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { 161std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
150 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); 162 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
163 auto sdl_controller = SDL_GameControllerFromInstanceID(sdl_id);
151 const std::string guid = GetGUID(sdl_joystick); 164 const std::string guid = GetGUID(sdl_joystick);
152 165
153 std::lock_guard lock{joystick_map_mutex}; 166 std::lock_guard lock{joystick_map_mutex};
@@ -171,23 +184,27 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_
171 }); 184 });
172 if (nullptr_it != map_it->second.end()) { 185 if (nullptr_it != map_it->second.end()) {
173 // ... and map it 186 // ... and map it
174 (*nullptr_it)->SetSDLJoystick(sdl_joystick); 187 (*nullptr_it)->SetSDLJoystick(sdl_joystick, sdl_controller);
175 return *nullptr_it; 188 return *nullptr_it;
176 } 189 }
177 190
178 // There is no SDLJoystick without a mapped SDL_Joystick 191 // There is no SDLJoystick without a mapped SDL_Joystick
179 // Create a new SDLJoystick 192 // Create a new SDLJoystick
180 const int port = static_cast<int>(map_it->second.size()); 193 const int port = static_cast<int>(map_it->second.size());
181 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick); 194 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_controller);
182 return map_it->second.emplace_back(std::move(joystick)); 195 return map_it->second.emplace_back(std::move(joystick));
183 } 196 }
184 197
185 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); 198 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_controller);
186 return joystick_map[guid].emplace_back(std::move(joystick)); 199 return joystick_map[guid].emplace_back(std::move(joystick));
187} 200}
188 201
189void SDLState::InitJoystick(int joystick_index) { 202void SDLState::InitJoystick(int joystick_index) {
190 SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index); 203 SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
204 SDL_GameController* sdl_gamecontroller = nullptr;
205 if (SDL_IsGameController(joystick_index)) {
206 sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
207 }
191 if (!sdl_joystick) { 208 if (!sdl_joystick) {
192 LOG_ERROR(Input, "failed to open joystick {}", joystick_index); 209 LOG_ERROR(Input, "failed to open joystick {}", joystick_index);
193 return; 210 return;
@@ -196,7 +213,7 @@ void SDLState::InitJoystick(int joystick_index) {
196 213
197 std::lock_guard lock{joystick_map_mutex}; 214 std::lock_guard lock{joystick_map_mutex};
198 if (joystick_map.find(guid) == joystick_map.end()) { 215 if (joystick_map.find(guid) == joystick_map.end()) {
199 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); 216 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
200 joystick_map[guid].emplace_back(std::move(joystick)); 217 joystick_map[guid].emplace_back(std::move(joystick));
201 return; 218 return;
202 } 219 }
@@ -205,11 +222,11 @@ void SDLState::InitJoystick(int joystick_index) {
205 joystick_guid_list.begin(), joystick_guid_list.end(), 222 joystick_guid_list.begin(), joystick_guid_list.end(),
206 [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); }); 223 [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); });
207 if (it != joystick_guid_list.end()) { 224 if (it != joystick_guid_list.end()) {
208 (*it)->SetSDLJoystick(sdl_joystick); 225 (*it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
209 return; 226 return;
210 } 227 }
211 const int port = static_cast<int>(joystick_guid_list.size()); 228 const int port = static_cast<int>(joystick_guid_list.size());
212 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick); 229 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
213 joystick_guid_list.emplace_back(std::move(joystick)); 230 joystick_guid_list.emplace_back(std::move(joystick));
214} 231}
215 232
@@ -231,7 +248,7 @@ void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
231 248
232 // Destruct SDL_Joystick outside the lock guard because SDL can internally call the 249 // Destruct SDL_Joystick outside the lock guard because SDL can internally call the
233 // event callback which locks the mutex again. 250 // event callback which locks the mutex again.
234 joystick->SetSDLJoystick(nullptr); 251 joystick->SetSDLJoystick(nullptr, nullptr);
235} 252}
236 253
237void SDLState::HandleGameControllerEvent(const SDL_Event& event) { 254void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
@@ -460,7 +477,7 @@ public:
460 const int port = params.Get("port", 0); 477 const int port = params.Get("port", 0);
461 const int axis_x = params.Get("axis_x", 0); 478 const int axis_x = params.Get("axis_x", 0);
462 const int axis_y = params.Get("axis_y", 1); 479 const int axis_y = params.Get("axis_y", 1);
463 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); 480 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
464 const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f); 481 const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
465 auto joystick = state.GetSDLJoystickByGUID(guid, port); 482 auto joystick = state.GetSDLJoystickByGUID(guid, port);
466 483
@@ -476,8 +493,10 @@ private:
476 493
477SDLState::SDLState() { 494SDLState::SDLState() {
478 using namespace Input; 495 using namespace Input;
479 RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>(*this)); 496 analog_factory = std::make_shared<SDLAnalogFactory>(*this);
480 RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>(*this)); 497 button_factory = std::make_shared<SDLButtonFactory>(*this);
498 RegisterFactory<AnalogDevice>("sdl", analog_factory);
499 RegisterFactory<ButtonDevice>("sdl", button_factory);
481 500
482 // If the frontend is going to manage the event loop, then we dont start one here 501 // If the frontend is going to manage the event loop, then we dont start one here
483 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK); 502 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK);
@@ -485,6 +504,7 @@ SDLState::SDLState() {
485 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); 504 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
486 return; 505 return;
487 } 506 }
507 has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
488 if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) { 508 if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
489 LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError()); 509 LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
490 } 510 }
@@ -497,7 +517,7 @@ SDLState::SDLState() {
497 using namespace std::chrono_literals; 517 using namespace std::chrono_literals;
498 while (initialized) { 518 while (initialized) {
499 SDL_PumpEvents(); 519 SDL_PumpEvents();
500 std::this_thread::sleep_for(10ms); 520 std::this_thread::sleep_for(5ms);
501 } 521 }
502 }); 522 });
503 } 523 }
@@ -523,65 +543,233 @@ SDLState::~SDLState() {
523 } 543 }
524} 544}
525 545
526static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { 546std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
547 std::scoped_lock lock(joystick_map_mutex);
548 std::vector<Common::ParamPackage> devices = {};
549 for (const auto& [key, value] : joystick_map) {
550 for (const auto& joystick : value) {
551 auto controller = joystick->GetSDLGameController();
552 auto joy = joystick->GetSDLJoystick();
553 if (controller) {
554 std::string name =
555 fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
556 devices.emplace_back(Common::ParamPackage{
557 {"class", "sdl"},
558 {"display", name},
559 {"guid", joystick->GetGUID()},
560 {"port", std::to_string(joystick->GetPort())},
561 });
562 } else if (joy) {
563 std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort());
564 devices.emplace_back(Common::ParamPackage{
565 {"class", "sdl"},
566 {"display", name},
567 {"guid", joystick->GetGUID()},
568 {"port", std::to_string(joystick->GetPort())},
569 });
570 }
571 }
572 }
573 return devices;
574}
575
576namespace {
577Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, u8 axis,
578 float value = 0.1) {
579 Common::ParamPackage params({{"engine", "sdl"}});
580 params.Set("port", port);
581 params.Set("guid", guid);
582 params.Set("axis", axis);
583 if (value > 0) {
584 params.Set("direction", "+");
585 params.Set("threshold", "0.5");
586 } else {
587 params.Set("direction", "-");
588 params.Set("threshold", "-0.5");
589 }
590 return params;
591}
592
593Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, u8 button) {
594 Common::ParamPackage params({{"engine", "sdl"}});
595 params.Set("port", port);
596 params.Set("guid", guid);
597 params.Set("button", button);
598 return params;
599}
600
601Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, u8 hat, u8 value) {
527 Common::ParamPackage params({{"engine", "sdl"}}); 602 Common::ParamPackage params({{"engine", "sdl"}});
528 603
604 params.Set("port", port);
605 params.Set("guid", guid);
606 params.Set("hat", hat);
607 switch (value) {
608 case SDL_HAT_UP:
609 params.Set("direction", "up");
610 break;
611 case SDL_HAT_DOWN:
612 params.Set("direction", "down");
613 break;
614 case SDL_HAT_LEFT:
615 params.Set("direction", "left");
616 break;
617 case SDL_HAT_RIGHT:
618 params.Set("direction", "right");
619 break;
620 default:
621 return {};
622 }
623 return params;
624}
625
626Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
627 Common::ParamPackage params{};
628
529 switch (event.type) { 629 switch (event.type) {
530 case SDL_JOYAXISMOTION: { 630 case SDL_JOYAXISMOTION: {
531 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 631 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
532 params.Set("port", joystick->GetPort()); 632 params = BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
533 params.Set("guid", joystick->GetGUID()); 633 event.jaxis.axis, event.jaxis.value);
534 params.Set("axis", event.jaxis.axis);
535 if (event.jaxis.value > 0) {
536 params.Set("direction", "+");
537 params.Set("threshold", "0.5");
538 } else {
539 params.Set("direction", "-");
540 params.Set("threshold", "-0.5");
541 }
542 break; 634 break;
543 } 635 }
544 case SDL_JOYBUTTONUP: { 636 case SDL_JOYBUTTONUP: {
545 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); 637 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
546 params.Set("port", joystick->GetPort()); 638 params = BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
547 params.Set("guid", joystick->GetGUID()); 639 event.jbutton.button);
548 params.Set("button", event.jbutton.button);
549 break; 640 break;
550 } 641 }
551 case SDL_JOYHATMOTION: { 642 case SDL_JOYHATMOTION: {
552 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); 643 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
553 params.Set("port", joystick->GetPort()); 644 params = BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
554 params.Set("guid", joystick->GetGUID()); 645 event.jhat.hat, event.jhat.value);
555 params.Set("hat", event.jhat.hat);
556 switch (event.jhat.value) {
557 case SDL_HAT_UP:
558 params.Set("direction", "up");
559 break;
560 case SDL_HAT_DOWN:
561 params.Set("direction", "down");
562 break;
563 case SDL_HAT_LEFT:
564 params.Set("direction", "left");
565 break;
566 case SDL_HAT_RIGHT:
567 params.Set("direction", "right");
568 break;
569 default:
570 return {};
571 }
572 break; 646 break;
573 } 647 }
574 } 648 }
575 return params; 649 return params;
576} 650}
577 651
578namespace Polling { 652Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
653 const SDL_GameControllerButtonBind& binding) {
654 Common::ParamPackage out{};
655 switch (binding.bindType) {
656 case SDL_CONTROLLER_BINDTYPE_AXIS:
657 out = BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
658 break;
659 case SDL_CONTROLLER_BINDTYPE_BUTTON:
660 out = BuildButtonParamPackageForButton(port, guid, binding.value.button);
661 break;
662 case SDL_CONTROLLER_BINDTYPE_HAT:
663 out = BuildHatParamPackageForButton(port, guid, binding.value.hat.hat,
664 binding.value.hat.hat_mask);
665 break;
666 default:
667 break;
668 }
669 return out;
670};
671
672Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x,
673 int axis_y) {
674 Common::ParamPackage params{};
675 params.Set("engine", "sdl");
676 params.Set("port", port);
677 params.Set("guid", guid);
678 params.Set("axis_x", axis_x);
679 params.Set("axis_y", axis_y);
680 return params;
681}
682} // Anonymous namespace
683
684ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) {
685 // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
686 // We will add those afterwards
687 // This list also excludes Screenshot since theres not really a mapping for that
688 std::unordered_map<Settings::NativeButton::Values, SDL_GameControllerButton>
689 switch_to_sdl_button = {
690 {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
691 {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
692 {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
693 {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
694 {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
695 {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
696 {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
697 {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
698 {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
699 {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
700 {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
701 {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
702 {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
703 {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
704 {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
705 {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
706 {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
707 };
708 if (!params.Has("guid") || !params.Has("port")) {
709 return {};
710 }
711 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
712 auto controller = joystick->GetSDLGameController();
713 if (!controller) {
714 return {};
715 }
716
717 ButtonMapping mapping{};
718 for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
719 const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
720 mapping[switch_button] =
721 BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding);
722 }
723
724 // Add the missing bindings for ZL/ZR
725 std::unordered_map<Settings::NativeButton::Values, SDL_GameControllerAxis> switch_to_sdl_axis =
726 {
727 {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
728 {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
729 };
730 for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
731 const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
732 mapping[switch_button] =
733 BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding);
734 }
735
736 return mapping;
737}
738
739AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
740 if (!params.Has("guid") || !params.Has("port")) {
741 return {};
742 }
743 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
744 auto controller = joystick->GetSDLGameController();
745 if (!controller) {
746 return {};
747 }
748
749 AnalogMapping mapping = {};
750 const auto& binding_left_x =
751 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
752 const auto& binding_left_y =
753 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
754 mapping[Settings::NativeAnalog::LStick] =
755 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
756 binding_left_x.value.axis, binding_left_y.value.axis);
757 const auto& binding_right_x =
758 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
759 const auto& binding_right_y =
760 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
761 mapping[Settings::NativeAnalog::RStick] =
762 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
763 binding_right_x.value.axis, binding_right_y.value.axis);
764 return mapping;
765}
579 766
767namespace Polling {
580class SDLPoller : public InputCommon::Polling::DevicePoller { 768class SDLPoller : public InputCommon::Polling::DevicePoller {
581public: 769public:
582 explicit SDLPoller(SDLState& state_) : state(state_) {} 770 explicit SDLPoller(SDLState& state_) : state(state_) {}
583 771
584 void Start() override { 772 void Start(std::string device_id) override {
585 state.event_queue.Clear(); 773 state.event_queue.Clear();
586 state.polling = true; 774 state.polling = true;
587 } 775 }
@@ -601,71 +789,106 @@ public:
601 Common::ParamPackage GetNextInput() override { 789 Common::ParamPackage GetNextInput() override {
602 SDL_Event event; 790 SDL_Event event;
603 while (state.event_queue.Pop(event)) { 791 while (state.event_queue.Pop(event)) {
604 switch (event.type) { 792 const auto package = FromEvent(event);
605 case SDL_JOYAXISMOTION: 793 if (package) {
606 if (std::abs(event.jaxis.value / 32767.0) < 0.5) { 794 return *package;
607 break;
608 }
609 [[fallthrough]];
610 case SDL_JOYBUTTONUP:
611 case SDL_JOYHATMOTION:
612 return SDLEventToButtonParamPackage(state, event);
613 } 795 }
614 } 796 }
615 return {}; 797 return {};
616 } 798 }
799 std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) {
800 switch (event.type) {
801 case SDL_JOYAXISMOTION:
802 if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
803 break;
804 }
805 [[fallthrough]];
806 case SDL_JOYBUTTONUP:
807 case SDL_JOYHATMOTION:
808 return {SDLEventToButtonParamPackage(state, event)};
809 }
810 return {};
811 }
617}; 812};
618 813
619class SDLAnalogPoller final : public SDLPoller { 814/**
815 * Attempts to match the press to a controller joy axis (left/right stick) and if a match
816 * isn't found, checks if the event matches anything from SDLButtonPoller and uses that
817 * instead
818 */
819class SDLAnalogPreferredPoller final : public SDLPoller {
620public: 820public:
621 explicit SDLAnalogPoller(SDLState& state_) : SDLPoller(state_) {} 821 explicit SDLAnalogPreferredPoller(SDLState& state_)
622 822 : SDLPoller(state_), button_poller(state_) {}
623 void Start() override {
624 SDLPoller::Start();
625 823
824 void Start(std::string device_id) override {
825 SDLPoller::Start(device_id);
826 // Load the game controller
626 // Reset stored axes 827 // Reset stored axes
627 analog_x_axis = -1; 828 analog_x_axis = -1;
628 analog_y_axis = -1; 829 analog_y_axis = -1;
629 analog_axes_joystick = -1;
630 } 830 }
631 831
632 Common::ParamPackage GetNextInput() override { 832 Common::ParamPackage GetNextInput() override {
633 SDL_Event event; 833 SDL_Event event;
634 while (state.event_queue.Pop(event)) { 834 while (state.event_queue.Pop(event)) {
635 if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) { 835 // Filter out axis events that are below a threshold
836 if (event.type == SDL_JOYAXISMOTION && std::abs(event.jaxis.value / 32767.0) < 0.5) {
636 continue; 837 continue;
637 } 838 }
638 // An analog device needs two axes, so we need to store the axis for later and wait for 839 // Simplify controller config by testing if game controller support is enabled.
639 // a second SDL event. The axes also must be from the same joystick. 840 if (event.type == SDL_JOYAXISMOTION) {
640 const int axis = event.jaxis.axis; 841 const auto axis = event.jaxis.axis;
641 if (analog_x_axis == -1) { 842 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
642 analog_x_axis = axis; 843 const auto controller = joystick->GetSDLGameController();
643 analog_axes_joystick = event.jaxis.which; 844 if (controller) {
644 } else if (analog_y_axis == -1 && analog_x_axis != axis && 845 const auto axis_left_x =
645 analog_axes_joystick == event.jaxis.which) { 846 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)
646 analog_y_axis = axis; 847 .value.axis;
848 const auto axis_left_y =
849 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY)
850 .value.axis;
851 const auto axis_right_x =
852 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX)
853 .value.axis;
854 const auto axis_right_y =
855 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY)
856 .value.axis;
857
858 if (axis == axis_left_x || axis == axis_left_y) {
859 analog_x_axis = axis_left_x;
860 analog_y_axis = axis_left_y;
861 break;
862 } else if (axis == axis_right_x || axis == axis_right_y) {
863 analog_x_axis = axis_right_x;
864 analog_y_axis = axis_right_y;
865 break;
866 }
867 }
868 }
869
870 // If the press wasn't accepted as a joy axis, check for a button press
871 auto button_press = button_poller.FromEvent(event);
872 if (button_press) {
873 return *button_press;
647 } 874 }
648 } 875 }
649 Common::ParamPackage params; 876
650 if (analog_x_axis != -1 && analog_y_axis != -1) { 877 if (analog_x_axis != -1 && analog_y_axis != -1) {
651 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 878 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
652 params.Set("engine", "sdl"); 879 auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
653 params.Set("port", joystick->GetPort()); 880 analog_x_axis, analog_y_axis);
654 params.Set("guid", joystick->GetGUID());
655 params.Set("axis_x", analog_x_axis);
656 params.Set("axis_y", analog_y_axis);
657 analog_x_axis = -1; 881 analog_x_axis = -1;
658 analog_y_axis = -1; 882 analog_y_axis = -1;
659 analog_axes_joystick = -1;
660 return params; 883 return params;
661 } 884 }
662 return params; 885 return {};
663 } 886 }
664 887
665private: 888private:
666 int analog_x_axis = -1; 889 int analog_x_axis = -1;
667 int analog_y_axis = -1; 890 int analog_y_axis = -1;
668 SDL_JoystickID analog_axes_joystick = -1; 891 SDLButtonPoller button_poller;
669}; 892};
670} // namespace Polling 893} // namespace Polling
671 894
@@ -673,8 +896,8 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
673 Pollers pollers; 896 Pollers pollers;
674 897
675 switch (type) { 898 switch (type) {
676 case InputCommon::Polling::DeviceType::Analog: 899 case InputCommon::Polling::DeviceType::AnalogPreferred:
677 pollers.emplace_back(std::make_unique<Polling::SDLAnalogPoller>(*this)); 900 pollers.emplace_back(std::make_unique<Polling::SDLAnalogPreferredPoller>(*this));
678 break; 901 break;
679 case InputCommon::Polling::DeviceType::Button: 902 case InputCommon::Polling::DeviceType::Button:
680 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this)); 903 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h
index 606a32c5b..bd19ba61d 100644
--- a/src/input_common/sdl/sdl_impl.h
+++ b/src/input_common/sdl/sdl_impl.h
@@ -50,6 +50,11 @@ public:
50 std::atomic<bool> polling = false; 50 std::atomic<bool> polling = false;
51 Common::SPSCQueue<SDL_Event> event_queue; 51 Common::SPSCQueue<SDL_Event> event_queue;
52 52
53 std::vector<Common::ParamPackage> GetInputDevices() override;
54
55 ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;
56 AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override;
57
53private: 58private:
54 void InitJoystick(int joystick_index); 59 void InitJoystick(int joystick_index);
55 void CloseJoystick(SDL_Joystick* sdl_joystick); 60 void CloseJoystick(SDL_Joystick* sdl_joystick);
@@ -57,6 +62,9 @@ private:
57 /// Needs to be called before SDL_QuitSubSystem. 62 /// Needs to be called before SDL_QuitSubSystem.
58 void CloseJoysticks(); 63 void CloseJoysticks();
59 64
65 // Set to true if SDL supports game controller subsystem
66 bool has_gamecontroller = false;
67
60 /// Map of GUID of a list of corresponding virtual Joysticks 68 /// Map of GUID of a list of corresponding virtual Joysticks
61 std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map; 69 std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
62 std::mutex joystick_map_mutex; 70 std::mutex joystick_map_mutex;
diff --git a/src/input_common/settings.cpp b/src/input_common/settings.cpp
new file mode 100644
index 000000000..80c719cf4
--- /dev/null
+++ b/src/input_common/settings.cpp
@@ -0,0 +1,33 @@
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 "input_common/settings.h"
6
7namespace Settings {
8namespace NativeButton {
9const std::array<const char*, NumButtons> mapping = {{
10 "button_a", "button_b", "button_x", "button_y", "button_lstick",
11 "button_rstick", "button_l", "button_r", "button_zl", "button_zr",
12 "button_plus", "button_minus", "button_dleft", "button_dup", "button_dright",
13 "button_ddown", "button_sl", "button_sr", "button_home", "button_screenshot",
14}};
15}
16
17namespace NativeAnalog {
18const std::array<const char*, NumAnalogs> mapping = {{
19 "lstick",
20 "rstick",
21}};
22}
23
24namespace NativeMouseButton {
25const std::array<const char*, NumMouseButtons> mapping = {{
26 "left",
27 "right",
28 "middle",
29 "forward",
30 "back",
31}};
32}
33} // namespace Settings
diff --git a/src/input_common/settings.h b/src/input_common/settings.h
new file mode 100644
index 000000000..8e481a7fe
--- /dev/null
+++ b/src/input_common/settings.h
@@ -0,0 +1,335 @@
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 <string>
9#include "common/common_types.h"
10
11namespace Settings {
12namespace NativeButton {
13enum Values {
14 A,
15 B,
16 X,
17 Y,
18 LStick,
19 RStick,
20 L,
21 R,
22 ZL,
23 ZR,
24 Plus,
25 Minus,
26
27 DLeft,
28 DUp,
29 DRight,
30 DDown,
31
32 SL,
33 SR,
34
35 Home,
36 Screenshot,
37
38 NumButtons,
39};
40
41constexpr int BUTTON_HID_BEGIN = A;
42constexpr int BUTTON_NS_BEGIN = Home;
43
44constexpr int BUTTON_HID_END = BUTTON_NS_BEGIN;
45constexpr int BUTTON_NS_END = NumButtons;
46
47constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN;
48constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN;
49
50extern const std::array<const char*, NumButtons> mapping;
51
52} // namespace NativeButton
53
54namespace NativeAnalog {
55enum Values {
56 LStick,
57 RStick,
58
59 NumAnalogs,
60};
61
62constexpr int STICK_HID_BEGIN = LStick;
63constexpr int STICK_HID_END = NumAnalogs;
64constexpr int NUM_STICKS_HID = NumAnalogs;
65
66extern const std::array<const char*, NumAnalogs> mapping;
67} // namespace NativeAnalog
68
69namespace NativeMouseButton {
70enum Values {
71 Left,
72 Right,
73 Middle,
74 Forward,
75 Back,
76
77 NumMouseButtons,
78};
79
80constexpr int MOUSE_HID_BEGIN = Left;
81constexpr int MOUSE_HID_END = NumMouseButtons;
82constexpr int NUM_MOUSE_HID = NumMouseButtons;
83
84extern const std::array<const char*, NumMouseButtons> mapping;
85} // namespace NativeMouseButton
86
87namespace NativeKeyboard {
88enum Keys {
89 None,
90 Error,
91
92 A = 4,
93 B,
94 C,
95 D,
96 E,
97 F,
98 G,
99 H,
100 I,
101 J,
102 K,
103 L,
104 M,
105 N,
106 O,
107 P,
108 Q,
109 R,
110 S,
111 T,
112 U,
113 V,
114 W,
115 X,
116 Y,
117 Z,
118 N1,
119 N2,
120 N3,
121 N4,
122 N5,
123 N6,
124 N7,
125 N8,
126 N9,
127 N0,
128 Enter,
129 Escape,
130 Backspace,
131 Tab,
132 Space,
133 Minus,
134 Equal,
135 LeftBrace,
136 RightBrace,
137 Backslash,
138 Tilde,
139 Semicolon,
140 Apostrophe,
141 Grave,
142 Comma,
143 Dot,
144 Slash,
145 CapsLockKey,
146
147 F1,
148 F2,
149 F3,
150 F4,
151 F5,
152 F6,
153 F7,
154 F8,
155 F9,
156 F10,
157 F11,
158 F12,
159
160 SystemRequest,
161 ScrollLockKey,
162 Pause,
163 Insert,
164 Home,
165 PageUp,
166 Delete,
167 End,
168 PageDown,
169 Right,
170 Left,
171 Down,
172 Up,
173
174 NumLockKey,
175 KPSlash,
176 KPAsterisk,
177 KPMinus,
178 KPPlus,
179 KPEnter,
180 KP1,
181 KP2,
182 KP3,
183 KP4,
184 KP5,
185 KP6,
186 KP7,
187 KP8,
188 KP9,
189 KP0,
190 KPDot,
191
192 Key102,
193 Compose,
194 Power,
195 KPEqual,
196
197 F13,
198 F14,
199 F15,
200 F16,
201 F17,
202 F18,
203 F19,
204 F20,
205 F21,
206 F22,
207 F23,
208 F24,
209
210 Open,
211 Help,
212 Properties,
213 Front,
214 Stop,
215 Repeat,
216 Undo,
217 Cut,
218 Copy,
219 Paste,
220 Find,
221 Mute,
222 VolumeUp,
223 VolumeDown,
224 CapsLockActive,
225 NumLockActive,
226 ScrollLockActive,
227 KPComma,
228
229 KPLeftParenthesis,
230 KPRightParenthesis,
231
232 LeftControlKey = 0xE0,
233 LeftShiftKey,
234 LeftAltKey,
235 LeftMetaKey,
236 RightControlKey,
237 RightShiftKey,
238 RightAltKey,
239 RightMetaKey,
240
241 MediaPlayPause,
242 MediaStopCD,
243 MediaPrevious,
244 MediaNext,
245 MediaEject,
246 MediaVolumeUp,
247 MediaVolumeDown,
248 MediaMute,
249 MediaWebsite,
250 MediaBack,
251 MediaForward,
252 MediaStop,
253 MediaFind,
254 MediaScrollUp,
255 MediaScrollDown,
256 MediaEdit,
257 MediaSleep,
258 MediaCoffee,
259 MediaRefresh,
260 MediaCalculator,
261
262 NumKeyboardKeys,
263};
264
265static_assert(NumKeyboardKeys == 0xFC, "Incorrect number of keyboard keys.");
266
267enum Modifiers {
268 LeftControl,
269 LeftShift,
270 LeftAlt,
271 LeftMeta,
272 RightControl,
273 RightShift,
274 RightAlt,
275 RightMeta,
276 CapsLock,
277 ScrollLock,
278 NumLock,
279
280 NumKeyboardMods,
281};
282
283constexpr int KEYBOARD_KEYS_HID_BEGIN = None;
284constexpr int KEYBOARD_KEYS_HID_END = NumKeyboardKeys;
285constexpr int NUM_KEYBOARD_KEYS_HID = NumKeyboardKeys;
286
287constexpr int KEYBOARD_MODS_HID_BEGIN = LeftControl;
288constexpr int KEYBOARD_MODS_HID_END = NumKeyboardMods;
289constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;
290
291} // namespace NativeKeyboard
292
293using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
294using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;
295using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>;
296using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>;
297using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;
298
299constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
300constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
301constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
302constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
303
304enum class ControllerType {
305 ProController,
306 DualJoyconDetached,
307 LeftJoycon,
308 RightJoycon,
309 Handheld,
310};
311
312struct PlayerInput {
313 bool connected;
314 ControllerType controller_type;
315 ButtonsRaw buttons;
316 AnalogsRaw analogs;
317 std::string lstick_mod;
318 std::string rstick_mod;
319
320 u32 body_color_left;
321 u32 body_color_right;
322 u32 button_color_left;
323 u32 button_color_right;
324};
325
326struct TouchscreenInput {
327 bool enabled;
328 std::string device;
329
330 u32 finger;
331 u32 diameter_x;
332 u32 diameter_y;
333 u32 rotation_angle;
334};
335} // namespace Settings
diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp
index 8c6ef1394..60cf47123 100644
--- a/src/input_common/udp/udp.cpp
+++ b/src/input_common/udp/udp.cpp
@@ -77,10 +77,11 @@ State::State() {
77 std::make_unique<Client>(status, Settings::values.udp_input_address, 77 std::make_unique<Client>(status, Settings::values.udp_input_address,
78 Settings::values.udp_input_port, Settings::values.udp_pad_index); 78 Settings::values.udp_input_port, Settings::values.udp_pad_index);
79 79
80 Input::RegisterFactory<Input::TouchDevice>("cemuhookudp", 80 motion_factory = std::make_shared<UDPMotionFactory>(status);
81 std::make_shared<UDPTouchFactory>(status)); 81 touch_factory = std::make_shared<UDPTouchFactory>(status);
82 Input::RegisterFactory<Input::MotionDevice>("cemuhookudp", 82
83 std::make_shared<UDPMotionFactory>(status)); 83 Input::RegisterFactory<Input::MotionDevice>("cemuhookudp", motion_factory);
84 Input::RegisterFactory<Input::TouchDevice>("cemuhookudp", touch_factory);
84} 85}
85 86
86State::~State() { 87State::~State() {
@@ -88,6 +89,12 @@ State::~State() {
88 Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp"); 89 Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp");
89} 90}
90 91
92std::vector<Common::ParamPackage> State::GetInputDevices() {
93 std::vector<Common::ParamPackage> devices = {};
94 // TODO support binding udp devices
95 return devices;
96}
97
91void State::ReloadUDPClient() { 98void State::ReloadUDPClient() {
92 client->ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port, 99 client->ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port,
93 Settings::values.udp_pad_index); 100 Settings::values.udp_pad_index);
diff --git a/src/input_common/udp/udp.h b/src/input_common/udp/udp.h
index 4f83f0441..24f6e0857 100644
--- a/src/input_common/udp/udp.h
+++ b/src/input_common/udp/udp.h
@@ -5,19 +5,26 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <vector>
9#include "common/param_package.h"
8 10
9namespace InputCommon::CemuhookUDP { 11namespace InputCommon::CemuhookUDP {
10 12
11class Client; 13class Client;
14class UDPMotionFactory;
15class UDPTouchFactory;
12 16
13class State { 17class State {
14public: 18public:
15 State(); 19 State();
16 ~State(); 20 ~State();
17 void ReloadUDPClient(); 21 void ReloadUDPClient();
22 std::vector<Common::ParamPackage> GetInputDevices();
18 23
19private: 24private:
20 std::unique_ptr<Client> client; 25 std::unique_ptr<Client> client;
26 std::shared_ptr<UDPMotionFactory> motion_factory;
27 std::shared_ptr<UDPTouchFactory> touch_factory;
21}; 28};
22 29
23std::unique_ptr<State> Init(); 30std::unique_ptr<State> Init();
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 656096c9f..6987e85e1 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -39,6 +39,9 @@ add_executable(yuzu
39 configuration/configure_debug.cpp 39 configuration/configure_debug.cpp
40 configuration/configure_debug.h 40 configuration/configure_debug.h
41 configuration/configure_debug.ui 41 configuration/configure_debug.ui
42 configuration/configure_debug_controller.cpp
43 configuration/configure_debug_controller.h
44 configuration/configure_debug_controller.ui
42 configuration/configure_dialog.cpp 45 configuration/configure_dialog.cpp
43 configuration/configure_dialog.h 46 configuration/configure_dialog.h
44 configuration/configure_filesystem.cpp 47 configuration/configure_filesystem.cpp
@@ -62,9 +65,9 @@ add_executable(yuzu
62 configuration/configure_input_player.cpp 65 configuration/configure_input_player.cpp
63 configuration/configure_input_player.h 66 configuration/configure_input_player.h
64 configuration/configure_input_player.ui 67 configuration/configure_input_player.ui
65 configuration/configure_input_simple.cpp 68 configuration/configure_input_advanced.cpp
66 configuration/configure_input_simple.h 69 configuration/configure_input_advanced.h
67 configuration/configure_input_simple.ui 70 configuration/configure_input_advanced.ui
68 configuration/configure_mouse_advanced.cpp 71 configuration/configure_mouse_advanced.cpp
69 configuration/configure_mouse_advanced.h 72 configuration/configure_mouse_advanced.h
70 configuration/configure_mouse_advanced.ui 73 configuration/configure_mouse_advanced.ui
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 7af974d8d..489877be9 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -6,7 +6,6 @@
6#include <QKeySequence> 6#include <QKeySequence>
7#include <QSettings> 7#include <QSettings>
8#include "common/file_util.h" 8#include "common/file_util.h"
9#include "configure_input_simple.h"
10#include "core/hle/service/acc/profile_manager.h" 9#include "core/hle/service/acc/profile_manager.h"
11#include "core/hle/service/hid/controllers/npad.h" 10#include "core/hle/service/hid/controllers/npad.h"
12#include "input_common/main.h" 11#include "input_common/main.h"
@@ -32,29 +31,29 @@ Config::~Config() {
32} 31}
33 32
34const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = { 33const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = {
35 Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_3, Qt::Key_4, Qt::Key_Q, 34 Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_3, Qt::Key_4, Qt::Key_Q,
36 Qt::Key_W, Qt::Key_1, Qt::Key_2, Qt::Key_N, Qt::Key_M, Qt::Key_F, Qt::Key_T, 35 Qt::Key_W, Qt::Key_1, Qt::Key_2, Qt::Key_N, Qt::Key_M, Qt::Key_F, Qt::Key_T,
37 Qt::Key_H, Qt::Key_G, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right, Qt::Key_Down, Qt::Key_J, 36 Qt::Key_H, Qt::Key_G, Qt::Key_D, Qt::Key_C, Qt::Key_B, Qt::Key_V,
38 Qt::Key_I, Qt::Key_L, Qt::Key_K, Qt::Key_D, Qt::Key_C, Qt::Key_B, Qt::Key_V,
39}; 37};
40 38
41const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{ 39const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{
42 { 40 {
43 Qt::Key_Up, 41 Qt::Key_Up,
44 Qt::Key_Down, 42 Qt::Key_Down,
45 Qt::Key_Left, 43 Qt::Key_Left,
46 Qt::Key_Right, 44 Qt::Key_Right,
47 Qt::Key_E,
48 }, 45 },
49 { 46 {
50 Qt::Key_I, 47 Qt::Key_I,
51 Qt::Key_K, 48 Qt::Key_K,
52 Qt::Key_J, 49 Qt::Key_J,
53 Qt::Key_L, 50 Qt::Key_L,
54 Qt::Key_R,
55 }, 51 },
56}}; 52}};
57 53
54const int Config::default_lstick_mod = Qt::Key_E;
55const int Config::default_rstick_mod = Qt::Key_R;
56
58const std::array<int, Settings::NativeMouseButton::NumMouseButtons> Config::default_mouse_buttons = 57const std::array<int, Settings::NativeMouseButton::NumMouseButtons> Config::default_mouse_buttons =
59 { 58 {
60 Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Apostrophe, Qt::Key_Minus, Qt::Key_Equal, 59 Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Apostrophe, Qt::Key_Minus, Qt::Key_Equal,
@@ -243,10 +242,10 @@ void Config::ReadPlayerValues() {
243 player.connected = 242 player.connected =
244 ReadSetting(QStringLiteral("player_%1_connected").arg(p), false).toBool(); 243 ReadSetting(QStringLiteral("player_%1_connected").arg(p), false).toBool();
245 244
246 player.type = static_cast<Settings::ControllerType>( 245 player.controller_type = static_cast<Settings::ControllerType>(
247 qt_config 246 qt_config
248 ->value(QStringLiteral("player_%1_type").arg(p), 247 ->value(QStringLiteral("player_%1_type").arg(p),
249 static_cast<u8>(Settings::ControllerType::DualJoycon)) 248 static_cast<u8>(Settings::ControllerType::ProController))
250 .toUInt()); 249 .toUInt());
251 250
252 player.body_color_left = qt_config 251 player.body_color_left = qt_config
@@ -300,12 +299,6 @@ void Config::ReadPlayerValues() {
300 } 299 }
301 } 300 }
302 } 301 }
303
304 std::stable_partition(
305 Settings::values.players.begin(),
306 Settings::values.players.begin() +
307 Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD),
308 [](const auto& player) { return player.connected; });
309} 302}
310 303
311void Config::ReadDebugValues() { 304void Config::ReadDebugValues() {
@@ -397,13 +390,6 @@ void Config::ReadTouchscreenValues() {
397 ReadSetting(QStringLiteral("touchscreen_diameter_y"), 15).toUInt(); 390 ReadSetting(QStringLiteral("touchscreen_diameter_y"), 15).toUInt();
398} 391}
399 392
400void Config::ApplyDefaultProfileIfInputInvalid() {
401 if (!std::any_of(Settings::values.players.begin(), Settings::values.players.end(),
402 [](const Settings::PlayerInput& in) { return in.connected; })) {
403 ApplyInputProfileConfiguration(UISettings::values.profile_index);
404 }
405}
406
407void Config::ReadAudioValues() { 393void Config::ReadAudioValues() {
408 qt_config->beginGroup(QStringLiteral("Audio")); 394 qt_config->beginGroup(QStringLiteral("Audio"));
409 395
@@ -433,6 +419,8 @@ void Config::ReadControlValues() {
433 ReadMouseValues(); 419 ReadMouseValues();
434 ReadTouchscreenValues(); 420 ReadTouchscreenValues();
435 421
422 Settings::values.vibration_enabled =
423 ReadSetting(QStringLiteral("vibration_enabled"), true).toBool();
436 Settings::values.motion_device = 424 Settings::values.motion_device =
437 ReadSetting(QStringLiteral("motion_device"), 425 ReadSetting(QStringLiteral("motion_device"),
438 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01")) 426 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"))
@@ -501,7 +489,7 @@ void Config::ReadDataStorageValues() {
501 Settings::values.gamecard_current_game = 489 Settings::values.gamecard_current_game =
502 ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool(); 490 ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool();
503 Settings::values.gamecard_path = 491 Settings::values.gamecard_path =
504 ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString(); 492 ReadSetting(QStringLiteral("gamecard_path"), QString{}).toString().toStdString();
505 493
506 qt_config->endGroup(); 494 qt_config->endGroup();
507} 495}
@@ -515,7 +503,7 @@ void Config::ReadDebuggingValues() {
515 Settings::values.use_gdbstub = ReadSetting(QStringLiteral("use_gdbstub"), false).toBool(); 503 Settings::values.use_gdbstub = ReadSetting(QStringLiteral("use_gdbstub"), false).toBool();
516 Settings::values.gdbstub_port = ReadSetting(QStringLiteral("gdbstub_port"), 24689).toInt(); 504 Settings::values.gdbstub_port = ReadSetting(QStringLiteral("gdbstub_port"), 24689).toInt();
517 Settings::values.program_args = 505 Settings::values.program_args =
518 ReadSetting(QStringLiteral("program_args"), QStringLiteral("")).toString().toStdString(); 506 ReadSetting(QStringLiteral("program_args"), QString{}).toString().toStdString();
519 Settings::values.dump_exefs = ReadSetting(QStringLiteral("dump_exefs"), false).toBool(); 507 Settings::values.dump_exefs = ReadSetting(QStringLiteral("dump_exefs"), false).toBool();
520 Settings::values.dump_nso = ReadSetting(QStringLiteral("dump_nso"), false).toBool(); 508 Settings::values.dump_nso = ReadSetting(QStringLiteral("dump_nso"), false).toBool();
521 Settings::values.reporting_services = 509 Settings::values.reporting_services =
@@ -548,8 +536,7 @@ void Config::ReadDisabledAddOnValues() {
548 const auto d_size = qt_config->beginReadArray(QStringLiteral("disabled")); 536 const auto d_size = qt_config->beginReadArray(QStringLiteral("disabled"));
549 for (int j = 0; j < d_size; ++j) { 537 for (int j = 0; j < d_size; ++j) {
550 qt_config->setArrayIndex(j); 538 qt_config->setArrayIndex(j);
551 out.push_back( 539 out.push_back(ReadSetting(QStringLiteral("d"), QString{}).toString().toStdString());
552 ReadSetting(QStringLiteral("d"), QStringLiteral("")).toString().toStdString());
553 } 540 }
554 qt_config->endArray(); 541 qt_config->endArray();
555 Settings::values.disabled_addons.insert_or_assign(title_id, out); 542 Settings::values.disabled_addons.insert_or_assign(title_id, out);
@@ -788,14 +775,11 @@ void Config::ReadUIValues() {
788 UISettings::values.first_start = ReadSetting(QStringLiteral("firstStart"), true).toBool(); 775 UISettings::values.first_start = ReadSetting(QStringLiteral("firstStart"), true).toBool();
789 UISettings::values.callout_flags = ReadSetting(QStringLiteral("calloutFlags"), 0).toUInt(); 776 UISettings::values.callout_flags = ReadSetting(QStringLiteral("calloutFlags"), 0).toUInt();
790 UISettings::values.show_console = ReadSetting(QStringLiteral("showConsole"), false).toBool(); 777 UISettings::values.show_console = ReadSetting(QStringLiteral("showConsole"), false).toBool();
791 UISettings::values.profile_index = ReadSetting(QStringLiteral("profileIndex"), 0).toUInt();
792 UISettings::values.pause_when_in_background = 778 UISettings::values.pause_when_in_background =
793 ReadSetting(QStringLiteral("pauseWhenInBackground"), false).toBool(); 779 ReadSetting(QStringLiteral("pauseWhenInBackground"), false).toBool();
794 UISettings::values.hide_mouse = 780 UISettings::values.hide_mouse =
795 ReadSetting(QStringLiteral("hideInactiveMouse"), false).toBool(); 781 ReadSetting(QStringLiteral("hideInactiveMouse"), false).toBool();
796 782
797 ApplyDefaultProfileIfInputInvalid();
798
799 qt_config->endGroup(); 783 qt_config->endGroup();
800} 784}
801 785
@@ -869,8 +853,9 @@ void Config::SavePlayerValues() {
869 const auto& player = Settings::values.players[p]; 853 const auto& player = Settings::values.players[p];
870 854
871 WriteSetting(QStringLiteral("player_%1_connected").arg(p), player.connected, false); 855 WriteSetting(QStringLiteral("player_%1_connected").arg(p), player.connected, false);
872 WriteSetting(QStringLiteral("player_%1_type").arg(p), static_cast<u8>(player.type), 856 WriteSetting(QStringLiteral("player_%1_type").arg(p),
873 static_cast<u8>(Settings::ControllerType::DualJoycon)); 857 static_cast<u8>(player.controller_type),
858 static_cast<u8>(Settings::ControllerType::ProController));
874 859
875 WriteSetting(QStringLiteral("player_%1_body_color_left").arg(p), player.body_color_left, 860 WriteSetting(QStringLiteral("player_%1_body_color_left").arg(p), player.body_color_left,
876 Settings::JOYCON_BODY_NEON_BLUE); 861 Settings::JOYCON_BODY_NEON_BLUE);
@@ -990,6 +975,7 @@ void Config::SaveControlValues() {
990 SaveMouseValues(); 975 SaveMouseValues();
991 SaveTouchscreenValues(); 976 SaveTouchscreenValues();
992 977
978 WriteSetting(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled, true);
993 WriteSetting(QStringLiteral("motion_device"), 979 WriteSetting(QStringLiteral("motion_device"),
994 QString::fromStdString(Settings::values.motion_device), 980 QString::fromStdString(Settings::values.motion_device),
995 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01")); 981 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"));
@@ -1036,7 +1022,7 @@ void Config::SaveDataStorageValues() {
1036 WriteSetting(QStringLiteral("gamecard_current_game"), Settings::values.gamecard_current_game, 1022 WriteSetting(QStringLiteral("gamecard_current_game"), Settings::values.gamecard_current_game,
1037 false); 1023 false);
1038 WriteSetting(QStringLiteral("gamecard_path"), 1024 WriteSetting(QStringLiteral("gamecard_path"),
1039 QString::fromStdString(Settings::values.gamecard_path), QStringLiteral("")); 1025 QString::fromStdString(Settings::values.gamecard_path), QString{});
1040 1026
1041 qt_config->endGroup(); 1027 qt_config->endGroup();
1042} 1028}
@@ -1049,7 +1035,7 @@ void Config::SaveDebuggingValues() {
1049 WriteSetting(QStringLiteral("use_gdbstub"), Settings::values.use_gdbstub, false); 1035 WriteSetting(QStringLiteral("use_gdbstub"), Settings::values.use_gdbstub, false);
1050 WriteSetting(QStringLiteral("gdbstub_port"), Settings::values.gdbstub_port, 24689); 1036 WriteSetting(QStringLiteral("gdbstub_port"), Settings::values.gdbstub_port, 24689);
1051 WriteSetting(QStringLiteral("program_args"), 1037 WriteSetting(QStringLiteral("program_args"),
1052 QString::fromStdString(Settings::values.program_args), QStringLiteral("")); 1038 QString::fromStdString(Settings::values.program_args), QString{});
1053 WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false); 1039 WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false);
1054 WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false); 1040 WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false);
1055 WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false); 1041 WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false);
@@ -1076,8 +1062,7 @@ void Config::SaveDisabledAddOnValues() {
1076 qt_config->beginWriteArray(QStringLiteral("disabled")); 1062 qt_config->beginWriteArray(QStringLiteral("disabled"));
1077 for (std::size_t j = 0; j < elem.second.size(); ++j) { 1063 for (std::size_t j = 0; j < elem.second.size(); ++j) {
1078 qt_config->setArrayIndex(static_cast<int>(j)); 1064 qt_config->setArrayIndex(static_cast<int>(j));
1079 WriteSetting(QStringLiteral("d"), QString::fromStdString(elem.second[j]), 1065 WriteSetting(QStringLiteral("d"), QString::fromStdString(elem.second[j]), QString{});
1080 QStringLiteral(""));
1081 } 1066 }
1082 qt_config->endArray(); 1067 qt_config->endArray();
1083 ++i; 1068 ++i;
@@ -1266,7 +1251,6 @@ void Config::SaveUIValues() {
1266 WriteSetting(QStringLiteral("firstStart"), UISettings::values.first_start, true); 1251 WriteSetting(QStringLiteral("firstStart"), UISettings::values.first_start, true);
1267 WriteSetting(QStringLiteral("calloutFlags"), UISettings::values.callout_flags, 0); 1252 WriteSetting(QStringLiteral("calloutFlags"), UISettings::values.callout_flags, 0);
1268 WriteSetting(QStringLiteral("showConsole"), UISettings::values.show_console, false); 1253 WriteSetting(QStringLiteral("showConsole"), UISettings::values.show_console, false);
1269 WriteSetting(QStringLiteral("profileIndex"), UISettings::values.profile_index, 0);
1270 WriteSetting(QStringLiteral("pauseWhenInBackground"), 1254 WriteSetting(QStringLiteral("pauseWhenInBackground"),
1271 UISettings::values.pause_when_in_background, false); 1255 UISettings::values.pause_when_in_background, false);
1272 WriteSetting(QStringLiteral("hideInactiveMouse"), UISettings::values.hide_mouse, false); 1256 WriteSetting(QStringLiteral("hideInactiveMouse"), UISettings::values.hide_mouse, false);
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index e5f39b040..9eeaf9d1e 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -23,7 +23,9 @@ public:
23 void Save(); 23 void Save();
24 24
25 static const std::array<int, Settings::NativeButton::NumButtons> default_buttons; 25 static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
26 static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs; 26 static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs;
27 static const int default_lstick_mod;
28 static const int default_rstick_mod;
27 static const std::array<int, Settings::NativeMouseButton::NumMouseButtons> 29 static const std::array<int, Settings::NativeMouseButton::NumMouseButtons>
28 default_mouse_buttons; 30 default_mouse_buttons;
29 static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys; 31 static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
@@ -37,7 +39,6 @@ private:
37 void ReadKeyboardValues(); 39 void ReadKeyboardValues();
38 void ReadMouseValues(); 40 void ReadMouseValues();
39 void ReadTouchscreenValues(); 41 void ReadTouchscreenValues();
40 void ApplyDefaultProfileIfInputInvalid();
41 42
42 // Read functions bases off the respective config section names. 43 // Read functions bases off the respective config section names.
43 void ReadAudioValues(); 44 void ReadAudioValues();
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index 5f5d8e571..fcf42cdcb 100644
--- a/src/yuzu/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
@@ -6,7 +6,7 @@
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>382</width> 9 <width>650</width>
10 <height>650</height> 10 <height>650</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
@@ -26,13 +26,13 @@
26 <widget class="QListWidget" name="selectorList"> 26 <widget class="QListWidget" name="selectorList">
27 <property name="minimumSize"> 27 <property name="minimumSize">
28 <size> 28 <size>
29 <width>150</width> 29 <width>120</width>
30 <height>0</height> 30 <height>0</height>
31 </size> 31 </size>
32 </property> 32 </property>
33 <property name="maximumSize"> 33 <property name="maximumSize">
34 <size> 34 <size>
35 <width>150</width> 35 <width>120</width>
36 <height>16777215</height> 36 <height>16777215</height>
37 </size> 37 </size>
38 </property> 38 </property>
@@ -44,76 +44,121 @@
44 <number>0</number> 44 <number>0</number>
45 </property> 45 </property>
46 <widget class="ConfigureGeneral" name="generalTab"> 46 <widget class="ConfigureGeneral" name="generalTab">
47 <property name="accessibleName">
48 <string>General</string>
49 </property>
47 <attribute name="title"> 50 <attribute name="title">
48 <string>General</string> 51 <string>General</string>
49 </attribute> 52 </attribute>
50 </widget> 53 </widget>
51 <widget class="ConfigureUi" name="uiTab"> 54 <widget class="ConfigureUi" name="uiTab">
55 <property name="accessibleName">
56 <string>UI</string>
57 </property>
52 <attribute name="title"> 58 <attribute name="title">
53 <string>Game List</string> 59 <string>Game List</string>
54 </attribute> 60 </attribute>
55 </widget> 61 </widget>
56 <widget class="ConfigureSystem" name="systemTab"> 62 <widget class="ConfigureSystem" name="systemTab">
63 <property name="accessibleName">
64 <string>System</string>
65 </property>
57 <attribute name="title"> 66 <attribute name="title">
58 <string>System</string> 67 <string>System</string>
59 </attribute> 68 </attribute>
60 </widget> 69 </widget>
61 <widget class="ConfigureProfileManager" name="profileManagerTab"> 70 <widget class="ConfigureProfileManager" name="profileManagerTab">
71 <property name="accessibleName">
72 <string>Profiles</string>
73 </property>
62 <attribute name="title"> 74 <attribute name="title">
63 <string>Profiles</string> 75 <string>Profiles</string>
64 </attribute> 76 </attribute>
65 </widget> 77 </widget>
66 <widget class="ConfigureFilesystem" name="filesystemTab"> 78 <widget class="ConfigureFilesystem" name="filesystemTab">
79 <property name="accessibleName">
80 <string>Filesystem</string>
81 </property>
67 <attribute name="title"> 82 <attribute name="title">
68 <string>Filesystem</string> 83 <string>Filesystem</string>
69 </attribute> 84 </attribute>
70 </widget> 85 </widget>
71 <widget class="ConfigureInputSimple" name="inputTab"> 86 <widget class="ConfigureInput" name="inputTab">
87 <property name="accessibleName">
88 <string>Controls</string>
89 </property>
72 <attribute name="title"> 90 <attribute name="title">
73 <string>Input</string> 91 <string>Controls</string>
74 </attribute> 92 </attribute>
75 </widget> 93 </widget>
76 <widget class="ConfigureHotkeys" name="hotkeysTab"> 94 <widget class="ConfigureHotkeys" name="hotkeysTab">
95 <property name="accessibleName">
96 <string>Hotkeys</string>
97 </property>
77 <attribute name="title"> 98 <attribute name="title">
78 <string>Hotkeys</string> 99 <string>Hotkeys</string>
79 </attribute> 100 </attribute>
80 </widget> 101 </widget>
81 <widget class="ConfigureCpu" name="cpuTab"> 102 <widget class="ConfigureCpu" name="cpuTab">
103 <property name="accessibleName">
104 <string>CPU</string>
105 </property>
82 <attribute name="title"> 106 <attribute name="title">
83 <string>CPU</string> 107 <string>CPU</string>
84 </attribute> 108 </attribute>
85 </widget> 109 </widget>
86 <widget class="ConfigureCpuDebug" name="cpuDebugTab"> 110 <widget class="ConfigureCpuDebug" name="cpuDebugTab">
111 <property name="accessibleName">
112 <string>Debug</string>
113 </property>
87 <attribute name="title"> 114 <attribute name="title">
88 <string>Debug</string> 115 <string>Debug</string>
89 </attribute> 116 </attribute>
90 </widget> 117 </widget>
91 <widget class="ConfigureGraphics" name="graphicsTab"> 118 <widget class="ConfigureGraphics" name="graphicsTab">
119 <property name="accessibleName">
120 <string>Graphics</string>
121 </property>
92 <attribute name="title"> 122 <attribute name="title">
93 <string>Graphics</string> 123 <string>Graphics</string>
94 </attribute> 124 </attribute>
95 </widget> 125 </widget>
96 <widget class="ConfigureGraphicsAdvanced" name="graphicsAdvancedTab"> 126 <widget class="ConfigureGraphicsAdvanced" name="graphicsAdvancedTab">
127 <property name="accessibleName">
128 <string>Advanced</string>
129 </property>
97 <attribute name="title"> 130 <attribute name="title">
98 <string>GraphicsAdvanced</string> 131 <string>GraphicsAdvanced</string>
99 </attribute> 132 </attribute>
100 </widget> 133 </widget>
101 <widget class="ConfigureAudio" name="audioTab"> 134 <widget class="ConfigureAudio" name="audioTab">
135 <property name="accessibleName">
136 <string>Audio</string>
137 </property>
102 <attribute name="title"> 138 <attribute name="title">
103 <string>Audio</string> 139 <string>Audio</string>
104 </attribute> 140 </attribute>
105 </widget> 141 </widget>
106 <widget class="ConfigureDebug" name="debugTab"> 142 <widget class="ConfigureDebug" name="debugTab">
143 <property name="accessibleName">
144 <string>Debug</string>
145 </property>
107 <attribute name="title"> 146 <attribute name="title">
108 <string>Debug</string> 147 <string>Debug</string>
109 </attribute> 148 </attribute>
110 </widget> 149 </widget>
111 <widget class="ConfigureWeb" name="webTab"> 150 <widget class="ConfigureWeb" name="webTab">
151 <property name="accessibleName">
152 <string>Web</string>
153 </property>
112 <attribute name="title"> 154 <attribute name="title">
113 <string>Web</string> 155 <string>Web</string>
114 </attribute> 156 </attribute>
115 </widget> 157 </widget>
116 <widget class="ConfigureService" name="serviceTab"> 158 <widget class="ConfigureService" name="serviceTab">
159 <property name="accessibleName">
160 <string>Services</string>
161 </property>
117 <attribute name="title"> 162 <attribute name="title">
118 <string>Services</string> 163 <string>Services</string>
119 </attribute> 164 </attribute>
@@ -205,9 +250,9 @@
205 <container>1</container> 250 <container>1</container>
206 </customwidget> 251 </customwidget>
207 <customwidget> 252 <customwidget>
208 <class>ConfigureInputSimple</class> 253 <class>ConfigureInput</class>
209 <extends>QWidget</extends> 254 <extends>QWidget</extends>
210 <header>configuration/configure_input_simple.h</header> 255 <header>configuration/configure_input.h</header>
211 <container>1</container> 256 <container>1</container>
212 </customwidget> 257 </customwidget>
213 <customwidget> 258 <customwidget>
diff --git a/src/yuzu/configuration/configure_debug_controller.cpp b/src/yuzu/configuration/configure_debug_controller.cpp
new file mode 100644
index 000000000..45996b73f
--- /dev/null
+++ b/src/yuzu/configuration/configure_debug_controller.cpp
@@ -0,0 +1,39 @@
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_debug_controller.h"
6#include "yuzu/configuration/configure_debug_controller.h"
7
8ConfigureDebugController::ConfigureDebugController(QWidget* parent)
9 : QDialog(parent), ui(std::make_unique<Ui::ConfigureDebugController>()) {
10 ui->setupUi(this);
11
12 debug_controller = new ConfigureInputPlayer(this, 9, nullptr, true);
13 ui->controllerLayout->addWidget(debug_controller);
14
15 connect(ui->clear_all_button, &QPushButton::clicked, this,
16 [this] { debug_controller->ClearAll(); });
17 connect(ui->restore_defaults_button, &QPushButton::clicked, this,
18 [this] { debug_controller->RestoreDefaults(); });
19
20 RetranslateUI();
21}
22
23ConfigureDebugController::~ConfigureDebugController() = default;
24
25void ConfigureDebugController::ApplyConfiguration() {
26 debug_controller->ApplyConfiguration();
27}
28
29void ConfigureDebugController::changeEvent(QEvent* event) {
30 if (event->type() == QEvent::LanguageChange) {
31 RetranslateUI();
32 }
33
34 QDialog::changeEvent(event);
35}
36
37void ConfigureDebugController::RetranslateUI() {
38 ui->retranslateUi(this);
39}
diff --git a/src/yuzu/configuration/configure_debug_controller.h b/src/yuzu/configuration/configure_debug_controller.h
new file mode 100644
index 000000000..df359a4f3
--- /dev/null
+++ b/src/yuzu/configuration/configure_debug_controller.h
@@ -0,0 +1,33 @@
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_player.h"
10
11class QPushButton;
12
13namespace Ui {
14class ConfigureDebugController;
15}
16
17class ConfigureDebugController : public QDialog {
18 Q_OBJECT
19
20public:
21 explicit ConfigureDebugController(QWidget* parent);
22 ~ConfigureDebugController() override;
23
24 void ApplyConfiguration();
25
26private:
27 void changeEvent(QEvent* event) override;
28 void RetranslateUI();
29
30 ConfigureInputPlayer* debug_controller;
31
32 std::unique_ptr<Ui::ConfigureDebugController> ui;
33};
diff --git a/src/yuzu/configuration/configure_debug_controller.ui b/src/yuzu/configuration/configure_debug_controller.ui
new file mode 100644
index 000000000..a95ed50ff
--- /dev/null
+++ b/src/yuzu/configuration/configure_debug_controller.ui
@@ -0,0 +1,97 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureDebugController</class>
4 <widget class="QDialog" name="ConfigureDebugController">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>780</width>
10 <height>500</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Configure Debug Controller</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="controllerLayout"/>
34 </item>
35 <item>
36 <layout class="QHBoxLayout" name="horizontalLayout">
37 <item>
38 <widget class="QPushButton" name="clear_all_button">
39 <property name="text">
40 <string>Clear</string>
41 </property>
42 </widget>
43 </item>
44 <item>
45 <widget class="QPushButton" name="restore_defaults_button">
46 <property name="text">
47 <string>Defaults</string>
48 </property>
49 </widget>
50 </item>
51 <item>
52 <widget class="QDialogButtonBox" name="buttonBox">
53 <property name="standardButtons">
54 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
55 </property>
56 </widget>
57 </item>
58 </layout>
59 </item>
60 </layout>
61 </widget>
62 <resources/>
63 <connections>
64 <connection>
65 <sender>buttonBox</sender>
66 <signal>accepted()</signal>
67 <receiver>ConfigureDebugController</receiver>
68 <slot>accept()</slot>
69 <hints>
70 <hint type="sourcelabel">
71 <x>140</x>
72 <y>318</y>
73 </hint>
74 <hint type="destinationlabel">
75 <x>140</x>
76 <y>169</y>
77 </hint>
78 </hints>
79 </connection>
80 <connection>
81 <sender>buttonBox</sender>
82 <signal>rejected()</signal>
83 <receiver>ConfigureDebugController</receiver>
84 <slot>reject()</slot>
85 <hints>
86 <hint type="sourcelabel">
87 <x>140</x>
88 <y>318</y>
89 </hint>
90 <hint type="destinationlabel">
91 <x>140</x>
92 <y>169</y>
93 </hint>
94 </hints>
95 </connection>
96 </connections>
97</ui>
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index 4e30dc51e..857577591 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -80,12 +80,12 @@ Q_DECLARE_METATYPE(QList<QWidget*>);
80 80
81void ConfigureDialog::PopulateSelectionList() { 81void ConfigureDialog::PopulateSelectionList() {
82 const std::array<std::pair<QString, QList<QWidget*>>, 6> items{ 82 const std::array<std::pair<QString, QList<QWidget*>>, 6> items{
83 {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}}, 83 {{tr("General"), {ui->generalTab, ui->hotkeysTab, ui->uiTab, ui->webTab, ui->debugTab}},
84 {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}}, 84 {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}},
85 {tr("CPU"), {ui->cpuTab, ui->cpuDebugTab}}, 85 {tr("CPU"), {ui->cpuTab, ui->cpuDebugTab}},
86 {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}}, 86 {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}},
87 {tr("Audio"), {ui->audioTab}}, 87 {tr("Audio"), {ui->audioTab}},
88 {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}, 88 {tr("Controls"), ui->inputTab->GetSubTabs()}},
89 }; 89 };
90 90
91 [[maybe_unused]] const QSignalBlocker blocker(ui->selectorList); 91 [[maybe_unused]] const QSignalBlocker blocker(ui->selectorList);
@@ -117,7 +117,7 @@ void ConfigureDialog::UpdateVisibleTabs() {
117 {ui->generalTab, tr("General")}, 117 {ui->generalTab, tr("General")},
118 {ui->systemTab, tr("System")}, 118 {ui->systemTab, tr("System")},
119 {ui->profileManagerTab, tr("Profiles")}, 119 {ui->profileManagerTab, tr("Profiles")},
120 {ui->inputTab, tr("Input")}, 120 {ui->inputTab, tr("Controls")},
121 {ui->hotkeysTab, tr("Hotkeys")}, 121 {ui->hotkeysTab, tr("Hotkeys")},
122 {ui->cpuTab, tr("CPU")}, 122 {ui->cpuTab, tr("CPU")},
123 {ui->cpuDebugTab, tr("Debug")}, 123 {ui->cpuDebugTab, tr("Debug")},
@@ -138,6 +138,6 @@ void ConfigureDialog::UpdateVisibleTabs() {
138 const QList<QWidget*> tabs = qvariant_cast<QList<QWidget*>>(items[0]->data(Qt::UserRole)); 138 const QList<QWidget*> tabs = qvariant_cast<QList<QWidget*>>(items[0]->data(Qt::UserRole));
139 139
140 for (const auto tab : tabs) { 140 for (const auto tab : tabs) {
141 ui->tabWidget->addTab(tab, widgets.at(tab)); 141 ui->tabWidget->addTab(tab, tab->accessibleName());
142 } 142 }
143} 143}
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index f2977719c..5200d2d0e 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -8,18 +8,32 @@
8#include <QSignalBlocker> 8#include <QSignalBlocker>
9#include <QTimer> 9#include <QTimer>
10 10
11#include "configuration/configure_touchscreen_advanced.h"
12#include "core/core.h" 11#include "core/core.h"
13#include "core/hle/service/am/am.h" 12#include "core/hle/service/am/am.h"
14#include "core/hle/service/am/applet_ae.h" 13#include "core/hle/service/am/applet_ae.h"
15#include "core/hle/service/am/applet_oe.h" 14#include "core/hle/service/am/applet_oe.h"
16#include "core/hle/service/hid/controllers/npad.h"
17#include "core/hle/service/sm/sm.h" 15#include "core/hle/service/sm/sm.h"
18#include "ui_configure_input.h" 16#include "ui_configure_input.h"
17#include "ui_configure_input_advanced.h"
19#include "ui_configure_input_player.h" 18#include "ui_configure_input_player.h"
19#include "yuzu/configuration/configure_debug_controller.h"
20#include "yuzu/configuration/configure_input.h" 20#include "yuzu/configuration/configure_input.h"
21#include "yuzu/configuration/configure_input_advanced.h"
21#include "yuzu/configuration/configure_input_player.h" 22#include "yuzu/configuration/configure_input_player.h"
22#include "yuzu/configuration/configure_mouse_advanced.h" 23#include "yuzu/configuration/configure_mouse_advanced.h"
24#include "yuzu/configuration/configure_touchscreen_advanced.h"
25
26namespace {
27template <typename Dialog, typename... Args>
28void CallConfigureDialog(ConfigureInput& parent, Args&&... args) {
29 Dialog dialog(&parent, std::forward<Args>(args)...);
30
31 const auto res = dialog.exec();
32 if (res == QDialog::Accepted) {
33 dialog.ApplyConfiguration();
34 }
35}
36} // Anonymous namespace
23 37
24void OnDockedModeChanged(bool last_state, bool new_state) { 38void OnDockedModeChanged(bool last_state, bool new_state) {
25 if (last_state == new_state) { 39 if (last_state == new_state) {
@@ -48,97 +62,93 @@ void OnDockedModeChanged(bool last_state, bool new_state) {
48 } 62 }
49} 63}
50 64
51namespace {
52template <typename Dialog, typename... Args>
53void CallConfigureDialog(ConfigureInput& parent, Args&&... args) {
54 parent.ApplyConfiguration();
55 Dialog dialog(&parent, std::forward<Args>(args)...);
56
57 const auto res = dialog.exec();
58 if (res == QDialog::Accepted) {
59 dialog.ApplyConfiguration();
60 }
61}
62} // Anonymous namespace
63
64ConfigureInput::ConfigureInput(QWidget* parent) 65ConfigureInput::ConfigureInput(QWidget* parent)
65 : QDialog(parent), ui(std::make_unique<Ui::ConfigureInput>()) { 66 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) {
66 ui->setupUi(this); 67 ui->setupUi(this);
67 68
68 players_controller = { 69 player_controllers = {
69 ui->player1_combobox, ui->player2_combobox, ui->player3_combobox, ui->player4_combobox, 70 new ConfigureInputPlayer(this, 0, ui->consoleInputSettings),
70 ui->player5_combobox, ui->player6_combobox, ui->player7_combobox, ui->player8_combobox, 71 new ConfigureInputPlayer(this, 1, ui->consoleInputSettings),
72 new ConfigureInputPlayer(this, 2, ui->consoleInputSettings),
73 new ConfigureInputPlayer(this, 3, ui->consoleInputSettings),
74 new ConfigureInputPlayer(this, 4, ui->consoleInputSettings),
75 new ConfigureInputPlayer(this, 5, ui->consoleInputSettings),
76 new ConfigureInputPlayer(this, 6, ui->consoleInputSettings),
77 new ConfigureInputPlayer(this, 7, ui->consoleInputSettings),
71 }; 78 };
72 79
73 players_configure = { 80 player_tabs = {
74 ui->player1_configure, ui->player2_configure, ui->player3_configure, ui->player4_configure, 81 ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, ui->tabPlayer4,
75 ui->player5_configure, ui->player6_configure, ui->player7_configure, ui->player8_configure, 82 ui->tabPlayer5, ui->tabPlayer6, ui->tabPlayer7, ui->tabPlayer8,
76 }; 83 };
77 84
78 RetranslateUI(); 85 player_connected = {
79 LoadConfiguration(); 86 ui->checkboxPlayer1Connected, ui->checkboxPlayer2Connected, ui->checkboxPlayer3Connected,
80 UpdateUIEnabled(); 87 ui->checkboxPlayer4Connected, ui->checkboxPlayer5Connected, ui->checkboxPlayer6Connected,
81 88 ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected,
82 connect(ui->restore_defaults_button, &QPushButton::clicked, this, 89 };
83 &ConfigureInput::RestoreDefaults);
84 90
85 for (auto* enabled : players_controller) { 91 for (std::size_t i = 0; i < player_tabs.size(); ++i) {
86 connect(enabled, QOverload<int>::of(&QComboBox::currentIndexChanged), this, 92 player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i]));
87 &ConfigureInput::UpdateUIEnabled); 93 player_tabs[i]->layout()->addWidget(player_controllers[i]);
94 connect(player_controllers[i], &ConfigureInputPlayer::Connected, [&, i](bool is_connected) {
95 if (is_connected) {
96 for (std::size_t index = 0; index <= i; ++index) {
97 player_connected[index]->setChecked(is_connected);
98 }
99 } else {
100 for (std::size_t index = i; index < player_tabs.size(); ++index) {
101 player_connected[index]->setChecked(is_connected);
102 }
103 }
104 });
105 connect(player_controllers[i], &ConfigureInputPlayer::RefreshInputDevices,
106 [&] { UpdateAllInputDevices(); });
107 connect(player_connected[i], &QCheckBox::stateChanged,
108 [&, i](int state) { player_controllers[i]->ConnectPlayer(state == Qt::Checked); });
88 } 109 }
89 connect(ui->use_docked_mode, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled); 110 // Only the first player can choose handheld mode so connect the signal just to player 1
90 connect(ui->handheld_connected, &QCheckBox::stateChanged, this, 111 connect(player_controllers[0], &ConfigureInputPlayer::HandheldStateChanged,
91 &ConfigureInput::UpdateUIEnabled); 112 [&](bool is_handheld) { UpdateDockedState(is_handheld); });
92 connect(ui->mouse_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled); 113
93 connect(ui->keyboard_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled); 114 advanced = new ConfigureInputAdvanced(this);
94 connect(ui->debug_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled); 115 ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced));
95 connect(ui->touchscreen_enabled, &QCheckBox::stateChanged, this, 116 ui->tabAdvanced->layout()->addWidget(advanced);
96 &ConfigureInput::UpdateUIEnabled); 117 connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog,
97 118 [this] { CallConfigureDialog<ConfigureDebugController>(*this); });
98 for (std::size_t i = 0; i < players_configure.size(); ++i) { 119 connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog,
99 connect(players_configure[i], &QPushButton::clicked, this,
100 [this, i] { CallConfigureDialog<ConfigureInputPlayer>(*this, i, false); });
101 }
102
103 connect(ui->handheld_configure, &QPushButton::clicked, this,
104 [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 8, false); });
105
106 connect(ui->debug_configure, &QPushButton::clicked, this,
107 [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 9, true); });
108
109 connect(ui->mouse_advanced, &QPushButton::clicked, this,
110 [this] { CallConfigureDialog<ConfigureMouseAdvanced>(*this); }); 120 [this] { CallConfigureDialog<ConfigureMouseAdvanced>(*this); });
111 121 connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog,
112 connect(ui->touchscreen_advanced, &QPushButton::clicked, this,
113 [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); }); 122 [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
123
124 connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); });
125 connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); });
126
127 RetranslateUI();
128 LoadConfiguration();
114} 129}
115 130
116ConfigureInput::~ConfigureInput() = default; 131ConfigureInput::~ConfigureInput() = default;
117 132
118void ConfigureInput::ApplyConfiguration() { 133QList<QWidget*> ConfigureInput::GetSubTabs() const {
119 for (std::size_t i = 0; i < players_controller.size(); ++i) { 134 return {
120 const auto controller_type_index = players_controller[i]->currentIndex(); 135 ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, ui->tabPlayer4, ui->tabPlayer5,
121 136 ui->tabPlayer6, ui->tabPlayer7, ui->tabPlayer8, ui->tabAdvanced,
122 Settings::values.players[i].connected = controller_type_index != 0; 137 };
138}
123 139
124 if (controller_type_index > 0) { 140void ConfigureInput::ApplyConfiguration() {
125 Settings::values.players[i].type = 141 for (auto controller : player_controllers) {
126 static_cast<Settings::ControllerType>(controller_type_index - 1); 142 controller->ApplyConfiguration();
127 } else {
128 Settings::values.players[i].type = Settings::ControllerType::DualJoycon;
129 }
130 } 143 }
131 144
145 advanced->ApplyConfiguration();
146
132 const bool pre_docked_mode = Settings::values.use_docked_mode; 147 const bool pre_docked_mode = Settings::values.use_docked_mode;
133 Settings::values.use_docked_mode = ui->use_docked_mode->isChecked(); 148 Settings::values.use_docked_mode = ui->radioDocked->isChecked();
134 OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode); 149 OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
135 Settings::values 150
136 .players[Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD)] 151 Settings::values.vibration_enabled = ui->vibrationGroup->isChecked();
137 .connected = ui->handheld_connected->isChecked();
138 Settings::values.debug_pad_enabled = ui->debug_enabled->isChecked();
139 Settings::values.mouse_enabled = ui->mouse_enabled->isChecked();
140 Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked();
141 Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
142} 152}
143 153
144void ConfigureInput::changeEvent(QEvent* event) { 154void ConfigureInput::changeEvent(QEvent* event) {
@@ -146,94 +156,63 @@ void ConfigureInput::changeEvent(QEvent* event) {
146 RetranslateUI(); 156 RetranslateUI();
147 } 157 }
148 158
149 QDialog::changeEvent(event); 159 QWidget::changeEvent(event);
150} 160}
151 161
152void ConfigureInput::RetranslateUI() { 162void ConfigureInput::RetranslateUI() {
153 ui->retranslateUi(this); 163 ui->retranslateUi(this);
154 RetranslateControllerComboBoxes();
155} 164}
156 165
157void ConfigureInput::RetranslateControllerComboBoxes() { 166void ConfigureInput::LoadConfiguration() {
158 for (auto* controller_box : players_controller) {
159 [[maybe_unused]] const QSignalBlocker blocker(controller_box);
160
161 controller_box->clear();
162 controller_box->addItems({tr("None"), tr("Pro Controller"), tr("Dual Joycons"),
163 tr("Single Right Joycon"), tr("Single Left Joycon")});
164 }
165
166 LoadPlayerControllerIndices(); 167 LoadPlayerControllerIndices();
167} 168 UpdateDockedState(Settings::values.players[0].controller_type ==
169 Settings::ControllerType::Handheld);
168 170
169void ConfigureInput::UpdateUIEnabled() { 171 ui->vibrationGroup->setChecked(Settings::values.vibration_enabled);
170 bool hit_disabled = false; 172}
171 for (auto* player : players_controller) {
172 player->setDisabled(hit_disabled);
173 if (hit_disabled) {
174 player->setCurrentIndex(0);
175 }
176 if (!hit_disabled && player->currentIndex() == 0) {
177 hit_disabled = true;
178 }
179 }
180 173
181 for (std::size_t i = 0; i < players_controller.size(); ++i) { 174void ConfigureInput::LoadPlayerControllerIndices() {
182 players_configure[i]->setEnabled(players_controller[i]->currentIndex() != 0); 175 for (std::size_t i = 0; i < player_connected.size(); ++i) {
176 const auto connected = Settings::values.players[i].connected ||
177 (i == 0 && Settings::values.players[8].connected);
178 player_connected[i]->setChecked(connected);
183 } 179 }
180}
184 181
185 ui->handheld_connected->setChecked(ui->handheld_connected->isChecked() && 182void ConfigureInput::ClearAll() {
186 !ui->use_docked_mode->isChecked()); 183 // We don't have a good way to know what tab is active, but we can find out by getting the
187 ui->handheld_connected->setEnabled(!ui->use_docked_mode->isChecked()); 184 // parent of the consoleInputSettings
188 ui->handheld_configure->setEnabled(ui->handheld_connected->isChecked() && 185 auto player_tab = static_cast<ConfigureInputPlayer*>(ui->consoleInputSettings->parent());
189 !ui->use_docked_mode->isChecked()); 186 player_tab->ClearAll();
190 ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked());
191 ui->debug_configure->setEnabled(ui->debug_enabled->isChecked());
192 ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked());
193} 187}
194 188
195void ConfigureInput::LoadConfiguration() { 189void ConfigureInput::RestoreDefaults() {
196 std::stable_partition( 190 // We don't have a good way to know what tab is active, but we can find out by getting the
197 Settings::values.players.begin(), 191 // parent of the consoleInputSettings
198 Settings::values.players.begin() + 192 auto player_tab = static_cast<ConfigureInputPlayer*>(ui->consoleInputSettings->parent());
199 Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD), 193 player_tab->RestoreDefaults();
200 [](const auto& player) { return player.connected; }); 194
195 ui->radioDocked->setChecked(true);
196 ui->radioUndocked->setChecked(false);
197 ui->vibrationGroup->setChecked(true);
198}
201 199
202 LoadPlayerControllerIndices(); 200void ConfigureInput::UpdateDockedState(bool is_handheld) {
201 // If the controller type is handheld only, disallow changing docked mode
202 ui->radioDocked->setEnabled(!is_handheld);
203 ui->radioUndocked->setEnabled(!is_handheld);
203 204
204 ui->use_docked_mode->setChecked(Settings::values.use_docked_mode); 205 ui->radioDocked->setChecked(Settings::values.use_docked_mode);
205 ui->handheld_connected->setChecked( 206 ui->radioUndocked->setChecked(!Settings::values.use_docked_mode);
206 Settings::values
207 .players[Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD)]
208 .connected);
209 ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled);
210 ui->mouse_enabled->setChecked(Settings::values.mouse_enabled);
211 ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
212 ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
213
214 UpdateUIEnabled();
215}
216 207
217void ConfigureInput::LoadPlayerControllerIndices() { 208 // If its handheld only, force docked mode off (since you can't play handheld in a dock)
218 for (std::size_t i = 0; i < players_controller.size(); ++i) { 209 if (is_handheld) {
219 const auto connected = Settings::values.players[i].connected; 210 ui->radioUndocked->setChecked(true);
220 players_controller[i]->setCurrentIndex(
221 connected ? static_cast<u8>(Settings::values.players[i].type) + 1 : 0);
222 } 211 }
223} 212}
224 213
225void ConfigureInput::RestoreDefaults() { 214void ConfigureInput::UpdateAllInputDevices() {
226 players_controller[0]->setCurrentIndex(2); 215 for (const auto& player : player_controllers) {
227 216 player->UpdateInputDevices();
228 for (std::size_t i = 1; i < players_controller.size(); ++i) {
229 players_controller[i]->setCurrentIndex(0);
230 } 217 }
231
232 ui->use_docked_mode->setCheckState(Qt::Unchecked);
233 ui->handheld_connected->setCheckState(Qt::Unchecked);
234 ui->mouse_enabled->setCheckState(Qt::Unchecked);
235 ui->keyboard_enabled->setCheckState(Qt::Unchecked);
236 ui->debug_enabled->setCheckState(Qt::Unchecked);
237 ui->touchscreen_enabled->setCheckState(Qt::Checked);
238 UpdateUIEnabled();
239} 218}
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index 2f70cb3ca..8241d23ef 100644
--- a/src/yuzu/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
@@ -10,11 +10,14 @@
10#include <QDialog> 10#include <QDialog>
11#include <QKeyEvent> 11#include <QKeyEvent>
12 12
13#include "yuzu/configuration/configure_input_advanced.h"
14#include "yuzu/configuration/configure_input_player.h"
15
13#include "ui_configure_input.h" 16#include "ui_configure_input.h"
14 17
15class QPushButton;
16class QString; 18class QString;
17class QTimer; 19class QTimer;
20class QCheckBox;
18 21
19namespace Ui { 22namespace Ui {
20class ConfigureInput; 23class ConfigureInput;
@@ -22,22 +25,25 @@ class ConfigureInput;
22 25
23void OnDockedModeChanged(bool last_state, bool new_state); 26void OnDockedModeChanged(bool last_state, bool new_state);
24 27
25class ConfigureInput : public QDialog { 28class ConfigureInput : public QWidget {
26 Q_OBJECT 29 Q_OBJECT
27 30
28public: 31public:
29 explicit ConfigureInput(QWidget* parent = nullptr); 32 explicit ConfigureInput(QWidget* parent = nullptr);
30 ~ConfigureInput() override; 33 ~ConfigureInput() override;
31 34
32 /// Save all button configurations to settings file 35 /// Save all button configurations to settings file.
33 void ApplyConfiguration(); 36 void ApplyConfiguration();
34 37
38 QList<QWidget*> GetSubTabs() const;
39
35private: 40private:
36 void changeEvent(QEvent* event) override; 41 void changeEvent(QEvent* event) override;
37 void RetranslateUI(); 42 void RetranslateUI();
38 void RetranslateControllerComboBoxes(); 43 void ClearAll();
39 44
40 void UpdateUIEnabled(); 45 void UpdateDockedState(bool is_handheld);
46 void UpdateAllInputDevices();
41 47
42 /// Load configuration settings. 48 /// Load configuration settings.
43 void LoadConfiguration(); 49 void LoadConfiguration();
@@ -48,6 +54,8 @@ private:
48 54
49 std::unique_ptr<Ui::ConfigureInput> ui; 55 std::unique_ptr<Ui::ConfigureInput> ui;
50 56
51 std::array<QComboBox*, 8> players_controller; 57 std::array<ConfigureInputPlayer*, 8> player_controllers;
52 std::array<QPushButton*, 8> players_configure; 58 std::array<QWidget*, 8> player_tabs;
59 std::array<QCheckBox*, 8> player_connected;
60 ConfigureInputAdvanced* advanced;
53}; 61};
diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui
index efffd8487..136955224 100644
--- a/src/yuzu/configuration/configure_input.ui
+++ b/src/yuzu/configuration/configure_input.ui
@@ -1,529 +1,554 @@
1<?xml version="1.0" encoding="UTF-8"?> 1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0"> 2<ui version="4.0">
3 <class>ConfigureInput</class> 3 <class>ConfigureInput</class>
4 <widget class="QDialog" name="ConfigureInput"> 4 <widget class="QWidget" name="ConfigureInput">
5 <property name="geometry"> 5 <property name="geometry">
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>384</width> 9 <width>700</width>
10 <height>576</height> 10 <height>540</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Custom Input Settings</string> 14 <string>ConfigureInput</string>
15 </property> 15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout_5"> 16 <layout class="QVBoxLayout" name="verticalLayout_5">
17 <property name="spacing">
18 <number>2</number>
19 </property>
20 <property name="leftMargin">
21 <number>3</number>
22 </property>
23 <property name="topMargin">
24 <number>3</number>
25 </property>
26 <property name="rightMargin">
27 <number>3</number>
28 </property>
29 <property name="bottomMargin">
30 <number>3</number>
31 </property>
17 <item> 32 <item>
18 <layout class="QVBoxLayout" name="verticalLayout"> 33 <widget class="QTabWidget" name="tabWidget">
19 <item> 34 <property name="currentIndex">
20 <widget class="QGroupBox" name="gridGroupBox_1"> 35 <number>0</number>
21 <property name="title"> 36 </property>
22 <string>Players</string> 37 <widget class="QWidget" name="tabPlayer1">
23 </property> 38 <property name="accessibleName">
24 <layout class="QGridLayout" name="gridLayout"> 39 <string>Player 1</string>
25 <item row="1" column="2"> 40 </property>
26 <widget class="QComboBox" name="player1_combobox"> 41 <attribute name="title">
27 <property name="minimumSize"> 42 <string>Player 1</string>
28 <size> 43 </attribute>
29 <width>110</width> 44 </widget>
30 <height>0</height> 45 <widget class="QWidget" name="tabPlayer2">
31 </size> 46 <property name="accessibleName">
32 </property> 47 <string>Player 2</string>
33 </widget> 48 </property>
34 </item> 49 <attribute name="title">
35 <item row="1" column="3"> 50 <string>Player 2</string>
36 <widget class="QPushButton" name="player1_configure"> 51 </attribute>
37 <property name="text"> 52 </widget>
38 <string>Configure</string> 53 <widget class="QWidget" name="tabPlayer3">
39 </property> 54 <property name="accessibleName">
40 </widget> 55 <string>Player 3</string>
41 </item> 56 </property>
42 <item row="0" column="2"> 57 <attribute name="title">
43 <widget class="QLabel" name="label"> 58 <string>Player 3</string>
44 <property name="text"> 59 </attribute>
45 <string>Controller Type</string> 60 </widget>
46 </property> 61 <widget class="QWidget" name="tabPlayer4">
47 <property name="alignment"> 62 <property name="accessibleName">
48 <set>Qt::AlignCenter</set> 63 <string>Player 4</string>
49 </property> 64 </property>
50 </widget> 65 <attribute name="title">
51 </item> 66 <string>Player 4</string>
52 <item row="2" column="2"> 67 </attribute>
53 <widget class="QComboBox" name="player2_combobox"> 68 </widget>
54 <property name="minimumSize"> 69 <widget class="QWidget" name="tabPlayer5">
55 <size> 70 <property name="accessibleName">
56 <width>110</width> 71 <string>Player 5</string>
57 <height>0</height> 72 </property>
58 </size> 73 <attribute name="title">
59 </property> 74 <string>Player 5</string>
60 </widget> 75 </attribute>
61 </item> 76 </widget>
62 <item row="3" column="2"> 77 <widget class="QWidget" name="tabPlayer6">
63 <widget class="QComboBox" name="player3_combobox"> 78 <property name="accessibleName">
64 <property name="minimumSize"> 79 <string>Player 6</string>
65 <size> 80 </property>
66 <width>110</width> 81 <attribute name="title">
67 <height>0</height> 82 <string>Player 6</string>
68 </size> 83 </attribute>
69 </property> 84 </widget>
70 </widget> 85 <widget class="QWidget" name="tabPlayer7">
71 </item> 86 <property name="accessibleName">
72 <item row="4" column="2"> 87 <string>Player 7</string>
73 <widget class="QComboBox" name="player4_combobox"> 88 </property>
74 <property name="minimumSize"> 89 <attribute name="title">
75 <size> 90 <string>Player 7</string>
76 <width>110</width> 91 </attribute>
77 <height>0</height> 92 </widget>
78 </size> 93 <widget class="QWidget" name="tabPlayer8">
79 </property> 94 <property name="accessibleName">
80 </widget> 95 <string>Player 8</string>
81 </item> 96 </property>
82 <item row="5" column="2"> 97 <attribute name="title">
83 <widget class="QComboBox" name="player5_combobox"> 98 <string>Player 8</string>
84 <property name="minimumSize"> 99 </attribute>
85 <size> 100 </widget>
86 <width>110</width> 101 <widget class="QWidget" name="tabAdvanced">
87 <height>0</height> 102 <property name="accessibleName">
88 </size> 103 <string>Advanced</string>
89 </property> 104 </property>
90 </widget> 105 <attribute name="title">
91 </item> 106 <string>Advanced</string>
92 <item row="6" column="2"> 107 </attribute>
93 <widget class="QComboBox" name="player6_combobox"> 108 </widget>
94 <property name="minimumSize"> 109 </widget>
95 <size> 110 </item>
96 <width>110</width> 111 <item alignment="Qt::AlignVCenter">
97 <height>0</height> 112 <widget class="QWidget" name="consoleInputSettings" native="true">
98 </size> 113 <layout class="QHBoxLayout" name="buttonsBottomRightHorizontalLayout">
99 </property> 114 <property name="spacing">
100 </widget> 115 <number>3</number>
101 </item> 116 </property>
102 <item row="7" column="2"> 117 <property name="leftMargin">
103 <widget class="QComboBox" name="player7_combobox"> 118 <number>0</number>
104 <property name="minimumSize"> 119 </property>
105 <size> 120 <property name="topMargin">
106 <width>110</width> 121 <number>3</number>
107 <height>0</height> 122 </property>
108 </size> 123 <property name="rightMargin">
109 </property> 124 <number>0</number>
110 </widget> 125 </property>
111 </item> 126 <property name="bottomMargin">
112 <item row="8" column="2"> 127 <number>0</number>
113 <widget class="QComboBox" name="player8_combobox"> 128 </property>
114 <property name="minimumSize"> 129 <item alignment="Qt::AlignVCenter">
115 <size> 130 <widget class="QGroupBox" name="handheldGroup">
116 <width>110</width> 131 <property name="maximumSize">
117 <height>0</height> 132 <size>
118 </size> 133 <width>16777215</width>
119 </property> 134 <height>16777215</height>
120 </widget> 135 </size>
121 </item> 136 </property>
122 <item row="2" column="3"> 137 <property name="title">
123 <widget class="QPushButton" name="player2_configure"> 138 <string>Console Mode</string>
124 <property name="text"> 139 </property>
125 <string>Configure</string> 140 <layout class="QHBoxLayout" name="horizontalLayout">
126 </property> 141 <property name="spacing">
127 </widget> 142 <number>6</number>
128 </item> 143 </property>
129 <item row="3" column="3"> 144 <property name="leftMargin">
130 <widget class="QPushButton" name="player3_configure"> 145 <number>3</number>
131 <property name="text"> 146 </property>
132 <string>Configure</string> 147 <property name="topMargin">
133 </property> 148 <number>6</number>
134 </widget> 149 </property>
135 </item> 150 <property name="rightMargin">
136 <item row="4" column="3"> 151 <number>3</number>
137 <widget class="QPushButton" name="player4_configure"> 152 </property>
138 <property name="text"> 153 <property name="bottomMargin">
139 <string>Configure</string> 154 <number>6</number>
140 </property> 155 </property>
141 </widget> 156 <item>
142 </item> 157 <widget class="QRadioButton" name="radioDocked">
143 <item row="5" column="3"> 158 <property name="text">
144 <widget class="QPushButton" name="player5_configure"> 159 <string>Docked</string>
145 <property name="text"> 160 </property>
146 <string>Configure</string> 161 <property name="checked">
147 </property> 162 <bool>true</bool>
148 </widget> 163 </property>
149 </item> 164 </widget>
150 <item row="6" column="3"> 165 </item>
151 <widget class="QPushButton" name="player6_configure"> 166 <item>
152 <property name="text"> 167 <widget class="QRadioButton" name="radioUndocked">
153 <string>Configure</string> 168 <property name="text">
154 </property> 169 <string>Undocked</string>
155 </widget> 170 </property>
156 </item> 171 </widget>
157 <item row="7" column="3"> 172 </item>
158 <widget class="QPushButton" name="player7_configure"> 173 </layout>
159 <property name="text"> 174 </widget>
160 <string>Configure</string> 175 </item>
161 </property> 176 <item>
162 </widget> 177 <widget class="QGroupBox" name="vibrationGroup">
163 </item> 178 <property name="title">
164 <item row="8" column="3"> 179 <string>Vibration</string>
165 <widget class="QPushButton" name="player8_configure"> 180 </property>
166 <property name="text"> 181 <property name="checkable">
167 <string>Configure</string> 182 <bool>true</bool>
168 </property> 183 </property>
169 </widget> 184 <layout class="QHBoxLayout" name="horizontalLayout_2">
170 </item> 185 <property name="leftMargin">
171 <item row="0" column="0"> 186 <number>3</number>
172 <spacer name="horizontalSpacer"> 187 </property>
173 <property name="orientation"> 188 <property name="topMargin">
174 <enum>Qt::Horizontal</enum> 189 <number>3</number>
175 </property> 190 </property>
176 <property name="sizeHint" stdset="0"> 191 <property name="rightMargin">
177 <size> 192 <number>3</number>
178 <width>40</width> 193 </property>
179 <height>20</height> 194 <property name="bottomMargin">
180 </size> 195 <number>3</number>
181 </property> 196 </property>
182 </spacer> 197 <item>
183 </item> 198 <widget class="QSpinBox" name="vibrationSpin">
184 <item row="0" column="4"> 199 <property name="minimumSize">
185 <spacer name="horizontalSpacer_2"> 200 <size>
186 <property name="orientation"> 201 <width>65</width>
187 <enum>Qt::Horizontal</enum> 202 <height>21</height>
188 </property> 203 </size>
189 <property name="sizeHint" stdset="0"> 204 </property>
190 <size> 205 <property name="maximumSize">
191 <width>40</width> 206 <size>
192 <height>20</height> 207 <width>65</width>
193 </size> 208 <height>16777215</height>
194 </property> 209 </size>
195 </spacer> 210 </property>
196 </item> 211 <property name="suffix">
197 <item row="1" column="1"> 212 <string>%</string>
198 <widget class="QLabel" name="label_3"> 213 </property>
199 <property name="minimumSize"> 214 <property name="minimum">
200 <size> 215 <number>1</number>
201 <width>55</width> 216 </property>
202 <height>0</height> 217 <property name="maximum">
203 </size> 218 <number>200</number>
204 </property> 219 </property>
205 <property name="text"> 220 <property name="value">
206 <string>Player 1</string> 221 <number>100</number>
207 </property> 222 </property>
208 </widget> 223 </widget>
209 </item> 224 </item>
210 <item row="2" column="1"> 225 </layout>
211 <widget class="QLabel" name="label_4"> 226 </widget>
212 <property name="text"> 227 </item>
213 <string>Player 2</string> 228 <item>
214 </property> 229 <widget class="QGroupBox" name="motionGroup">
215 </widget> 230 <property name="title">
216 </item> 231 <string>Motion</string>
217 <item row="3" column="1"> 232 </property>
218 <widget class="QLabel" name="label_5"> 233 <property name="checkable">
219 <property name="text"> 234 <bool>true</bool>
220 <string>Player 3</string> 235 </property>
221 </property> 236 <layout class="QHBoxLayout" name="horizontalLayout_3">
222 </widget> 237 <property name="leftMargin">
223 </item> 238 <number>3</number>
224 <item row="4" column="1"> 239 </property>
225 <widget class="QLabel" name="label_6"> 240 <property name="topMargin">
226 <property name="text"> 241 <number>3</number>
227 <string>Player 4</string> 242 </property>
228 </property> 243 <property name="rightMargin">
229 </widget> 244 <number>3</number>
230 </item> 245 </property>
231 <item row="5" column="1"> 246 <property name="bottomMargin">
232 <widget class="QLabel" name="label_7"> 247 <number>3</number>
233 <property name="text"> 248 </property>
234 <string>Player 5</string> 249 <item>
235 </property> 250 <widget class="QPushButton" name="motionButton">
236 </widget> 251 <property name="minimumSize">
237 </item> 252 <size>
238 <item row="6" column="1"> 253 <width>57</width>
239 <widget class="QLabel" name="label_8"> 254 <height>0</height>
240 <property name="text"> 255 </size>
241 <string>Player 6</string> 256 </property>
242 </property> 257 <property name="maximumSize">
243 </widget> 258 <size>
244 </item> 259 <width>55</width>
245 <item row="7" column="1"> 260 <height>16777215</height>
246 <widget class="QLabel" name="label_9"> 261 </size>
247 <property name="text"> 262 </property>
248 <string>Player 7</string> 263 <property name="styleSheet">
249 </property> 264 <string notr="true">min-width: 55px;</string>
250 </widget> 265 </property>
251 </item> 266 <property name="text">
252 <item row="8" column="1"> 267 <string>Configure</string>
253 <widget class="QLabel" name="label_10"> 268 </property>
254 <property name="text"> 269 </widget>
255 <string>Player 8</string> 270 </item>
256 </property> 271 </layout>
257 </widget> 272 </widget>
258 </item> 273 </item>
259 </layout> 274 <item alignment="Qt::AlignVCenter">
260 </widget> 275 <widget class="QWidget" name="widget" native="true">
261 </item> 276 <layout class="QGridLayout" name="gridLayout_2">
262 <item> 277 <property name="leftMargin">
263 <widget class="QGroupBox" name="gridGroupBox_2"> 278 <number>5</number>
264 <property name="title"> 279 </property>
265 <string>Handheld</string> 280 <property name="topMargin">
266 </property> 281 <number>0</number>
267 <layout class="QGridLayout" name="gridLayout_2">
268 <item row="1" column="2">
269 <spacer name="horizontalSpacer_5">
270 <property name="orientation">
271 <enum>Qt::Horizontal</enum>
272 </property>
273 <property name="sizeType">
274 <enum>QSizePolicy::Fixed</enum>
275 </property>
276 <property name="sizeHint" stdset="0">
277 <size>
278 <width>72</width>
279 <height>20</height>
280 </size>
281 </property>
282 </spacer>
283 </item>
284 <item row="1" column="4">
285 <spacer name="horizontalSpacer_4">
286 <property name="orientation">
287 <enum>Qt::Horizontal</enum>
288 </property>
289 <property name="sizeHint" stdset="0">
290 <size>
291 <width>40</width>
292 <height>20</height>
293 </size>
294 </property>
295 </spacer>
296 </item>
297 <item row="1" column="3">
298 <widget class="QPushButton" name="handheld_configure">
299 <property name="text">
300 <string>Configure</string>
301 </property>
302 </widget>
303 </item>
304 <item row="1" column="0">
305 <spacer name="horizontalSpacer_3">
306 <property name="orientation">
307 <enum>Qt::Horizontal</enum>
308 </property>
309 <property name="sizeHint" stdset="0">
310 <size>
311 <width>40</width>
312 <height>20</height>
313 </size>
314 </property>
315 </spacer>
316 </item>
317 <item row="1" column="1">
318 <widget class="QCheckBox" name="handheld_connected">
319 <property name="text">
320 <string>Joycons Docked</string>
321 </property>
322 </widget>
323 </item>
324 <item row="0" column="1">
325 <widget class="QCheckBox" name="use_docked_mode">
326 <property name="text">
327 <string>Use Docked Mode</string>
328 </property>
329 </widget>
330 </item>
331 </layout>
332 </widget>
333 </item>
334 <item>
335 <widget class="QGroupBox" name="gridGroupBox_3">
336 <property name="title">
337 <string>Other</string>
338 </property>
339 <layout class="QGridLayout" name="gridLayout_3">
340 <item row="1" column="1">
341 <widget class="QCheckBox" name="keyboard_enabled">
342 <property name="minimumSize">
343 <size>
344 <width>0</width>
345 <height>23</height>
346 </size>
347 </property>
348 <property name="text">
349 <string>Keyboard</string>
350 </property>
351 </widget>
352 </item>
353 <item row="2" column="1">
354 <widget class="QCheckBox" name="debug_enabled">
355 <property name="text">
356 <string>Debug Controller</string>
357 </property>
358 </widget>
359 </item>
360 <item row="3" column="1">
361 <widget class="QCheckBox" name="touchscreen_enabled">
362 <property name="text">
363 <string>Touchscreen</string>
364 </property>
365 </widget>
366 </item>
367 <item row="0" column="1">
368 <widget class="QCheckBox" name="mouse_enabled">
369 <property name="minimumSize">
370 <size>
371 <width>0</width>
372 <height>23</height>
373 </size>
374 </property>
375 <property name="text">
376 <string>Mouse</string>
377 </property>
378 </widget>
379 </item>
380 <item row="0" column="4">
381 <spacer name="horizontalSpacer_7">
382 <property name="orientation">
383 <enum>Qt::Horizontal</enum>
384 </property>
385 <property name="sizeHint" stdset="0">
386 <size>
387 <width>40</width>
388 <height>20</height>
389 </size>
390 </property>
391 </spacer>
392 </item>
393 <item row="0" column="2">
394 <spacer name="horizontalSpacer_8">
395 <property name="orientation">
396 <enum>Qt::Horizontal</enum>
397 </property>
398 <property name="sizeType">
399 <enum>QSizePolicy::Fixed</enum>
400 </property>
401 <property name="sizeHint" stdset="0">
402 <size>
403 <width>76</width>
404 <height>20</height>
405 </size>
406 </property>
407 </spacer>
408 </item>
409 <item row="0" column="0">
410 <spacer name="horizontalSpacer_6">
411 <property name="orientation">
412 <enum>Qt::Horizontal</enum>
413 </property>
414 <property name="sizeHint" stdset="0">
415 <size>
416 <width>40</width>
417 <height>20</height>
418 </size>
419 </property>
420 </spacer>
421 </item>
422 <item row="3" column="3">
423 <widget class="QPushButton" name="touchscreen_advanced">
424 <property name="text">
425 <string>Advanced</string>
426 </property>
427 </widget>
428 </item>
429 <item row="2" column="3">
430 <widget class="QPushButton" name="debug_configure">
431 <property name="text">
432 <string>Configure</string>
433 </property>
434 </widget>
435 </item>
436 <item row="0" column="3">
437 <widget class="QPushButton" name="mouse_advanced">
438 <property name="text">
439 <string>Advanced</string>
440 </property>
441 </widget>
442 </item>
443 </layout>
444 </widget>
445 </item>
446 <item>
447 <spacer name="verticalSpacer">
448 <property name="orientation">
449 <enum>Qt::Vertical</enum>
450 </property>
451 <property name="sizeHint" stdset="0">
452 <size>
453 <width>20</width>
454 <height>40</height>
455 </size>
456 </property>
457 </spacer>
458 </item>
459 <item>
460 <layout class="QHBoxLayout" name="horizontalLayout">
461 <item>
462 <widget class="QPushButton" name="restore_defaults_button">
463 <property name="text">
464 <string>Restore Defaults</string>
465 </property> 282 </property>
466 </widget> 283 <property name="rightMargin">
467 </item> 284 <number>0</number>
468 <item>
469 <spacer name="horizontalSpacer_9">
470 <property name="orientation">
471 <enum>Qt::Horizontal</enum>
472 </property> 285 </property>
473 <property name="sizeHint" stdset="0"> 286 <property name="bottomMargin">
474 <size> 287 <number>0</number>
475 <width>40</width>
476 <height>20</height>
477 </size>
478 </property> 288 </property>
479 </spacer> 289 <property name="spacing">
480 </item> 290 <number>3</number>
481 <item>
482 <widget class="QDialogButtonBox" name="buttonBox">
483 <property name="standardButtons">
484 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
485 </property> 291 </property>
486 </widget> 292 <item row="1" column="2">
487 </item> 293 <widget class="QCheckBox" name="checkboxPlayer2Connected">
488 </layout> 294 <property name="text">
489 </item> 295 <string/>
490 </layout> 296 </property>
297 </widget>
298 </item>
299 <item row="1" column="0">
300 <widget class="QLabel" name="label_2">
301 <property name="text">
302 <string>Controllers</string>
303 </property>
304 </widget>
305 </item>
306 <item row="1" column="4">
307 <widget class="QCheckBox" name="checkboxPlayer4Connected">
308 <property name="text">
309 <string/>
310 </property>
311 </widget>
312 </item>
313 <item row="1" column="3">
314 <widget class="QCheckBox" name="checkboxPlayer3Connected">
315 <property name="text">
316 <string/>
317 </property>
318 </widget>
319 </item>
320 <item row="1" column="5">
321 <widget class="QCheckBox" name="checkboxPlayer5Connected">
322 <property name="text">
323 <string/>
324 </property>
325 </widget>
326 </item>
327 <item row="0" column="1">
328 <widget class="QLabel" name="label">
329 <property name="text">
330 <string>1</string>
331 </property>
332 <property name="alignment">
333 <set>Qt::AlignCenter</set>
334 </property>
335 </widget>
336 </item>
337 <item row="1" column="7">
338 <widget class="QCheckBox" name="checkboxPlayer7Connected">
339 <property name="text">
340 <string/>
341 </property>
342 </widget>
343 </item>
344 <item row="1" column="6">
345 <widget class="QCheckBox" name="checkboxPlayer6Connected">
346 <property name="text">
347 <string/>
348 </property>
349 </widget>
350 </item>
351 <item row="1" column="1">
352 <widget class="QCheckBox" name="checkboxPlayer1Connected">
353 <property name="layoutDirection">
354 <enum>Qt::LeftToRight</enum>
355 </property>
356 <property name="checked">
357 <bool>true</bool>
358 </property>
359 </widget>
360 </item>
361 <item row="1" column="8">
362 <widget class="QCheckBox" name="checkboxPlayer8Connected">
363 <property name="text">
364 <string/>
365 </property>
366 </widget>
367 </item>
368 <item row="0" column="2">
369 <widget class="QLabel" name="label_3">
370 <property name="text">
371 <string>2</string>
372 </property>
373 <property name="alignment">
374 <set>Qt::AlignCenter</set>
375 </property>
376 </widget>
377 </item>
378 <item row="0" column="3">
379 <widget class="QLabel" name="label_4">
380 <property name="text">
381 <string>3</string>
382 </property>
383 <property name="alignment">
384 <set>Qt::AlignCenter</set>
385 </property>
386 </widget>
387 </item>
388 <item row="0" column="4">
389 <widget class="QLabel" name="label_5">
390 <property name="text">
391 <string>4</string>
392 </property>
393 <property name="alignment">
394 <set>Qt::AlignCenter</set>
395 </property>
396 </widget>
397 </item>
398 <item row="0" column="5">
399 <widget class="QLabel" name="label_6">
400 <property name="text">
401 <string>5</string>
402 </property>
403 <property name="alignment">
404 <set>Qt::AlignCenter</set>
405 </property>
406 </widget>
407 </item>
408 <item row="0" column="6">
409 <widget class="QLabel" name="label_7">
410 <property name="text">
411 <string>6</string>
412 </property>
413 <property name="alignment">
414 <set>Qt::AlignCenter</set>
415 </property>
416 </widget>
417 </item>
418 <item row="0" column="7">
419 <widget class="QLabel" name="label_8">
420 <property name="text">
421 <string>7</string>
422 </property>
423 <property name="alignment">
424 <set>Qt::AlignCenter</set>
425 </property>
426 </widget>
427 </item>
428 <item row="0" column="8">
429 <widget class="QLabel" name="label_9">
430 <property name="text">
431 <string>8</string>
432 </property>
433 <property name="alignment">
434 <set>Qt::AlignCenter</set>
435 </property>
436 </widget>
437 </item>
438 <item row="0" column="0">
439 <widget class="QLabel" name="label_10">
440 <property name="text">
441 <string>Connected</string>
442 </property>
443 </widget>
444 </item>
445 </layout>
446 </widget>
447 </item>
448 <item>
449 <spacer name="horizontalSpacer">
450 <property name="orientation">
451 <enum>Qt::Horizontal</enum>
452 </property>
453 <property name="sizeHint" stdset="0">
454 <size>
455 <width>40</width>
456 <height>20</height>
457 </size>
458 </property>
459 </spacer>
460 </item>
461 <item alignment="Qt::AlignBottom">
462 <widget class="QPushButton" name="buttonRestoreDefaults">
463 <property name="sizePolicy">
464 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
465 <horstretch>0</horstretch>
466 <verstretch>0</verstretch>
467 </sizepolicy>
468 </property>
469 <property name="minimumSize">
470 <size>
471 <width>57</width>
472 <height>0</height>
473 </size>
474 </property>
475 <property name="maximumSize">
476 <size>
477 <width>55</width>
478 <height>16777215</height>
479 </size>
480 </property>
481 <property name="sizeIncrement">
482 <size>
483 <width>0</width>
484 <height>0</height>
485 </size>
486 </property>
487 <property name="baseSize">
488 <size>
489 <width>0</width>
490 <height>0</height>
491 </size>
492 </property>
493 <property name="layoutDirection">
494 <enum>Qt::LeftToRight</enum>
495 </property>
496 <property name="styleSheet">
497 <string notr="true">min-width: 55px;</string>
498 </property>
499 <property name="text">
500 <string>Defaults</string>
501 </property>
502 </widget>
503 </item>
504 <item alignment="Qt::AlignBottom">
505 <widget class="QPushButton" name="buttonClearAll">
506 <property name="sizePolicy">
507 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
508 <horstretch>0</horstretch>
509 <verstretch>0</verstretch>
510 </sizepolicy>
511 </property>
512 <property name="minimumSize">
513 <size>
514 <width>57</width>
515 <height>0</height>
516 </size>
517 </property>
518 <property name="maximumSize">
519 <size>
520 <width>55</width>
521 <height>16777215</height>
522 </size>
523 </property>
524 <property name="sizeIncrement">
525 <size>
526 <width>0</width>
527 <height>0</height>
528 </size>
529 </property>
530 <property name="baseSize">
531 <size>
532 <width>0</width>
533 <height>0</height>
534 </size>
535 </property>
536 <property name="layoutDirection">
537 <enum>Qt::LeftToRight</enum>
538 </property>
539 <property name="styleSheet">
540 <string notr="true">min-width: 55px;</string>
541 </property>
542 <property name="text">
543 <string>Clear</string>
544 </property>
545 </widget>
546 </item>
547 </layout>
548 </widget>
491 </item> 549 </item>
492 </layout> 550 </layout>
493 </widget> 551 </widget>
494 <resources/> 552 <resources/>
495 <connections> 553 <connections/>
496 <connection>
497 <sender>buttonBox</sender>
498 <signal>accepted()</signal>
499 <receiver>ConfigureInput</receiver>
500 <slot>accept()</slot>
501 <hints>
502 <hint type="sourcelabel">
503 <x>294</x>
504 <y>553</y>
505 </hint>
506 <hint type="destinationlabel">
507 <x>191</x>
508 <y>287</y>
509 </hint>
510 </hints>
511 </connection>
512 <connection>
513 <sender>buttonBox</sender>
514 <signal>rejected()</signal>
515 <receiver>ConfigureInput</receiver>
516 <slot>reject()</slot>
517 <hints>
518 <hint type="sourcelabel">
519 <x>294</x>
520 <y>553</y>
521 </hint>
522 <hint type="destinationlabel">
523 <x>191</x>
524 <y>287</y>
525 </hint>
526 </hints>
527 </connection>
528 </connections>
529</ui> 554</ui>
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
new file mode 100644
index 000000000..18db04e7e
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -0,0 +1,169 @@
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 <QColorDialog>
6#include "core/core.h"
7#include "core/settings.h"
8#include "ui_configure_input_advanced.h"
9#include "yuzu/configuration/configure_input_advanced.h"
10
11ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent)
12 : QWidget(parent), ui(new Ui::ConfigureInputAdvanced) {
13 ui->setupUi(this);
14
15 controllers_color_buttons = {{
16 {
17 ui->player1_left_body_button,
18 ui->player1_left_buttons_button,
19 ui->player1_right_body_button,
20 ui->player1_right_buttons_button,
21 },
22 {
23 ui->player2_left_body_button,
24 ui->player2_left_buttons_button,
25 ui->player2_right_body_button,
26 ui->player2_right_buttons_button,
27 },
28 {
29 ui->player3_left_body_button,
30 ui->player3_left_buttons_button,
31 ui->player3_right_body_button,
32 ui->player3_right_buttons_button,
33 },
34 {
35 ui->player4_left_body_button,
36 ui->player4_left_buttons_button,
37 ui->player4_right_body_button,
38 ui->player4_right_buttons_button,
39 },
40 {
41 ui->player5_left_body_button,
42 ui->player5_left_buttons_button,
43 ui->player5_right_body_button,
44 ui->player5_right_buttons_button,
45 },
46 {
47 ui->player6_left_body_button,
48 ui->player6_left_buttons_button,
49 ui->player6_right_body_button,
50 ui->player6_right_buttons_button,
51 },
52 {
53 ui->player7_left_body_button,
54 ui->player7_left_buttons_button,
55 ui->player7_right_body_button,
56 ui->player7_right_buttons_button,
57 },
58 {
59 ui->player8_left_body_button,
60 ui->player8_left_buttons_button,
61 ui->player8_right_body_button,
62 ui->player8_right_buttons_button,
63 },
64 }};
65
66 for (std::size_t player_idx = 0; player_idx < controllers_color_buttons.size(); ++player_idx) {
67 auto& color_buttons = controllers_color_buttons[player_idx];
68 for (std::size_t button_idx = 0; button_idx < color_buttons.size(); ++button_idx) {
69 connect(color_buttons[button_idx], &QPushButton::clicked, this,
70 [this, player_idx, button_idx] {
71 OnControllerButtonClick(static_cast<int>(player_idx),
72 static_cast<int>(button_idx));
73 });
74 }
75 }
76
77 connect(ui->mouse_enabled, &QCheckBox::stateChanged, this,
78 &ConfigureInputAdvanced::UpdateUIEnabled);
79 connect(ui->debug_enabled, &QCheckBox::stateChanged, this,
80 &ConfigureInputAdvanced::UpdateUIEnabled);
81 connect(ui->touchscreen_enabled, &QCheckBox::stateChanged, this,
82 &ConfigureInputAdvanced::UpdateUIEnabled);
83
84 connect(ui->debug_configure, &QPushButton::clicked, this,
85 [this] { CallDebugControllerDialog(); });
86 connect(ui->mouse_advanced, &QPushButton::clicked, this, [this] { CallMouseConfigDialog(); });
87 connect(ui->touchscreen_advanced, &QPushButton::clicked, this,
88 [this] { CallTouchscreenConfigDialog(); });
89
90 LoadConfiguration();
91}
92
93ConfigureInputAdvanced::~ConfigureInputAdvanced() = default;
94
95void ConfigureInputAdvanced::OnControllerButtonClick(int player_idx, int button_idx) {
96 const QColor new_bg_color = QColorDialog::getColor(controllers_colors[player_idx][button_idx]);
97 if (!new_bg_color.isValid()) {
98 return;
99 }
100 controllers_colors[player_idx][button_idx] = new_bg_color;
101 controllers_color_buttons[player_idx][button_idx]->setStyleSheet(
102 QStringLiteral("background-color: %1; min-width: 55px;")
103 .arg(controllers_colors[player_idx][button_idx].name()));
104}
105
106void ConfigureInputAdvanced::ApplyConfiguration() {
107 for (std::size_t player_idx = 0; player_idx < controllers_color_buttons.size(); ++player_idx) {
108 auto& player = Settings::values.players[player_idx];
109 std::array<u32, 4> colors{};
110 std::transform(controllers_colors[player_idx].begin(), controllers_colors[player_idx].end(),
111 colors.begin(), [](QColor color) { return color.rgb(); });
112
113 player.body_color_left = colors[0];
114 player.button_color_left = colors[1];
115 player.body_color_right = colors[2];
116 player.button_color_right = colors[3];
117 }
118
119 Settings::values.debug_pad_enabled = ui->debug_enabled->isChecked();
120 Settings::values.mouse_enabled = ui->mouse_enabled->isChecked();
121 Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked();
122 Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
123}
124
125void ConfigureInputAdvanced::LoadConfiguration() {
126 for (std::size_t player_idx = 0; player_idx < controllers_color_buttons.size(); ++player_idx) {
127 auto& player = Settings::values.players[player_idx];
128 std::array<u32, 4> colors = {
129 player.body_color_left,
130 player.button_color_left,
131 player.body_color_right,
132 player.button_color_right,
133 };
134
135 std::transform(colors.begin(), colors.end(), controllers_colors[player_idx].begin(),
136 [](u32 rgb) { return QColor::fromRgb(rgb); });
137
138 for (std::size_t button_idx = 0; button_idx < colors.size(); ++button_idx) {
139 controllers_color_buttons[player_idx][button_idx]->setStyleSheet(
140 QStringLiteral("background-color: %1; min-width: 55px;")
141 .arg(controllers_colors[player_idx][button_idx].name()));
142 }
143 }
144
145 ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled);
146 ui->mouse_enabled->setChecked(Settings::values.mouse_enabled);
147 ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
148 ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
149
150 UpdateUIEnabled();
151}
152
153void ConfigureInputAdvanced::changeEvent(QEvent* event) {
154 if (event->type() == QEvent::LanguageChange) {
155 RetranslateUI();
156 }
157
158 QWidget::changeEvent(event);
159}
160
161void ConfigureInputAdvanced::RetranslateUI() {
162 ui->retranslateUi(this);
163}
164
165void ConfigureInputAdvanced::UpdateUIEnabled() {
166 ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked());
167 ui->debug_configure->setEnabled(ui->debug_enabled->isChecked());
168 ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked());
169}
diff --git a/src/yuzu/configuration/configure_input_advanced.h b/src/yuzu/configuration/configure_input_advanced.h
new file mode 100644
index 000000000..d6e913675
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_advanced.h
@@ -0,0 +1,44 @@
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 <QWidget>
9
10class QColor;
11class QPushButton;
12
13namespace Ui {
14class ConfigureInputAdvanced;
15}
16
17class ConfigureInputAdvanced : public QWidget {
18 Q_OBJECT
19
20public:
21 explicit ConfigureInputAdvanced(QWidget* parent = nullptr);
22 ~ConfigureInputAdvanced() override;
23
24 void ApplyConfiguration();
25
26signals:
27 void CallDebugControllerDialog();
28 void CallMouseConfigDialog();
29 void CallTouchscreenConfigDialog();
30
31private:
32 void changeEvent(QEvent* event) override;
33 void RetranslateUI();
34 void UpdateUIEnabled();
35
36 void OnControllerButtonClick(int player_idx, int button_idx);
37
38 void LoadConfiguration();
39
40 std::unique_ptr<Ui::ConfigureInputAdvanced> ui;
41
42 std::array<std::array<QColor, 4>, 8> controllers_colors;
43 std::array<std::array<QPushButton*, 4>, 8> controllers_color_buttons;
44};
diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui
new file mode 100644
index 000000000..5958435fc
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_advanced.ui
@@ -0,0 +1,2688 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureInputAdvanced</class>
4 <widget class="QWidget" name="ConfigureInputAdvanced">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>710</width>
10 <height>580</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Configure Input</string>
15 </property>
16 <property name="styleSheet">
17 <string notr="true"/>
18 </property>
19 <layout class="QHBoxLayout" name="horizontalLayout">
20 <property name="spacing">
21 <number>0</number>
22 </property>
23 <property name="leftMargin">
24 <number>0</number>
25 </property>
26 <property name="topMargin">
27 <number>0</number>
28 </property>
29 <property name="rightMargin">
30 <number>0</number>
31 </property>
32 <property name="bottomMargin">
33 <number>0</number>
34 </property>
35 <item>
36 <widget class="QWidget" name="mainInputAdvanced" native="true">
37 <layout class="QHBoxLayout" name="main" stretch="1,1">
38 <property name="spacing">
39 <number>9</number>
40 </property>
41 <property name="leftMargin">
42 <number>0</number>
43 </property>
44 <property name="topMargin">
45 <number>0</number>
46 </property>
47 <property name="rightMargin">
48 <number>0</number>
49 </property>
50 <property name="bottomMargin">
51 <number>0</number>
52 </property>
53 <item>
54 <widget class="QWidget" name="leftInputAdvanced" native="true">
55 <layout class="QVBoxLayout" name="leftLayout" stretch="0">
56 <property name="spacing">
57 <number>3</number>
58 </property>
59 <property name="leftMargin">
60 <number>0</number>
61 </property>
62 <property name="topMargin">
63 <number>0</number>
64 </property>
65 <property name="rightMargin">
66 <number>0</number>
67 </property>
68 <property name="bottomMargin">
69 <number>0</number>
70 </property>
71 <item>
72 <widget class="QGroupBox" name="joyconColorsGroup">
73 <property name="title">
74 <string>Joycon Colors</string>
75 </property>
76 <layout class="QVBoxLayout" name="verticalLayout_3" stretch="1,1">
77 <property name="leftMargin">
78 <number>9</number>
79 </property>
80 <property name="topMargin">
81 <number>9</number>
82 </property>
83 <property name="rightMargin">
84 <number>9</number>
85 </property>
86 <property name="bottomMargin">
87 <number>9</number>
88 </property>
89 <item>
90 <widget class="QWidget" name="topLeftInputAdvanced" native="true">
91 <layout class="QVBoxLayout" name="verticalLayout_4">
92 <property name="spacing">
93 <number>6</number>
94 </property>
95 <property name="leftMargin">
96 <number>0</number>
97 </property>
98 <property name="topMargin">
99 <number>0</number>
100 </property>
101 <property name="rightMargin">
102 <number>0</number>
103 </property>
104 <property name="bottomMargin">
105 <number>0</number>
106 </property>
107 <item>
108 <widget class="QWidget" name="player12Widget" native="true">
109 <layout class="QHBoxLayout" name="horizontalLayout_4">
110 <property name="leftMargin">
111 <number>0</number>
112 </property>
113 <property name="topMargin">
114 <number>0</number>
115 </property>
116 <property name="rightMargin">
117 <number>0</number>
118 </property>
119 <property name="bottomMargin">
120 <number>0</number>
121 </property>
122 <item>
123 <widget class="QGroupBox" name="player1Group">
124 <property name="title">
125 <string>Player 1</string>
126 </property>
127 <layout class="QHBoxLayout" name="horizontalLayout_2">
128 <property name="spacing">
129 <number>6</number>
130 </property>
131 <property name="leftMargin">
132 <number>6</number>
133 </property>
134 <property name="topMargin">
135 <number>0</number>
136 </property>
137 <property name="rightMargin">
138 <number>6</number>
139 </property>
140 <property name="bottomMargin">
141 <number>6</number>
142 </property>
143 <item>
144 <widget class="QWidget" name="player1LeftJoycon" native="true">
145 <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_14">
146 <property name="spacing">
147 <number>0</number>
148 </property>
149 <property name="leftMargin">
150 <number>0</number>
151 </property>
152 <property name="topMargin">
153 <number>0</number>
154 </property>
155 <property name="rightMargin">
156 <number>0</number>
157 </property>
158 <property name="bottomMargin">
159 <number>0</number>
160 </property>
161 <item alignment="Qt::AlignHCenter">
162 <widget class="QGroupBox" name="player1LeftBodyGroup">
163 <property name="title">
164 <string>L Body</string>
165 </property>
166 <property name="alignment">
167 <set>Qt::AlignCenter</set>
168 </property>
169 <layout class="QVBoxLayout" name="verticalLayout_66">
170 <property name="spacing">
171 <number>3</number>
172 </property>
173 <property name="leftMargin">
174 <number>3</number>
175 </property>
176 <property name="topMargin">
177 <number>3</number>
178 </property>
179 <property name="rightMargin">
180 <number>3</number>
181 </property>
182 <property name="bottomMargin">
183 <number>3</number>
184 </property>
185 <item>
186 <widget class="QPushButton" name="player1_left_body_button">
187 <property name="sizePolicy">
188 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
189 <horstretch>0</horstretch>
190 <verstretch>0</verstretch>
191 </sizepolicy>
192 </property>
193 <property name="minimumSize">
194 <size>
195 <width>57</width>
196 <height>0</height>
197 </size>
198 </property>
199 <property name="maximumSize">
200 <size>
201 <width>55</width>
202 <height>16777215</height>
203 </size>
204 </property>
205 <property name="styleSheet">
206 <string notr="true">min-width: 55px;</string>
207 </property>
208 <property name="text">
209 <string/>
210 </property>
211 </widget>
212 </item>
213 </layout>
214 </widget>
215 </item>
216 <item alignment="Qt::AlignHCenter">
217 <widget class="QGroupBox" name="player1LeftButtonsGroup">
218 <property name="title">
219 <string>L Button</string>
220 </property>
221 <property name="alignment">
222 <set>Qt::AlignCenter</set>
223 </property>
224 <layout class="QVBoxLayout" name="verticalLayout_67">
225 <property name="spacing">
226 <number>3</number>
227 </property>
228 <property name="leftMargin">
229 <number>3</number>
230 </property>
231 <property name="topMargin">
232 <number>3</number>
233 </property>
234 <property name="rightMargin">
235 <number>3</number>
236 </property>
237 <property name="bottomMargin">
238 <number>3</number>
239 </property>
240 <item>
241 <widget class="QPushButton" name="player1_left_buttons_button">
242 <property name="sizePolicy">
243 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
244 <horstretch>0</horstretch>
245 <verstretch>0</verstretch>
246 </sizepolicy>
247 </property>
248 <property name="minimumSize">
249 <size>
250 <width>57</width>
251 <height>0</height>
252 </size>
253 </property>
254 <property name="maximumSize">
255 <size>
256 <width>55</width>
257 <height>16777215</height>
258 </size>
259 </property>
260 <property name="styleSheet">
261 <string notr="true">min-width: 55px;</string>
262 </property>
263 <property name="text">
264 <string/>
265 </property>
266 </widget>
267 </item>
268 </layout>
269 </widget>
270 </item>
271 </layout>
272 </widget>
273 </item>
274 <item>
275 <widget class="QWidget" name="player1RightJoycon" native="true">
276 <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_14">
277 <property name="spacing">
278 <number>0</number>
279 </property>
280 <property name="leftMargin">
281 <number>0</number>
282 </property>
283 <property name="topMargin">
284 <number>0</number>
285 </property>
286 <property name="rightMargin">
287 <number>0</number>
288 </property>
289 <property name="bottomMargin">
290 <number>0</number>
291 </property>
292 <item alignment="Qt::AlignHCenter">
293 <widget class="QGroupBox" name="player1RightBodyGroup">
294 <property name="title">
295 <string>R Body</string>
296 </property>
297 <property name="alignment">
298 <set>Qt::AlignCenter</set>
299 </property>
300 <layout class="QVBoxLayout" name="verticalLayout_64">
301 <property name="spacing">
302 <number>3</number>
303 </property>
304 <property name="leftMargin">
305 <number>3</number>
306 </property>
307 <property name="topMargin">
308 <number>3</number>
309 </property>
310 <property name="rightMargin">
311 <number>3</number>
312 </property>
313 <property name="bottomMargin">
314 <number>3</number>
315 </property>
316 <item>
317 <widget class="QPushButton" name="player1_right_body_button">
318 <property name="sizePolicy">
319 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
320 <horstretch>0</horstretch>
321 <verstretch>0</verstretch>
322 </sizepolicy>
323 </property>
324 <property name="minimumSize">
325 <size>
326 <width>57</width>
327 <height>0</height>
328 </size>
329 </property>
330 <property name="maximumSize">
331 <size>
332 <width>55</width>
333 <height>16777215</height>
334 </size>
335 </property>
336 <property name="styleSheet">
337 <string notr="true">min-width: 55px;</string>
338 </property>
339 <property name="text">
340 <string/>
341 </property>
342 </widget>
343 </item>
344 </layout>
345 </widget>
346 </item>
347 <item alignment="Qt::AlignHCenter">
348 <widget class="QGroupBox" name="player1RightButtonsGroup">
349 <property name="title">
350 <string>R Button</string>
351 </property>
352 <property name="alignment">
353 <set>Qt::AlignCenter</set>
354 </property>
355 <layout class="QVBoxLayout" name="verticalLayout_65">
356 <property name="spacing">
357 <number>3</number>
358 </property>
359 <property name="leftMargin">
360 <number>3</number>
361 </property>
362 <property name="topMargin">
363 <number>3</number>
364 </property>
365 <property name="rightMargin">
366 <number>3</number>
367 </property>
368 <property name="bottomMargin">
369 <number>3</number>
370 </property>
371 <item>
372 <widget class="QPushButton" name="player1_right_buttons_button">
373 <property name="sizePolicy">
374 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
375 <horstretch>0</horstretch>
376 <verstretch>0</verstretch>
377 </sizepolicy>
378 </property>
379 <property name="minimumSize">
380 <size>
381 <width>57</width>
382 <height>0</height>
383 </size>
384 </property>
385 <property name="maximumSize">
386 <size>
387 <width>55</width>
388 <height>16777215</height>
389 </size>
390 </property>
391 <property name="styleSheet">
392 <string notr="true">min-width: 55px;</string>
393 </property>
394 <property name="text">
395 <string/>
396 </property>
397 </widget>
398 </item>
399 </layout>
400 </widget>
401 </item>
402 </layout>
403 </widget>
404 </item>
405 </layout>
406 </widget>
407 </item>
408 <item>
409 <widget class="QGroupBox" name="player2Group">
410 <property name="title">
411 <string>Player 2</string>
412 </property>
413 <layout class="QHBoxLayout" name="horizontalLayout_14">
414 <property name="spacing">
415 <number>6</number>
416 </property>
417 <property name="leftMargin">
418 <number>6</number>
419 </property>
420 <property name="topMargin">
421 <number>0</number>
422 </property>
423 <property name="rightMargin">
424 <number>6</number>
425 </property>
426 <property name="bottomMargin">
427 <number>6</number>
428 </property>
429 <item>
430 <widget class="QWidget" name="player2LeftJoycon" native="true">
431 <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_15">
432 <property name="spacing">
433 <number>0</number>
434 </property>
435 <property name="leftMargin">
436 <number>0</number>
437 </property>
438 <property name="topMargin">
439 <number>0</number>
440 </property>
441 <property name="rightMargin">
442 <number>0</number>
443 </property>
444 <property name="bottomMargin">
445 <number>0</number>
446 </property>
447 <item alignment="Qt::AlignHCenter">
448 <widget class="QGroupBox" name="player2LeftBodyGroup">
449 <property name="title">
450 <string>L Body</string>
451 </property>
452 <property name="alignment">
453 <set>Qt::AlignCenter</set>
454 </property>
455 <layout class="QVBoxLayout" name="verticalLayout_70">
456 <property name="spacing">
457 <number>3</number>
458 </property>
459 <property name="leftMargin">
460 <number>3</number>
461 </property>
462 <property name="topMargin">
463 <number>3</number>
464 </property>
465 <property name="rightMargin">
466 <number>3</number>
467 </property>
468 <property name="bottomMargin">
469 <number>3</number>
470 </property>
471 <item>
472 <widget class="QPushButton" name="player2_left_body_button">
473 <property name="sizePolicy">
474 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
475 <horstretch>0</horstretch>
476 <verstretch>0</verstretch>
477 </sizepolicy>
478 </property>
479 <property name="minimumSize">
480 <size>
481 <width>57</width>
482 <height>0</height>
483 </size>
484 </property>
485 <property name="maximumSize">
486 <size>
487 <width>55</width>
488 <height>16777215</height>
489 </size>
490 </property>
491 <property name="styleSheet">
492 <string notr="true">min-width: 55px;</string>
493 </property>
494 <property name="text">
495 <string/>
496 </property>
497 </widget>
498 </item>
499 </layout>
500 </widget>
501 </item>
502 <item alignment="Qt::AlignHCenter">
503 <widget class="QGroupBox" name="player2LeftButtonsGroup">
504 <property name="title">
505 <string>L Button</string>
506 </property>
507 <property name="alignment">
508 <set>Qt::AlignCenter</set>
509 </property>
510 <layout class="QVBoxLayout" name="verticalLayout_71">
511 <property name="spacing">
512 <number>3</number>
513 </property>
514 <property name="leftMargin">
515 <number>3</number>
516 </property>
517 <property name="topMargin">
518 <number>3</number>
519 </property>
520 <property name="rightMargin">
521 <number>3</number>
522 </property>
523 <property name="bottomMargin">
524 <number>3</number>
525 </property>
526 <item>
527 <widget class="QPushButton" name="player2_left_buttons_button">
528 <property name="sizePolicy">
529 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
530 <horstretch>0</horstretch>
531 <verstretch>0</verstretch>
532 </sizepolicy>
533 </property>
534 <property name="minimumSize">
535 <size>
536 <width>57</width>
537 <height>0</height>
538 </size>
539 </property>
540 <property name="maximumSize">
541 <size>
542 <width>55</width>
543 <height>16777215</height>
544 </size>
545 </property>
546 <property name="styleSheet">
547 <string notr="true">min-width: 55px;</string>
548 </property>
549 <property name="text">
550 <string/>
551 </property>
552 </widget>
553 </item>
554 </layout>
555 </widget>
556 </item>
557 </layout>
558 </widget>
559 </item>
560 <item>
561 <widget class="QWidget" name="player2RightJoycon" native="true">
562 <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_15">
563 <property name="spacing">
564 <number>0</number>
565 </property>
566 <property name="leftMargin">
567 <number>0</number>
568 </property>
569 <property name="topMargin">
570 <number>0</number>
571 </property>
572 <property name="rightMargin">
573 <number>0</number>
574 </property>
575 <property name="bottomMargin">
576 <number>0</number>
577 </property>
578 <item alignment="Qt::AlignHCenter">
579 <widget class="QGroupBox" name="player2RightBodyGroup">
580 <property name="title">
581 <string>R Body</string>
582 </property>
583 <property name="alignment">
584 <set>Qt::AlignCenter</set>
585 </property>
586 <layout class="QVBoxLayout" name="verticalLayout_68">
587 <property name="spacing">
588 <number>3</number>
589 </property>
590 <property name="leftMargin">
591 <number>3</number>
592 </property>
593 <property name="topMargin">
594 <number>3</number>
595 </property>
596 <property name="rightMargin">
597 <number>3</number>
598 </property>
599 <property name="bottomMargin">
600 <number>3</number>
601 </property>
602 <item>
603 <widget class="QPushButton" name="player2_right_body_button">
604 <property name="sizePolicy">
605 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
606 <horstretch>0</horstretch>
607 <verstretch>0</verstretch>
608 </sizepolicy>
609 </property>
610 <property name="minimumSize">
611 <size>
612 <width>57</width>
613 <height>0</height>
614 </size>
615 </property>
616 <property name="maximumSize">
617 <size>
618 <width>55</width>
619 <height>16777215</height>
620 </size>
621 </property>
622 <property name="styleSheet">
623 <string notr="true">min-width: 55px;</string>
624 </property>
625 <property name="text">
626 <string/>
627 </property>
628 </widget>
629 </item>
630 </layout>
631 </widget>
632 </item>
633 <item alignment="Qt::AlignHCenter">
634 <widget class="QGroupBox" name="player2RightButtonsGroup">
635 <property name="title">
636 <string>R Button</string>
637 </property>
638 <property name="alignment">
639 <set>Qt::AlignCenter</set>
640 </property>
641 <layout class="QVBoxLayout" name="verticalLayout_69">
642 <property name="spacing">
643 <number>3</number>
644 </property>
645 <property name="leftMargin">
646 <number>3</number>
647 </property>
648 <property name="topMargin">
649 <number>3</number>
650 </property>
651 <property name="rightMargin">
652 <number>3</number>
653 </property>
654 <property name="bottomMargin">
655 <number>3</number>
656 </property>
657 <item>
658 <widget class="QPushButton" name="player2_right_buttons_button">
659 <property name="sizePolicy">
660 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
661 <horstretch>0</horstretch>
662 <verstretch>0</verstretch>
663 </sizepolicy>
664 </property>
665 <property name="minimumSize">
666 <size>
667 <width>57</width>
668 <height>0</height>
669 </size>
670 </property>
671 <property name="maximumSize">
672 <size>
673 <width>55</width>
674 <height>16777215</height>
675 </size>
676 </property>
677 <property name="styleSheet">
678 <string notr="true">min-width: 55px;</string>
679 </property>
680 <property name="text">
681 <string/>
682 </property>
683 </widget>
684 </item>
685 </layout>
686 </widget>
687 </item>
688 </layout>
689 </widget>
690 </item>
691 </layout>
692 </widget>
693 </item>
694 </layout>
695 </widget>
696 </item>
697 <item>
698 <widget class="QWidget" name="player34Widget" native="true">
699 <layout class="QHBoxLayout" name="horizontalLayout_5">
700 <property name="leftMargin">
701 <number>0</number>
702 </property>
703 <property name="topMargin">
704 <number>0</number>
705 </property>
706 <property name="rightMargin">
707 <number>0</number>
708 </property>
709 <property name="bottomMargin">
710 <number>0</number>
711 </property>
712 <item>
713 <widget class="QGroupBox" name="player3Group">
714 <property name="title">
715 <string>Player 3</string>
716 </property>
717 <layout class="QHBoxLayout" name="horizontalLayout_15">
718 <property name="spacing">
719 <number>6</number>
720 </property>
721 <property name="leftMargin">
722 <number>6</number>
723 </property>
724 <property name="topMargin">
725 <number>0</number>
726 </property>
727 <property name="rightMargin">
728 <number>6</number>
729 </property>
730 <property name="bottomMargin">
731 <number>6</number>
732 </property>
733 <item>
734 <widget class="QWidget" name="player3LeftJoycon" native="true">
735 <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_16">
736 <property name="spacing">
737 <number>0</number>
738 </property>
739 <property name="leftMargin">
740 <number>0</number>
741 </property>
742 <property name="topMargin">
743 <number>0</number>
744 </property>
745 <property name="rightMargin">
746 <number>0</number>
747 </property>
748 <property name="bottomMargin">
749 <number>0</number>
750 </property>
751 <item alignment="Qt::AlignHCenter">
752 <widget class="QGroupBox" name="player3LeftBodyGroup">
753 <property name="title">
754 <string>L Body</string>
755 </property>
756 <property name="alignment">
757 <set>Qt::AlignCenter</set>
758 </property>
759 <layout class="QVBoxLayout" name="verticalLayout_74">
760 <property name="spacing">
761 <number>3</number>
762 </property>
763 <property name="leftMargin">
764 <number>3</number>
765 </property>
766 <property name="topMargin">
767 <number>3</number>
768 </property>
769 <property name="rightMargin">
770 <number>3</number>
771 </property>
772 <property name="bottomMargin">
773 <number>3</number>
774 </property>
775 <item>
776 <widget class="QPushButton" name="player3_left_body_button">
777 <property name="sizePolicy">
778 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
779 <horstretch>0</horstretch>
780 <verstretch>0</verstretch>
781 </sizepolicy>
782 </property>
783 <property name="minimumSize">
784 <size>
785 <width>57</width>
786 <height>0</height>
787 </size>
788 </property>
789 <property name="maximumSize">
790 <size>
791 <width>55</width>
792 <height>16777215</height>
793 </size>
794 </property>
795 <property name="styleSheet">
796 <string notr="true">min-width: 55px;</string>
797 </property>
798 <property name="text">
799 <string/>
800 </property>
801 </widget>
802 </item>
803 </layout>
804 </widget>
805 </item>
806 <item alignment="Qt::AlignHCenter">
807 <widget class="QGroupBox" name="player3LeftButtonsGroup">
808 <property name="title">
809 <string>L Button</string>
810 </property>
811 <property name="alignment">
812 <set>Qt::AlignCenter</set>
813 </property>
814 <layout class="QVBoxLayout" name="verticalLayout_75">
815 <property name="spacing">
816 <number>3</number>
817 </property>
818 <property name="leftMargin">
819 <number>3</number>
820 </property>
821 <property name="topMargin">
822 <number>3</number>
823 </property>
824 <property name="rightMargin">
825 <number>3</number>
826 </property>
827 <property name="bottomMargin">
828 <number>3</number>
829 </property>
830 <item>
831 <widget class="QPushButton" name="player3_left_buttons_button">
832 <property name="sizePolicy">
833 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
834 <horstretch>0</horstretch>
835 <verstretch>0</verstretch>
836 </sizepolicy>
837 </property>
838 <property name="minimumSize">
839 <size>
840 <width>57</width>
841 <height>0</height>
842 </size>
843 </property>
844 <property name="maximumSize">
845 <size>
846 <width>55</width>
847 <height>16777215</height>
848 </size>
849 </property>
850 <property name="styleSheet">
851 <string notr="true">min-width: 55px;</string>
852 </property>
853 <property name="text">
854 <string/>
855 </property>
856 </widget>
857 </item>
858 </layout>
859 </widget>
860 </item>
861 </layout>
862 </widget>
863 </item>
864 <item>
865 <widget class="QWidget" name="player3RightJoycon" native="true">
866 <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_16">
867 <property name="spacing">
868 <number>0</number>
869 </property>
870 <property name="leftMargin">
871 <number>0</number>
872 </property>
873 <property name="topMargin">
874 <number>0</number>
875 </property>
876 <property name="rightMargin">
877 <number>0</number>
878 </property>
879 <property name="bottomMargin">
880 <number>0</number>
881 </property>
882 <item alignment="Qt::AlignHCenter">
883 <widget class="QGroupBox" name="player3RightBodyGroup">
884 <property name="title">
885 <string>R Body</string>
886 </property>
887 <property name="alignment">
888 <set>Qt::AlignCenter</set>
889 </property>
890 <layout class="QVBoxLayout" name="verticalLayout_72">
891 <property name="spacing">
892 <number>3</number>
893 </property>
894 <property name="leftMargin">
895 <number>3</number>
896 </property>
897 <property name="topMargin">
898 <number>3</number>
899 </property>
900 <property name="rightMargin">
901 <number>3</number>
902 </property>
903 <property name="bottomMargin">
904 <number>3</number>
905 </property>
906 <item>
907 <widget class="QPushButton" name="player3_right_body_button">
908 <property name="sizePolicy">
909 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
910 <horstretch>0</horstretch>
911 <verstretch>0</verstretch>
912 </sizepolicy>
913 </property>
914 <property name="minimumSize">
915 <size>
916 <width>57</width>
917 <height>0</height>
918 </size>
919 </property>
920 <property name="maximumSize">
921 <size>
922 <width>55</width>
923 <height>16777215</height>
924 </size>
925 </property>
926 <property name="styleSheet">
927 <string notr="true">min-width: 55px;</string>
928 </property>
929 <property name="text">
930 <string/>
931 </property>
932 </widget>
933 </item>
934 </layout>
935 </widget>
936 </item>
937 <item alignment="Qt::AlignHCenter">
938 <widget class="QGroupBox" name="player3RightButtonsGroup">
939 <property name="title">
940 <string>R Button</string>
941 </property>
942 <property name="alignment">
943 <set>Qt::AlignCenter</set>
944 </property>
945 <layout class="QVBoxLayout" name="verticalLayout_73">
946 <property name="spacing">
947 <number>3</number>
948 </property>
949 <property name="leftMargin">
950 <number>3</number>
951 </property>
952 <property name="topMargin">
953 <number>3</number>
954 </property>
955 <property name="rightMargin">
956 <number>3</number>
957 </property>
958 <property name="bottomMargin">
959 <number>3</number>
960 </property>
961 <item>
962 <widget class="QPushButton" name="player3_right_buttons_button">
963 <property name="sizePolicy">
964 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
965 <horstretch>0</horstretch>
966 <verstretch>0</verstretch>
967 </sizepolicy>
968 </property>
969 <property name="minimumSize">
970 <size>
971 <width>57</width>
972 <height>0</height>
973 </size>
974 </property>
975 <property name="maximumSize">
976 <size>
977 <width>55</width>
978 <height>16777215</height>
979 </size>
980 </property>
981 <property name="styleSheet">
982 <string notr="true">min-width: 55px;</string>
983 </property>
984 <property name="text">
985 <string/>
986 </property>
987 </widget>
988 </item>
989 </layout>
990 </widget>
991 </item>
992 </layout>
993 </widget>
994 </item>
995 </layout>
996 </widget>
997 </item>
998 <item>
999 <widget class="QGroupBox" name="player4Group">
1000 <property name="title">
1001 <string>Player 4</string>
1002 </property>
1003 <layout class="QHBoxLayout" name="horizontalLayout_16">
1004 <property name="spacing">
1005 <number>6</number>
1006 </property>
1007 <property name="leftMargin">
1008 <number>6</number>
1009 </property>
1010 <property name="topMargin">
1011 <number>0</number>
1012 </property>
1013 <property name="rightMargin">
1014 <number>6</number>
1015 </property>
1016 <property name="bottomMargin">
1017 <number>6</number>
1018 </property>
1019 <item>
1020 <widget class="QWidget" name="player4LeftJoycon" native="true">
1021 <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_17">
1022 <property name="spacing">
1023 <number>0</number>
1024 </property>
1025 <property name="leftMargin">
1026 <number>0</number>
1027 </property>
1028 <property name="topMargin">
1029 <number>0</number>
1030 </property>
1031 <property name="rightMargin">
1032 <number>0</number>
1033 </property>
1034 <property name="bottomMargin">
1035 <number>0</number>
1036 </property>
1037 <item alignment="Qt::AlignHCenter">
1038 <widget class="QGroupBox" name="player4LeftBodyGroup">
1039 <property name="title">
1040 <string>L Body</string>
1041 </property>
1042 <property name="alignment">
1043 <set>Qt::AlignCenter</set>
1044 </property>
1045 <layout class="QVBoxLayout" name="verticalLayout_78">
1046 <property name="spacing">
1047 <number>3</number>
1048 </property>
1049 <property name="leftMargin">
1050 <number>3</number>
1051 </property>
1052 <property name="topMargin">
1053 <number>3</number>
1054 </property>
1055 <property name="rightMargin">
1056 <number>3</number>
1057 </property>
1058 <property name="bottomMargin">
1059 <number>3</number>
1060 </property>
1061 <item>
1062 <widget class="QPushButton" name="player4_left_body_button">
1063 <property name="sizePolicy">
1064 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1065 <horstretch>0</horstretch>
1066 <verstretch>0</verstretch>
1067 </sizepolicy>
1068 </property>
1069 <property name="minimumSize">
1070 <size>
1071 <width>57</width>
1072 <height>0</height>
1073 </size>
1074 </property>
1075 <property name="maximumSize">
1076 <size>
1077 <width>55</width>
1078 <height>16777215</height>
1079 </size>
1080 </property>
1081 <property name="styleSheet">
1082 <string notr="true">min-width: 55px;</string>
1083 </property>
1084 <property name="text">
1085 <string/>
1086 </property>
1087 </widget>
1088 </item>
1089 </layout>
1090 </widget>
1091 </item>
1092 <item alignment="Qt::AlignHCenter">
1093 <widget class="QGroupBox" name="player4LeftButtonsGroup">
1094 <property name="title">
1095 <string>L Button</string>
1096 </property>
1097 <property name="alignment">
1098 <set>Qt::AlignCenter</set>
1099 </property>
1100 <layout class="QVBoxLayout" name="verticalLayout_79">
1101 <property name="spacing">
1102 <number>3</number>
1103 </property>
1104 <property name="leftMargin">
1105 <number>3</number>
1106 </property>
1107 <property name="topMargin">
1108 <number>3</number>
1109 </property>
1110 <property name="rightMargin">
1111 <number>3</number>
1112 </property>
1113 <property name="bottomMargin">
1114 <number>3</number>
1115 </property>
1116 <item>
1117 <widget class="QPushButton" name="player4_left_buttons_button">
1118 <property name="sizePolicy">
1119 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1120 <horstretch>0</horstretch>
1121 <verstretch>0</verstretch>
1122 </sizepolicy>
1123 </property>
1124 <property name="minimumSize">
1125 <size>
1126 <width>57</width>
1127 <height>0</height>
1128 </size>
1129 </property>
1130 <property name="maximumSize">
1131 <size>
1132 <width>55</width>
1133 <height>16777215</height>
1134 </size>
1135 </property>
1136 <property name="styleSheet">
1137 <string notr="true">min-width: 55px;</string>
1138 </property>
1139 <property name="text">
1140 <string/>
1141 </property>
1142 </widget>
1143 </item>
1144 </layout>
1145 </widget>
1146 </item>
1147 </layout>
1148 </widget>
1149 </item>
1150 <item>
1151 <widget class="QWidget" name="player4RightJoycon" native="true">
1152 <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_17">
1153 <property name="spacing">
1154 <number>0</number>
1155 </property>
1156 <property name="leftMargin">
1157 <number>0</number>
1158 </property>
1159 <property name="topMargin">
1160 <number>0</number>
1161 </property>
1162 <property name="rightMargin">
1163 <number>0</number>
1164 </property>
1165 <property name="bottomMargin">
1166 <number>0</number>
1167 </property>
1168 <item alignment="Qt::AlignHCenter">
1169 <widget class="QGroupBox" name="player4RightBodyGroup">
1170 <property name="title">
1171 <string>R Body</string>
1172 </property>
1173 <property name="alignment">
1174 <set>Qt::AlignCenter</set>
1175 </property>
1176 <layout class="QVBoxLayout" name="verticalLayout_76">
1177 <property name="spacing">
1178 <number>3</number>
1179 </property>
1180 <property name="leftMargin">
1181 <number>3</number>
1182 </property>
1183 <property name="topMargin">
1184 <number>3</number>
1185 </property>
1186 <property name="rightMargin">
1187 <number>3</number>
1188 </property>
1189 <property name="bottomMargin">
1190 <number>3</number>
1191 </property>
1192 <item>
1193 <widget class="QPushButton" name="player4_right_body_button">
1194 <property name="sizePolicy">
1195 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1196 <horstretch>0</horstretch>
1197 <verstretch>0</verstretch>
1198 </sizepolicy>
1199 </property>
1200 <property name="minimumSize">
1201 <size>
1202 <width>57</width>
1203 <height>0</height>
1204 </size>
1205 </property>
1206 <property name="maximumSize">
1207 <size>
1208 <width>55</width>
1209 <height>16777215</height>
1210 </size>
1211 </property>
1212 <property name="styleSheet">
1213 <string notr="true">min-width: 55px;</string>
1214 </property>
1215 <property name="text">
1216 <string/>
1217 </property>
1218 </widget>
1219 </item>
1220 </layout>
1221 </widget>
1222 </item>
1223 <item alignment="Qt::AlignHCenter">
1224 <widget class="QGroupBox" name="player4RightButtonsGroup">
1225 <property name="title">
1226 <string>R Button</string>
1227 </property>
1228 <property name="alignment">
1229 <set>Qt::AlignCenter</set>
1230 </property>
1231 <layout class="QVBoxLayout" name="verticalLayout_77">
1232 <property name="spacing">
1233 <number>3</number>
1234 </property>
1235 <property name="leftMargin">
1236 <number>3</number>
1237 </property>
1238 <property name="topMargin">
1239 <number>3</number>
1240 </property>
1241 <property name="rightMargin">
1242 <number>3</number>
1243 </property>
1244 <property name="bottomMargin">
1245 <number>3</number>
1246 </property>
1247 <item>
1248 <widget class="QPushButton" name="player4_right_buttons_button">
1249 <property name="sizePolicy">
1250 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1251 <horstretch>0</horstretch>
1252 <verstretch>0</verstretch>
1253 </sizepolicy>
1254 </property>
1255 <property name="minimumSize">
1256 <size>
1257 <width>57</width>
1258 <height>0</height>
1259 </size>
1260 </property>
1261 <property name="maximumSize">
1262 <size>
1263 <width>55</width>
1264 <height>16777215</height>
1265 </size>
1266 </property>
1267 <property name="styleSheet">
1268 <string notr="true">min-width: 55px;</string>
1269 </property>
1270 <property name="text">
1271 <string/>
1272 </property>
1273 </widget>
1274 </item>
1275 </layout>
1276 </widget>
1277 </item>
1278 </layout>
1279 </widget>
1280 </item>
1281 </layout>
1282 </widget>
1283 </item>
1284 </layout>
1285 </widget>
1286 </item>
1287 </layout>
1288 </widget>
1289 </item>
1290 <item>
1291 <widget class="QWidget" name="bottomLeftInputAdvanced" native="true">
1292 <layout class="QVBoxLayout" name="verticalLayout_5">
1293 <property name="spacing">
1294 <number>6</number>
1295 </property>
1296 <property name="leftMargin">
1297 <number>0</number>
1298 </property>
1299 <property name="topMargin">
1300 <number>0</number>
1301 </property>
1302 <property name="rightMargin">
1303 <number>0</number>
1304 </property>
1305 <property name="bottomMargin">
1306 <number>0</number>
1307 </property>
1308 <item>
1309 <widget class="QWidget" name="player56Widget" native="true">
1310 <layout class="QHBoxLayout" name="horizontalLayout_6">
1311 <property name="leftMargin">
1312 <number>0</number>
1313 </property>
1314 <property name="topMargin">
1315 <number>0</number>
1316 </property>
1317 <property name="rightMargin">
1318 <number>0</number>
1319 </property>
1320 <property name="bottomMargin">
1321 <number>0</number>
1322 </property>
1323 <item>
1324 <widget class="QGroupBox" name="player5Group">
1325 <property name="title">
1326 <string>Player 5</string>
1327 </property>
1328 <layout class="QHBoxLayout" name="horizontalLayout_10">
1329 <property name="spacing">
1330 <number>6</number>
1331 </property>
1332 <property name="leftMargin">
1333 <number>6</number>
1334 </property>
1335 <property name="topMargin">
1336 <number>0</number>
1337 </property>
1338 <property name="rightMargin">
1339 <number>6</number>
1340 </property>
1341 <property name="bottomMargin">
1342 <number>6</number>
1343 </property>
1344 <item>
1345 <widget class="QWidget" name="player5LeftJoycon" native="true">
1346 <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_10">
1347 <property name="spacing">
1348 <number>0</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="player5LeftBodyGroup">
1364 <property name="title">
1365 <string>L Body</string>
1366 </property>
1367 <property name="alignment">
1368 <set>Qt::AlignCenter</set>
1369 </property>
1370 <layout class="QVBoxLayout" name="verticalLayout_50">
1371 <property name="spacing">
1372 <number>3</number>
1373 </property>
1374 <property name="leftMargin">
1375 <number>3</number>
1376 </property>
1377 <property name="topMargin">
1378 <number>3</number>
1379 </property>
1380 <property name="rightMargin">
1381 <number>3</number>
1382 </property>
1383 <property name="bottomMargin">
1384 <number>3</number>
1385 </property>
1386 <item>
1387 <widget class="QPushButton" name="player5_left_body_button">
1388 <property name="sizePolicy">
1389 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1390 <horstretch>0</horstretch>
1391 <verstretch>0</verstretch>
1392 </sizepolicy>
1393 </property>
1394 <property name="minimumSize">
1395 <size>
1396 <width>57</width>
1397 <height>0</height>
1398 </size>
1399 </property>
1400 <property name="maximumSize">
1401 <size>
1402 <width>55</width>
1403 <height>16777215</height>
1404 </size>
1405 </property>
1406 <property name="styleSheet">
1407 <string notr="true">min-width: 55px;</string>
1408 </property>
1409 <property name="text">
1410 <string/>
1411 </property>
1412 </widget>
1413 </item>
1414 </layout>
1415 </widget>
1416 </item>
1417 <item alignment="Qt::AlignHCenter">
1418 <widget class="QGroupBox" name="player5LeftButtonsGroup">
1419 <property name="title">
1420 <string>L Button</string>
1421 </property>
1422 <property name="alignment">
1423 <set>Qt::AlignCenter</set>
1424 </property>
1425 <layout class="QVBoxLayout" name="verticalLayout_51">
1426 <property name="spacing">
1427 <number>3</number>
1428 </property>
1429 <property name="leftMargin">
1430 <number>3</number>
1431 </property>
1432 <property name="topMargin">
1433 <number>3</number>
1434 </property>
1435 <property name="rightMargin">
1436 <number>3</number>
1437 </property>
1438 <property name="bottomMargin">
1439 <number>3</number>
1440 </property>
1441 <item>
1442 <widget class="QPushButton" name="player5_left_buttons_button">
1443 <property name="sizePolicy">
1444 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1445 <horstretch>0</horstretch>
1446 <verstretch>0</verstretch>
1447 </sizepolicy>
1448 </property>
1449 <property name="minimumSize">
1450 <size>
1451 <width>57</width>
1452 <height>0</height>
1453 </size>
1454 </property>
1455 <property name="maximumSize">
1456 <size>
1457 <width>55</width>
1458 <height>16777215</height>
1459 </size>
1460 </property>
1461 <property name="styleSheet">
1462 <string notr="true">min-width: 55px;</string>
1463 </property>
1464 <property name="text">
1465 <string/>
1466 </property>
1467 </widget>
1468 </item>
1469 </layout>
1470 </widget>
1471 </item>
1472 </layout>
1473 </widget>
1474 </item>
1475 <item>
1476 <widget class="QWidget" name="player5RightJoycon" native="true">
1477 <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_10">
1478 <property name="spacing">
1479 <number>0</number>
1480 </property>
1481 <property name="leftMargin">
1482 <number>0</number>
1483 </property>
1484 <property name="topMargin">
1485 <number>0</number>
1486 </property>
1487 <property name="rightMargin">
1488 <number>0</number>
1489 </property>
1490 <property name="bottomMargin">
1491 <number>0</number>
1492 </property>
1493 <item alignment="Qt::AlignHCenter">
1494 <widget class="QGroupBox" name="player5RightBodyGroup">
1495 <property name="title">
1496 <string>R Body</string>
1497 </property>
1498 <property name="alignment">
1499 <set>Qt::AlignCenter</set>
1500 </property>
1501 <layout class="QVBoxLayout" name="verticalLayout_48">
1502 <property name="spacing">
1503 <number>3</number>
1504 </property>
1505 <property name="leftMargin">
1506 <number>3</number>
1507 </property>
1508 <property name="topMargin">
1509 <number>3</number>
1510 </property>
1511 <property name="rightMargin">
1512 <number>3</number>
1513 </property>
1514 <property name="bottomMargin">
1515 <number>3</number>
1516 </property>
1517 <item>
1518 <widget class="QPushButton" name="player5_right_body_button">
1519 <property name="sizePolicy">
1520 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1521 <horstretch>0</horstretch>
1522 <verstretch>0</verstretch>
1523 </sizepolicy>
1524 </property>
1525 <property name="minimumSize">
1526 <size>
1527 <width>57</width>
1528 <height>0</height>
1529 </size>
1530 </property>
1531 <property name="maximumSize">
1532 <size>
1533 <width>55</width>
1534 <height>16777215</height>
1535 </size>
1536 </property>
1537 <property name="styleSheet">
1538 <string notr="true">min-width: 55px;</string>
1539 </property>
1540 <property name="text">
1541 <string/>
1542 </property>
1543 </widget>
1544 </item>
1545 </layout>
1546 </widget>
1547 </item>
1548 <item alignment="Qt::AlignHCenter">
1549 <widget class="QGroupBox" name="player5RightButtonsGroup">
1550 <property name="title">
1551 <string>R Button</string>
1552 </property>
1553 <property name="alignment">
1554 <set>Qt::AlignCenter</set>
1555 </property>
1556 <layout class="QVBoxLayout" name="verticalLayout_49">
1557 <property name="spacing">
1558 <number>3</number>
1559 </property>
1560 <property name="leftMargin">
1561 <number>3</number>
1562 </property>
1563 <property name="topMargin">
1564 <number>3</number>
1565 </property>
1566 <property name="rightMargin">
1567 <number>3</number>
1568 </property>
1569 <property name="bottomMargin">
1570 <number>3</number>
1571 </property>
1572 <item>
1573 <widget class="QPushButton" name="player5_right_buttons_button">
1574 <property name="sizePolicy">
1575 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1576 <horstretch>0</horstretch>
1577 <verstretch>0</verstretch>
1578 </sizepolicy>
1579 </property>
1580 <property name="minimumSize">
1581 <size>
1582 <width>57</width>
1583 <height>0</height>
1584 </size>
1585 </property>
1586 <property name="maximumSize">
1587 <size>
1588 <width>55</width>
1589 <height>16777215</height>
1590 </size>
1591 </property>
1592 <property name="styleSheet">
1593 <string notr="true">min-width: 55px;</string>
1594 </property>
1595 <property name="text">
1596 <string/>
1597 </property>
1598 </widget>
1599 </item>
1600 </layout>
1601 </widget>
1602 </item>
1603 </layout>
1604 </widget>
1605 </item>
1606 </layout>
1607 </widget>
1608 </item>
1609 <item>
1610 <widget class="QGroupBox" name="player6Group">
1611 <property name="title">
1612 <string>Player 6</string>
1613 </property>
1614 <layout class="QHBoxLayout" name="horizontalLayout_11">
1615 <property name="spacing">
1616 <number>6</number>
1617 </property>
1618 <property name="leftMargin">
1619 <number>6</number>
1620 </property>
1621 <property name="topMargin">
1622 <number>0</number>
1623 </property>
1624 <property name="rightMargin">
1625 <number>6</number>
1626 </property>
1627 <property name="bottomMargin">
1628 <number>6</number>
1629 </property>
1630 <item>
1631 <widget class="QWidget" name="player6LeftJoycon" native="true">
1632 <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_11">
1633 <property name="spacing">
1634 <number>0</number>
1635 </property>
1636 <property name="leftMargin">
1637 <number>0</number>
1638 </property>
1639 <property name="topMargin">
1640 <number>0</number>
1641 </property>
1642 <property name="rightMargin">
1643 <number>0</number>
1644 </property>
1645 <property name="bottomMargin">
1646 <number>0</number>
1647 </property>
1648 <item alignment="Qt::AlignHCenter">
1649 <widget class="QGroupBox" name="player6LeftBodyGroup">
1650 <property name="title">
1651 <string>L Body</string>
1652 </property>
1653 <property name="alignment">
1654 <set>Qt::AlignCenter</set>
1655 </property>
1656 <layout class="QVBoxLayout" name="verticalLayout_54">
1657 <property name="spacing">
1658 <number>3</number>
1659 </property>
1660 <property name="leftMargin">
1661 <number>3</number>
1662 </property>
1663 <property name="topMargin">
1664 <number>3</number>
1665 </property>
1666 <property name="rightMargin">
1667 <number>3</number>
1668 </property>
1669 <property name="bottomMargin">
1670 <number>3</number>
1671 </property>
1672 <item>
1673 <widget class="QPushButton" name="player6_left_body_button">
1674 <property name="sizePolicy">
1675 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1676 <horstretch>0</horstretch>
1677 <verstretch>0</verstretch>
1678 </sizepolicy>
1679 </property>
1680 <property name="minimumSize">
1681 <size>
1682 <width>57</width>
1683 <height>0</height>
1684 </size>
1685 </property>
1686 <property name="maximumSize">
1687 <size>
1688 <width>55</width>
1689 <height>16777215</height>
1690 </size>
1691 </property>
1692 <property name="styleSheet">
1693 <string notr="true">min-width: 55px;</string>
1694 </property>
1695 <property name="text">
1696 <string/>
1697 </property>
1698 </widget>
1699 </item>
1700 </layout>
1701 </widget>
1702 </item>
1703 <item alignment="Qt::AlignHCenter">
1704 <widget class="QGroupBox" name="player6LeftButtonsGroup">
1705 <property name="title">
1706 <string>L Button</string>
1707 </property>
1708 <property name="alignment">
1709 <set>Qt::AlignCenter</set>
1710 </property>
1711 <layout class="QVBoxLayout" name="verticalLayout_55">
1712 <property name="spacing">
1713 <number>3</number>
1714 </property>
1715 <property name="leftMargin">
1716 <number>3</number>
1717 </property>
1718 <property name="topMargin">
1719 <number>3</number>
1720 </property>
1721 <property name="rightMargin">
1722 <number>3</number>
1723 </property>
1724 <property name="bottomMargin">
1725 <number>3</number>
1726 </property>
1727 <item>
1728 <widget class="QPushButton" name="player6_left_buttons_button">
1729 <property name="sizePolicy">
1730 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1731 <horstretch>0</horstretch>
1732 <verstretch>0</verstretch>
1733 </sizepolicy>
1734 </property>
1735 <property name="minimumSize">
1736 <size>
1737 <width>57</width>
1738 <height>0</height>
1739 </size>
1740 </property>
1741 <property name="maximumSize">
1742 <size>
1743 <width>55</width>
1744 <height>16777215</height>
1745 </size>
1746 </property>
1747 <property name="styleSheet">
1748 <string notr="true">min-width: 55px;</string>
1749 </property>
1750 <property name="text">
1751 <string/>
1752 </property>
1753 </widget>
1754 </item>
1755 </layout>
1756 </widget>
1757 </item>
1758 </layout>
1759 </widget>
1760 </item>
1761 <item>
1762 <widget class="QWidget" name="player6RightJoycon" native="true">
1763 <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_11">
1764 <property name="spacing">
1765 <number>0</number>
1766 </property>
1767 <property name="leftMargin">
1768 <number>0</number>
1769 </property>
1770 <property name="topMargin">
1771 <number>0</number>
1772 </property>
1773 <property name="rightMargin">
1774 <number>0</number>
1775 </property>
1776 <property name="bottomMargin">
1777 <number>0</number>
1778 </property>
1779 <item alignment="Qt::AlignHCenter">
1780 <widget class="QGroupBox" name="player6RightBodyGroup">
1781 <property name="title">
1782 <string>R Body</string>
1783 </property>
1784 <property name="alignment">
1785 <set>Qt::AlignCenter</set>
1786 </property>
1787 <layout class="QVBoxLayout" name="verticalLayout_52">
1788 <property name="spacing">
1789 <number>3</number>
1790 </property>
1791 <property name="leftMargin">
1792 <number>3</number>
1793 </property>
1794 <property name="topMargin">
1795 <number>3</number>
1796 </property>
1797 <property name="rightMargin">
1798 <number>3</number>
1799 </property>
1800 <property name="bottomMargin">
1801 <number>3</number>
1802 </property>
1803 <item>
1804 <widget class="QPushButton" name="player6_right_body_button">
1805 <property name="sizePolicy">
1806 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1807 <horstretch>0</horstretch>
1808 <verstretch>0</verstretch>
1809 </sizepolicy>
1810 </property>
1811 <property name="minimumSize">
1812 <size>
1813 <width>57</width>
1814 <height>0</height>
1815 </size>
1816 </property>
1817 <property name="maximumSize">
1818 <size>
1819 <width>55</width>
1820 <height>16777215</height>
1821 </size>
1822 </property>
1823 <property name="styleSheet">
1824 <string notr="true">min-width: 55px;</string>
1825 </property>
1826 <property name="text">
1827 <string/>
1828 </property>
1829 </widget>
1830 </item>
1831 </layout>
1832 </widget>
1833 </item>
1834 <item alignment="Qt::AlignHCenter">
1835 <widget class="QGroupBox" name="player6RightButtonsGroup">
1836 <property name="title">
1837 <string>R Button</string>
1838 </property>
1839 <property name="alignment">
1840 <set>Qt::AlignCenter</set>
1841 </property>
1842 <layout class="QVBoxLayout" name="verticalLayout_53">
1843 <property name="spacing">
1844 <number>3</number>
1845 </property>
1846 <property name="leftMargin">
1847 <number>3</number>
1848 </property>
1849 <property name="topMargin">
1850 <number>3</number>
1851 </property>
1852 <property name="rightMargin">
1853 <number>3</number>
1854 </property>
1855 <property name="bottomMargin">
1856 <number>3</number>
1857 </property>
1858 <item>
1859 <widget class="QPushButton" name="player6_right_buttons_button">
1860 <property name="sizePolicy">
1861 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1862 <horstretch>0</horstretch>
1863 <verstretch>0</verstretch>
1864 </sizepolicy>
1865 </property>
1866 <property name="minimumSize">
1867 <size>
1868 <width>57</width>
1869 <height>0</height>
1870 </size>
1871 </property>
1872 <property name="maximumSize">
1873 <size>
1874 <width>55</width>
1875 <height>16777215</height>
1876 </size>
1877 </property>
1878 <property name="styleSheet">
1879 <string notr="true">min-width: 55px;</string>
1880 </property>
1881 <property name="text">
1882 <string/>
1883 </property>
1884 </widget>
1885 </item>
1886 </layout>
1887 </widget>
1888 </item>
1889 </layout>
1890 </widget>
1891 </item>
1892 </layout>
1893 </widget>
1894 </item>
1895 </layout>
1896 </widget>
1897 </item>
1898 <item>
1899 <widget class="QWidget" name="player78Widget" native="true">
1900 <layout class="QHBoxLayout" name="horizontalLayout_7">
1901 <property name="leftMargin">
1902 <number>0</number>
1903 </property>
1904 <property name="topMargin">
1905 <number>0</number>
1906 </property>
1907 <property name="rightMargin">
1908 <number>0</number>
1909 </property>
1910 <property name="bottomMargin">
1911 <number>0</number>
1912 </property>
1913 <item>
1914 <widget class="QGroupBox" name="player7Group">
1915 <property name="title">
1916 <string>Player 7</string>
1917 </property>
1918 <layout class="QHBoxLayout" name="horizontalLayout_12">
1919 <property name="spacing">
1920 <number>6</number>
1921 </property>
1922 <property name="leftMargin">
1923 <number>6</number>
1924 </property>
1925 <property name="topMargin">
1926 <number>0</number>
1927 </property>
1928 <property name="rightMargin">
1929 <number>6</number>
1930 </property>
1931 <property name="bottomMargin">
1932 <number>6</number>
1933 </property>
1934 <item>
1935 <widget class="QWidget" name="player7LeftJoycon" native="true">
1936 <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_12">
1937 <property name="spacing">
1938 <number>0</number>
1939 </property>
1940 <property name="leftMargin">
1941 <number>0</number>
1942 </property>
1943 <property name="topMargin">
1944 <number>0</number>
1945 </property>
1946 <property name="rightMargin">
1947 <number>0</number>
1948 </property>
1949 <property name="bottomMargin">
1950 <number>0</number>
1951 </property>
1952 <item alignment="Qt::AlignHCenter">
1953 <widget class="QGroupBox" name="player7LeftBodyGroup">
1954 <property name="title">
1955 <string>L Body</string>
1956 </property>
1957 <property name="alignment">
1958 <set>Qt::AlignCenter</set>
1959 </property>
1960 <layout class="QVBoxLayout" name="verticalLayout_58">
1961 <property name="spacing">
1962 <number>3</number>
1963 </property>
1964 <property name="leftMargin">
1965 <number>3</number>
1966 </property>
1967 <property name="topMargin">
1968 <number>3</number>
1969 </property>
1970 <property name="rightMargin">
1971 <number>3</number>
1972 </property>
1973 <property name="bottomMargin">
1974 <number>3</number>
1975 </property>
1976 <item>
1977 <widget class="QPushButton" name="player7_left_body_button">
1978 <property name="sizePolicy">
1979 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1980 <horstretch>0</horstretch>
1981 <verstretch>0</verstretch>
1982 </sizepolicy>
1983 </property>
1984 <property name="minimumSize">
1985 <size>
1986 <width>57</width>
1987 <height>0</height>
1988 </size>
1989 </property>
1990 <property name="maximumSize">
1991 <size>
1992 <width>55</width>
1993 <height>16777215</height>
1994 </size>
1995 </property>
1996 <property name="styleSheet">
1997 <string notr="true">min-width: 55px;</string>
1998 </property>
1999 <property name="text">
2000 <string/>
2001 </property>
2002 </widget>
2003 </item>
2004 </layout>
2005 </widget>
2006 </item>
2007 <item alignment="Qt::AlignHCenter">
2008 <widget class="QGroupBox" name="player7LeftButtonsGroup">
2009 <property name="title">
2010 <string>L Button</string>
2011 </property>
2012 <property name="alignment">
2013 <set>Qt::AlignCenter</set>
2014 </property>
2015 <layout class="QVBoxLayout" name="verticalLayout_59">
2016 <property name="spacing">
2017 <number>3</number>
2018 </property>
2019 <property name="leftMargin">
2020 <number>3</number>
2021 </property>
2022 <property name="topMargin">
2023 <number>3</number>
2024 </property>
2025 <property name="rightMargin">
2026 <number>3</number>
2027 </property>
2028 <property name="bottomMargin">
2029 <number>3</number>
2030 </property>
2031 <item>
2032 <widget class="QPushButton" name="player7_left_buttons_button">
2033 <property name="sizePolicy">
2034 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
2035 <horstretch>0</horstretch>
2036 <verstretch>0</verstretch>
2037 </sizepolicy>
2038 </property>
2039 <property name="minimumSize">
2040 <size>
2041 <width>57</width>
2042 <height>0</height>
2043 </size>
2044 </property>
2045 <property name="maximumSize">
2046 <size>
2047 <width>55</width>
2048 <height>16777215</height>
2049 </size>
2050 </property>
2051 <property name="styleSheet">
2052 <string notr="true">min-width: 55px;</string>
2053 </property>
2054 <property name="text">
2055 <string/>
2056 </property>
2057 </widget>
2058 </item>
2059 </layout>
2060 </widget>
2061 </item>
2062 </layout>
2063 </widget>
2064 </item>
2065 <item>
2066 <widget class="QWidget" name="player7RightJoycon" native="true">
2067 <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_12">
2068 <property name="spacing">
2069 <number>0</number>
2070 </property>
2071 <property name="leftMargin">
2072 <number>0</number>
2073 </property>
2074 <property name="topMargin">
2075 <number>0</number>
2076 </property>
2077 <property name="rightMargin">
2078 <number>0</number>
2079 </property>
2080 <property name="bottomMargin">
2081 <number>0</number>
2082 </property>
2083 <item alignment="Qt::AlignHCenter">
2084 <widget class="QGroupBox" name="player7RightBodyGroup">
2085 <property name="title">
2086 <string>R Body</string>
2087 </property>
2088 <property name="alignment">
2089 <set>Qt::AlignCenter</set>
2090 </property>
2091 <layout class="QVBoxLayout" name="verticalLayout_56">
2092 <property name="spacing">
2093 <number>3</number>
2094 </property>
2095 <property name="leftMargin">
2096 <number>3</number>
2097 </property>
2098 <property name="topMargin">
2099 <number>3</number>
2100 </property>
2101 <property name="rightMargin">
2102 <number>3</number>
2103 </property>
2104 <property name="bottomMargin">
2105 <number>3</number>
2106 </property>
2107 <item>
2108 <widget class="QPushButton" name="player7_right_body_button">
2109 <property name="sizePolicy">
2110 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
2111 <horstretch>0</horstretch>
2112 <verstretch>0</verstretch>
2113 </sizepolicy>
2114 </property>
2115 <property name="minimumSize">
2116 <size>
2117 <width>57</width>
2118 <height>0</height>
2119 </size>
2120 </property>
2121 <property name="maximumSize">
2122 <size>
2123 <width>55</width>
2124 <height>16777215</height>
2125 </size>
2126 </property>
2127 <property name="styleSheet">
2128 <string notr="true">min-width: 55px;</string>
2129 </property>
2130 <property name="text">
2131 <string/>
2132 </property>
2133 </widget>
2134 </item>
2135 </layout>
2136 </widget>
2137 </item>
2138 <item alignment="Qt::AlignHCenter">
2139 <widget class="QGroupBox" name="player7RightButtonsGroup">
2140 <property name="title">
2141 <string>R Button</string>
2142 </property>
2143 <property name="alignment">
2144 <set>Qt::AlignCenter</set>
2145 </property>
2146 <layout class="QVBoxLayout" name="verticalLayout_57">
2147 <property name="spacing">
2148 <number>3</number>
2149 </property>
2150 <property name="leftMargin">
2151 <number>3</number>
2152 </property>
2153 <property name="topMargin">
2154 <number>3</number>
2155 </property>
2156 <property name="rightMargin">
2157 <number>3</number>
2158 </property>
2159 <property name="bottomMargin">
2160 <number>3</number>
2161 </property>
2162 <item>
2163 <widget class="QPushButton" name="player7_right_buttons_button">
2164 <property name="sizePolicy">
2165 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
2166 <horstretch>0</horstretch>
2167 <verstretch>0</verstretch>
2168 </sizepolicy>
2169 </property>
2170 <property name="minimumSize">
2171 <size>
2172 <width>57</width>
2173 <height>0</height>
2174 </size>
2175 </property>
2176 <property name="maximumSize">
2177 <size>
2178 <width>55</width>
2179 <height>16777215</height>
2180 </size>
2181 </property>
2182 <property name="styleSheet">
2183 <string notr="true">min-width: 55px;</string>
2184 </property>
2185 <property name="text">
2186 <string/>
2187 </property>
2188 </widget>
2189 </item>
2190 </layout>
2191 </widget>
2192 </item>
2193 </layout>
2194 </widget>
2195 </item>
2196 </layout>
2197 </widget>
2198 </item>
2199 <item>
2200 <widget class="QGroupBox" name="player8Group">
2201 <property name="title">
2202 <string>Player 8</string>
2203 </property>
2204 <layout class="QHBoxLayout" name="horizontalLayout_13">
2205 <property name="spacing">
2206 <number>6</number>
2207 </property>
2208 <property name="leftMargin">
2209 <number>6</number>
2210 </property>
2211 <property name="topMargin">
2212 <number>0</number>
2213 </property>
2214 <property name="rightMargin">
2215 <number>6</number>
2216 </property>
2217 <property name="bottomMargin">
2218 <number>6</number>
2219 </property>
2220 <item>
2221 <widget class="QWidget" name="player8LeftJoycon" native="true">
2222 <layout class="QVBoxLayout" name="buttonMiscButtonsLeftJoyconVerticalLayout_13">
2223 <property name="spacing">
2224 <number>0</number>
2225 </property>
2226 <property name="leftMargin">
2227 <number>0</number>
2228 </property>
2229 <property name="topMargin">
2230 <number>0</number>
2231 </property>
2232 <property name="rightMargin">
2233 <number>0</number>
2234 </property>
2235 <property name="bottomMargin">
2236 <number>0</number>
2237 </property>
2238 <item alignment="Qt::AlignHCenter">
2239 <widget class="QGroupBox" name="player8LeftBodyGroup">
2240 <property name="title">
2241 <string>L Body</string>
2242 </property>
2243 <property name="alignment">
2244 <set>Qt::AlignCenter</set>
2245 </property>
2246 <layout class="QVBoxLayout" name="verticalLayout_62">
2247 <property name="spacing">
2248 <number>3</number>
2249 </property>
2250 <property name="leftMargin">
2251 <number>3</number>
2252 </property>
2253 <property name="topMargin">
2254 <number>3</number>
2255 </property>
2256 <property name="rightMargin">
2257 <number>3</number>
2258 </property>
2259 <property name="bottomMargin">
2260 <number>3</number>
2261 </property>
2262 <item>
2263 <widget class="QPushButton" name="player8_left_body_button">
2264 <property name="sizePolicy">
2265 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
2266 <horstretch>0</horstretch>
2267 <verstretch>0</verstretch>
2268 </sizepolicy>
2269 </property>
2270 <property name="minimumSize">
2271 <size>
2272 <width>57</width>
2273 <height>0</height>
2274 </size>
2275 </property>
2276 <property name="maximumSize">
2277 <size>
2278 <width>55</width>
2279 <height>16777215</height>
2280 </size>
2281 </property>
2282 <property name="styleSheet">
2283 <string notr="true">min-width: 55px;</string>
2284 </property>
2285 <property name="text">
2286 <string/>
2287 </property>
2288 </widget>
2289 </item>
2290 </layout>
2291 </widget>
2292 </item>
2293 <item alignment="Qt::AlignHCenter">
2294 <widget class="QGroupBox" name="player8LeftButtonsGroup">
2295 <property name="title">
2296 <string>L Button</string>
2297 </property>
2298 <property name="alignment">
2299 <set>Qt::AlignCenter</set>
2300 </property>
2301 <layout class="QVBoxLayout" name="verticalLayout_63">
2302 <property name="spacing">
2303 <number>3</number>
2304 </property>
2305 <property name="leftMargin">
2306 <number>3</number>
2307 </property>
2308 <property name="topMargin">
2309 <number>3</number>
2310 </property>
2311 <property name="rightMargin">
2312 <number>3</number>
2313 </property>
2314 <property name="bottomMargin">
2315 <number>3</number>
2316 </property>
2317 <item>
2318 <widget class="QPushButton" name="player8_left_buttons_button">
2319 <property name="sizePolicy">
2320 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
2321 <horstretch>0</horstretch>
2322 <verstretch>0</verstretch>
2323 </sizepolicy>
2324 </property>
2325 <property name="minimumSize">
2326 <size>
2327 <width>57</width>
2328 <height>0</height>
2329 </size>
2330 </property>
2331 <property name="maximumSize">
2332 <size>
2333 <width>55</width>
2334 <height>16777215</height>
2335 </size>
2336 </property>
2337 <property name="styleSheet">
2338 <string notr="true">min-width: 55px;</string>
2339 </property>
2340 <property name="text">
2341 <string/>
2342 </property>
2343 </widget>
2344 </item>
2345 </layout>
2346 </widget>
2347 </item>
2348 </layout>
2349 </widget>
2350 </item>
2351 <item>
2352 <widget class="QWidget" name="player8RightJoycon" native="true">
2353 <layout class="QVBoxLayout" name="buttonMiscButtonsRightJoyconVerticalLayout_13">
2354 <property name="spacing">
2355 <number>0</number>
2356 </property>
2357 <property name="leftMargin">
2358 <number>0</number>
2359 </property>
2360 <property name="topMargin">
2361 <number>0</number>
2362 </property>
2363 <property name="rightMargin">
2364 <number>0</number>
2365 </property>
2366 <property name="bottomMargin">
2367 <number>0</number>
2368 </property>
2369 <item alignment="Qt::AlignHCenter">
2370 <widget class="QGroupBox" name="player8RightBodyGroup">
2371 <property name="title">
2372 <string>R Body</string>
2373 </property>
2374 <property name="alignment">
2375 <set>Qt::AlignCenter</set>
2376 </property>
2377 <layout class="QVBoxLayout" name="verticalLayout_60">
2378 <property name="spacing">
2379 <number>3</number>
2380 </property>
2381 <property name="leftMargin">
2382 <number>3</number>
2383 </property>
2384 <property name="topMargin">
2385 <number>3</number>
2386 </property>
2387 <property name="rightMargin">
2388 <number>3</number>
2389 </property>
2390 <property name="bottomMargin">
2391 <number>3</number>
2392 </property>
2393 <item>
2394 <widget class="QPushButton" name="player8_right_body_button">
2395 <property name="sizePolicy">
2396 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
2397 <horstretch>0</horstretch>
2398 <verstretch>0</verstretch>
2399 </sizepolicy>
2400 </property>
2401 <property name="minimumSize">
2402 <size>
2403 <width>57</width>
2404 <height>0</height>
2405 </size>
2406 </property>
2407 <property name="maximumSize">
2408 <size>
2409 <width>55</width>
2410 <height>16777215</height>
2411 </size>
2412 </property>
2413 <property name="styleSheet">
2414 <string notr="true">min-width: 55px;</string>
2415 </property>
2416 <property name="text">
2417 <string/>
2418 </property>
2419 </widget>
2420 </item>
2421 </layout>
2422 </widget>
2423 </item>
2424 <item alignment="Qt::AlignHCenter">
2425 <widget class="QGroupBox" name="player8RightButtonsGroup">
2426 <property name="title">
2427 <string>R Button</string>
2428 </property>
2429 <property name="alignment">
2430 <set>Qt::AlignCenter</set>
2431 </property>
2432 <layout class="QVBoxLayout" name="verticalLayout_61">
2433 <property name="spacing">
2434 <number>3</number>
2435 </property>
2436 <property name="leftMargin">
2437 <number>3</number>
2438 </property>
2439 <property name="topMargin">
2440 <number>3</number>
2441 </property>
2442 <property name="rightMargin">
2443 <number>3</number>
2444 </property>
2445 <property name="bottomMargin">
2446 <number>3</number>
2447 </property>
2448 <item>
2449 <widget class="QPushButton" name="player8_right_buttons_button">
2450 <property name="sizePolicy">
2451 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
2452 <horstretch>0</horstretch>
2453 <verstretch>0</verstretch>
2454 </sizepolicy>
2455 </property>
2456 <property name="minimumSize">
2457 <size>
2458 <width>57</width>
2459 <height>0</height>
2460 </size>
2461 </property>
2462 <property name="maximumSize">
2463 <size>
2464 <width>55</width>
2465 <height>16777215</height>
2466 </size>
2467 </property>
2468 <property name="styleSheet">
2469 <string notr="true">min-width: 55px;</string>
2470 </property>
2471 <property name="text">
2472 <string/>
2473 </property>
2474 </widget>
2475 </item>
2476 </layout>
2477 </widget>
2478 </item>
2479 </layout>
2480 </widget>
2481 </item>
2482 </layout>
2483 </widget>
2484 </item>
2485 </layout>
2486 </widget>
2487 </item>
2488 </layout>
2489 </widget>
2490 </item>
2491 </layout>
2492 </widget>
2493 </item>
2494 </layout>
2495 </widget>
2496 </item>
2497 <item>
2498 <widget class="QWidget" name="rightInputAdvanced" native="true">
2499 <layout class="QVBoxLayout" name="rightLayout" stretch="1,1">
2500 <property name="spacing">
2501 <number>3</number>
2502 </property>
2503 <property name="leftMargin">
2504 <number>0</number>
2505 </property>
2506 <property name="topMargin">
2507 <number>0</number>
2508 </property>
2509 <property name="rightMargin">
2510 <number>0</number>
2511 </property>
2512 <property name="bottomMargin">
2513 <number>0</number>
2514 </property>
2515 <item>
2516 <widget class="QWidget" name="topRightInputAdvanced" native="true">
2517 <layout class="QVBoxLayout" name="verticalLayout">
2518 <property name="leftMargin">
2519 <number>0</number>
2520 </property>
2521 <property name="topMargin">
2522 <number>0</number>
2523 </property>
2524 <property name="rightMargin">
2525 <number>0</number>
2526 </property>
2527 <property name="bottomMargin">
2528 <number>0</number>
2529 </property>
2530 <item>
2531 <widget class="QGroupBox" name="gridGroupBox_3">
2532 <property name="title">
2533 <string>Other</string>
2534 </property>
2535 <layout class="QGridLayout" name="gridLayout_3">
2536 <item row="0" column="0">
2537 <widget class="QCheckBox" name="keyboard_enabled">
2538 <property name="minimumSize">
2539 <size>
2540 <width>0</width>
2541 <height>23</height>
2542 </size>
2543 </property>
2544 <property name="text">
2545 <string>Keyboard</string>
2546 </property>
2547 </widget>
2548 </item>
2549 <item row="4" column="2">
2550 <widget class="QPushButton" name="touchscreen_advanced">
2551 <property name="text">
2552 <string>Advanced</string>
2553 </property>
2554 </widget>
2555 </item>
2556 <item row="1" column="1">
2557 <spacer name="horizontalSpacer_8">
2558 <property name="orientation">
2559 <enum>Qt::Horizontal</enum>
2560 </property>
2561 <property name="sizeType">
2562 <enum>QSizePolicy::Fixed</enum>
2563 </property>
2564 <property name="sizeHint" stdset="0">
2565 <size>
2566 <width>76</width>
2567 <height>20</height>
2568 </size>
2569 </property>
2570 </spacer>
2571 </item>
2572 <item row="1" column="2">
2573 <widget class="QPushButton" name="mouse_advanced">
2574 <property name="text">
2575 <string>Advanced</string>
2576 </property>
2577 </widget>
2578 </item>
2579 <item row="4" column="0">
2580 <widget class="QCheckBox" name="touchscreen_enabled">
2581 <property name="text">
2582 <string>Touchscreen</string>
2583 </property>
2584 </widget>
2585 </item>
2586 <item row="1" column="0">
2587 <widget class="QCheckBox" name="mouse_enabled">
2588 <property name="minimumSize">
2589 <size>
2590 <width>0</width>
2591 <height>23</height>
2592 </size>
2593 </property>
2594 <property name="text">
2595 <string>Mouse</string>
2596 </property>
2597 </widget>
2598 </item>
2599 <item row="6" column="0">
2600 <widget class="QLabel" name="motion_touch">
2601 <property name="text">
2602 <string>Motion / Touch</string>
2603 </property>
2604 </widget>
2605 </item>
2606 <item row="6" column="2">
2607 <widget class="QPushButton" name="buttonMotionTouch">
2608 <property name="text">
2609 <string>Configure</string>
2610 </property>
2611 </widget>
2612 </item>
2613 <item row="5" column="0">
2614 <widget class="QCheckBox" name="debug_enabled">
2615 <property name="text">
2616 <string>Debug Controller</string>
2617 </property>
2618 </widget>
2619 </item>
2620 <item row="5" column="2">
2621 <widget class="QPushButton" name="debug_configure">
2622 <property name="text">
2623 <string>Configure</string>
2624 </property>
2625 </widget>
2626 </item>
2627 </layout>
2628 </widget>
2629 </item>
2630 <item>
2631 <spacer name="verticalSpacer">
2632 <property name="orientation">
2633 <enum>Qt::Vertical</enum>
2634 </property>
2635 <property name="sizeHint" stdset="0">
2636 <size>
2637 <width>20</width>
2638 <height>40</height>
2639 </size>
2640 </property>
2641 </spacer>
2642 </item>
2643 </layout>
2644 </widget>
2645 </item>
2646 <item>
2647 <widget class="QWidget" name="bottomRightInputAdvanced" native="true">
2648 <layout class="QVBoxLayout" name="verticalLayout_2">
2649 <property name="leftMargin">
2650 <number>0</number>
2651 </property>
2652 <property name="topMargin">
2653 <number>0</number>
2654 </property>
2655 <property name="rightMargin">
2656 <number>0</number>
2657 </property>
2658 <property name="bottomMargin">
2659 <number>0</number>
2660 </property>
2661 <item>
2662 <spacer name="mainVerticalSpacer">
2663 <property name="orientation">
2664 <enum>Qt::Vertical</enum>
2665 </property>
2666 <property name="sizeHint" stdset="0">
2667 <size>
2668 <width>20</width>
2669 <height>40</height>
2670 </size>
2671 </property>
2672 </spacer>
2673 </item>
2674 </layout>
2675 </widget>
2676 </item>
2677 </layout>
2678 </widget>
2679 </item>
2680 </layout>
2681 </widget>
2682 </item>
2683 </layout>
2684 </widget>
2685 <resources>
2686 </resources>
2687 <connections/>
2688</ui>
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 597defe8c..4d79a51f3 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -5,38 +5,86 @@
5#include <algorithm> 5#include <algorithm>
6#include <memory> 6#include <memory>
7#include <utility> 7#include <utility>
8#include <QColorDialog>
9#include <QGridLayout> 8#include <QGridLayout>
9#include <QInputDialog>
10#include <QKeyEvent> 10#include <QKeyEvent>
11#include <QMenu> 11#include <QMenu>
12#include <QMessageBox> 12#include <QMessageBox>
13#include <QTimer> 13#include <QTimer>
14#include "common/assert.h" 14#include "common/assert.h"
15#include "common/param_package.h" 15#include "common/param_package.h"
16#include "core/core.h"
17#include "core/hle/service/hid/controllers/npad.h"
18#include "core/hle/service/hid/hid.h"
19#include "core/hle/service/sm/sm.h"
16#include "input_common/main.h" 20#include "input_common/main.h"
17#include "ui_configure_input_player.h" 21#include "ui_configure_input_player.h"
18#include "yuzu/configuration/config.h" 22#include "yuzu/configuration/config.h"
19#include "yuzu/configuration/configure_input_player.h" 23#include "yuzu/configuration/configure_input_player.h"
20 24
25constexpr std::size_t HANDHELD_INDEX = 8;
26
21const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM> 27const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM>
22 ConfigureInputPlayer::analog_sub_buttons{{ 28 ConfigureInputPlayer::analog_sub_buttons{{
23 "up", 29 "up",
24 "down", 30 "down",
25 "left", 31 "left",
26 "right", 32 "right",
27 "modifier",
28 }}; 33 }};
29 34
30static void LayerGridElements(QGridLayout* grid, QWidget* item, QWidget* onTopOf) { 35namespace {
31 const int index1 = grid->indexOf(item); 36
32 const int index2 = grid->indexOf(onTopOf); 37void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index,
33 int row, column, rowSpan, columnSpan; 38 bool connected) {
34 grid->getItemPosition(index2, &row, &column, &rowSpan, &columnSpan); 39 Core::System& system{Core::System::GetInstance()};
35 grid->takeAt(index1); 40 if (!system.IsPoweredOn()) {
36 grid->addWidget(item, row, column, rowSpan, columnSpan); 41 return;
42 }
43 Service::SM::ServiceManager& sm = system.ServiceManager();
44
45 auto& npad =
46 sm.GetService<Service::HID::Hid>("hid")
47 ->GetAppletResource()
48 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
49
50 npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected);
51}
52
53/// Maps the controller type combobox index to Controller Type enum
54constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) {
55 switch (index) {
56 case 0:
57 default:
58 return Settings::ControllerType::ProController;
59 case 1:
60 return Settings::ControllerType::DualJoyconDetached;
61 case 2:
62 return Settings::ControllerType::LeftJoycon;
63 case 3:
64 return Settings::ControllerType::RightJoycon;
65 case 4:
66 return Settings::ControllerType::Handheld;
67 }
68}
69
70/// Maps the Controller Type enum to controller type combobox index
71constexpr int GetIndexFromControllerType(Settings::ControllerType type) {
72 switch (type) {
73 case Settings::ControllerType::ProController:
74 default:
75 return 0;
76 case Settings::ControllerType::DualJoyconDetached:
77 return 1;
78 case Settings::ControllerType::LeftJoycon:
79 return 2;
80 case Settings::ControllerType::RightJoycon:
81 return 3;
82 case Settings::ControllerType::Handheld:
83 return 4;
84 }
37} 85}
38 86
39static QString GetKeyName(int key_code) { 87QString GetKeyName(int key_code) {
40 switch (key_code) { 88 switch (key_code) {
41 case Qt::Key_Shift: 89 case Qt::Key_Shift:
42 return QObject::tr("Shift"); 90 return QObject::tr("Shift");
@@ -51,9 +99,16 @@ static QString GetKeyName(int key_code) {
51 } 99 }
52} 100}
53 101
54static void SetAnalogButton(const Common::ParamPackage& input_param, 102void SetAnalogParam(const Common::ParamPackage& input_param, Common::ParamPackage& analog_param,
55 Common::ParamPackage& analog_param, const std::string& button_name) { 103 const std::string& button_name) {
56 if (analog_param.Get("engine", "") != "analog_from_button") { 104 // The poller returned a complete axis, so set all the buttons
105 if (input_param.Has("axis_x") && input_param.Has("axis_y")) {
106 analog_param = input_param;
107 return;
108 }
109 // Check if the current configuration has either no engine or an axis binding.
110 // Clears out the old binding and adds one with analog_from_button.
111 if (!analog_param.Has("engine") || analog_param.Has("axis_x") || analog_param.Has("axis_y")) {
57 analog_param = { 112 analog_param = {
58 {"engine", "analog_from_button"}, 113 {"engine", "analog_from_button"},
59 }; 114 };
@@ -61,7 +116,7 @@ static void SetAnalogButton(const Common::ParamPackage& input_param,
61 analog_param.Set(button_name, input_param.Serialize()); 116 analog_param.Set(button_name, input_param.Serialize());
62} 117}
63 118
64static QString ButtonToText(const Common::ParamPackage& param) { 119QString ButtonToText(const Common::ParamPackage& param) {
65 if (!param.Has("engine")) { 120 if (!param.Has("engine")) {
66 return QObject::tr("[not set]"); 121 return QObject::tr("[not set]");
67 } 122 }
@@ -111,7 +166,7 @@ static QString ButtonToText(const Common::ParamPackage& param) {
111 return QObject::tr("[unknown]"); 166 return QObject::tr("[unknown]");
112} 167}
113 168
114static QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) { 169QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) {
115 if (!param.Has("engine")) { 170 if (!param.Has("engine")) {
116 return QObject::tr("[not set]"); 171 return QObject::tr("[not set]");
117 } 172 }
@@ -161,22 +216,24 @@ static QString AnalogToText(const Common::ParamPackage& param, const std::string
161 } 216 }
162 return QObject::tr("[unknown]"); 217 return QObject::tr("[unknown]");
163} 218}
219} // namespace
164 220
165ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug) 221ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index,
166 : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index), 222 QWidget* bottom_row, bool debug)
223 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index),
167 debug(debug), timeout_timer(std::make_unique<QTimer>()), 224 debug(debug), timeout_timer(std::make_unique<QTimer>()),
168 poll_timer(std::make_unique<QTimer>()) { 225 poll_timer(std::make_unique<QTimer>()), bottom_row(bottom_row) {
169 ui->setupUi(this); 226 ui->setupUi(this);
227
170 setFocusPolicy(Qt::ClickFocus); 228 setFocusPolicy(Qt::ClickFocus);
171 229
172 button_map = { 230 button_map = {
173 ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, 231 ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY,
174 ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR, 232 ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR,
175 ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus, 233 ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus,
176 ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown, 234 ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown,
177 ui->buttonLStickLeft, ui->buttonLStickUp, ui->buttonLStickRight, ui->buttonLStickDown, 235 ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot,
178 ui->buttonRStickLeft, ui->buttonRStickUp, ui->buttonRStickRight, ui->buttonRStickDown, 236 ui->buttonLStickMod, ui->buttonRStickMod,
179 ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot,
180 }; 237 };
181 238
182 analog_map_buttons = {{ 239 analog_map_buttons = {{
@@ -185,208 +242,159 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
185 ui->buttonLStickDown, 242 ui->buttonLStickDown,
186 ui->buttonLStickLeft, 243 ui->buttonLStickLeft,
187 ui->buttonLStickRight, 244 ui->buttonLStickRight,
188 ui->buttonLStickMod,
189 }, 245 },
190 { 246 {
191 ui->buttonRStickUp, 247 ui->buttonRStickUp,
192 ui->buttonRStickDown, 248 ui->buttonRStickDown,
193 ui->buttonRStickLeft, 249 ui->buttonRStickLeft,
194 ui->buttonRStickRight, 250 ui->buttonRStickRight,
195 ui->buttonRStickMod,
196 }, 251 },
197 }}; 252 }};
198 253
199 debug_hidden = { 254 analog_map_deadzone_label = {ui->labelLStickDeadzone, ui->labelRStickDeadzone};
200 ui->buttonSL, ui->labelSL, 255 analog_map_deadzone_slider = {ui->sliderLStickDeadzone, ui->sliderRStickDeadzone};
201 ui->buttonSR, ui->labelSR, 256 analog_map_modifier_groupbox = {ui->buttonLStickModGroup, ui->buttonRStickModGroup};
202 ui->buttonLStick, ui->labelLStickPressed, 257 analog_map_modifier_button = {ui->buttonLStickMod, ui->buttonRStickMod};
203 ui->buttonRStick, ui->labelRStickPressed, 258 analog_map_modifier_label = {ui->labelLStickModifierRange, ui->labelRStickModifierRange};
204 ui->buttonHome, ui->labelHome, 259 analog_map_modifier_slider = {ui->sliderLStickModifierRange, ui->sliderRStickModifierRange};
205 ui->buttonScreenshot, ui->labelScreenshot, 260 analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup};
206 }; 261 analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange};
207 262
208 auto layout = Settings::values.players[player_index].type; 263 const auto ConfigureButtonClick = [&](QPushButton* button, Common::ParamPackage* param,
209 if (debug) 264 int default_val) {
210 layout = Settings::ControllerType::DualJoycon;
211
212 switch (layout) {
213 case Settings::ControllerType::ProController:
214 case Settings::ControllerType::DualJoycon:
215 layout_hidden = {
216 ui->buttonSL,
217 ui->labelSL,
218 ui->buttonSR,
219 ui->labelSR,
220 };
221 break;
222 case Settings::ControllerType::LeftJoycon:
223 layout_hidden = {
224 ui->right_body_button,
225 ui->right_buttons_button,
226 ui->right_body_label,
227 ui->right_buttons_label,
228 ui->buttonR,
229 ui->labelR,
230 ui->buttonZR,
231 ui->labelZR,
232 ui->labelHome,
233 ui->buttonHome,
234 ui->buttonPlus,
235 ui->labelPlus,
236 ui->RStick,
237 ui->faceButtons,
238 };
239 break;
240 case Settings::ControllerType::RightJoycon:
241 layout_hidden = {
242 ui->left_body_button, ui->left_buttons_button,
243 ui->left_body_label, ui->left_buttons_label,
244 ui->buttonL, ui->labelL,
245 ui->buttonZL, ui->labelZL,
246 ui->labelScreenshot, ui->buttonScreenshot,
247 ui->buttonMinus, ui->labelMinus,
248 ui->LStick, ui->Dpad,
249 };
250 break;
251 }
252
253 if (debug || layout == Settings::ControllerType::ProController) {
254 ui->controller_color->hide();
255 } else {
256 if (layout == Settings::ControllerType::LeftJoycon ||
257 layout == Settings::ControllerType::RightJoycon) {
258 ui->horizontalSpacer_4->setGeometry({0, 0, 0, 0});
259
260 LayerGridElements(ui->buttons, ui->shoulderButtons, ui->Dpad);
261 LayerGridElements(ui->buttons, ui->misc, ui->RStick);
262 LayerGridElements(ui->buttons, ui->Dpad, ui->faceButtons);
263 LayerGridElements(ui->buttons, ui->RStick, ui->LStick);
264 }
265 }
266
267 for (auto* widget : layout_hidden)
268 widget->setVisible(false);
269
270 analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog};
271 analog_map_deadzone_and_modifier_slider = {ui->sliderLStickDeadzoneAndModifier,
272 ui->sliderRStickDeadzoneAndModifier};
273 analog_map_deadzone_and_modifier_slider_label = {ui->labelLStickDeadzoneAndModifier,
274 ui->labelRStickDeadzoneAndModifier};
275
276 for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
277 auto* const button = button_map[button_id];
278 if (button == nullptr) {
279 continue;
280 }
281
282 button->setContextMenuPolicy(Qt::CustomContextMenu);
283 connect(button, &QPushButton::clicked, [=, this] { 265 connect(button, &QPushButton::clicked, [=, this] {
284 HandleClick( 266 HandleClick(
285 button_map[button_id], 267 button,
286 [=, this](Common::ParamPackage params) { 268 [=, this](Common::ParamPackage params) {
287 // Workaround for ZL & ZR for analog triggers like on XBOX controllors. 269 // Workaround for ZL & ZR for analog triggers like on XBOX
288 // Analog triggers (from controllers like the XBOX controller) would not 270 // controllers. Analog triggers (from controllers like the XBOX
289 // work due to a different range of their signals (from 0 to 255 on 271 // controller) would not work due to a different range of their
290 // analog triggers instead of -32768 to 32768 on analog joysticks). The 272 // signals (from 0 to 255 on analog triggers instead of -32768 to
291 // SDL driver misinterprets analog triggers as analog joysticks. 273 // 32768 on analog joysticks). The SDL driver misinterprets analog
274 // triggers as analog joysticks.
292 // TODO: reinterpret the signal range for analog triggers to map the 275 // TODO: reinterpret the signal range for analog triggers to map the
293 // values correctly. This is required for the correct emulation of the 276 // values correctly. This is required for the correct emulation of
294 // analog triggers of the GameCube controller. 277 // the analog triggers of the GameCube controller.
295 if (button_id == Settings::NativeButton::ZL || 278 if (button == ui->buttonZL || button == ui->buttonZR) {
296 button_id == Settings::NativeButton::ZR) {
297 params.Set("direction", "+"); 279 params.Set("direction", "+");
298 params.Set("threshold", "0.5"); 280 params.Set("threshold", "0.5");
299 } 281 }
300 buttons_param[button_id] = std::move(params); 282 (*param) = std::move(params);
301 }, 283 },
302 InputCommon::Polling::DeviceType::Button); 284 InputCommon::Polling::DeviceType::Button);
303 }); 285 });
304 connect(button, &QPushButton::customContextMenuRequested, 286 };
305 [=, this](const QPoint& menu_location) { 287
306 QMenu context_menu; 288 for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
307 context_menu.addAction(tr("Clear"), [&] { 289 auto* const button = button_map[button_id];
308 buttons_param[button_id].Clear(); 290 if (button == nullptr) {
309 button_map[button_id]->setText(tr("[not set]")); 291 continue;
310 }); 292 }
311 context_menu.addAction(tr("Restore Default"), [&] { 293 ConfigureButtonClick(button_map[button_id], &buttons_param[button_id],
312 buttons_param[button_id] = Common::ParamPackage{ 294 Config::default_buttons[button_id]);
313 InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
314 button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
315 });
316 context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
317 });
318 } 295 }
319 296
320 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { 297 // Handle clicks for the modifier buttons as well.
321 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { 298 ConfigureButtonClick(ui->buttonLStickMod, &lstick_mod, Config::default_lstick_mod);
299 ConfigureButtonClick(ui->buttonRStickMod, &rstick_mod, Config::default_rstick_mod);
300
301 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
302 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
322 auto* const analog_button = analog_map_buttons[analog_id][sub_button_id]; 303 auto* const analog_button = analog_map_buttons[analog_id][sub_button_id];
304
323 if (analog_button == nullptr) { 305 if (analog_button == nullptr) {
324 continue; 306 continue;
325 } 307 }
326 308
327 analog_button->setContextMenuPolicy(Qt::CustomContextMenu);
328 connect(analog_button, &QPushButton::clicked, [=, this] { 309 connect(analog_button, &QPushButton::clicked, [=, this] {
329 HandleClick( 310 HandleClick(
330 analog_map_buttons[analog_id][sub_button_id], 311 analog_map_buttons[analog_id][sub_button_id],
331 [=, this](const Common::ParamPackage& params) { 312 [=, this](const Common::ParamPackage& params) {
332 SetAnalogButton(params, analogs_param[analog_id], 313 SetAnalogParam(params, analogs_param[analog_id],
333 analog_sub_buttons[sub_button_id]); 314 analog_sub_buttons[sub_button_id]);
334 }, 315 },
335 InputCommon::Polling::DeviceType::Button); 316 InputCommon::Polling::DeviceType::AnalogPreferred);
336 }); 317 });
337 connect(analog_button, &QPushButton::customContextMenuRequested,
338 [=, this](const QPoint& menu_location) {
339 QMenu context_menu;
340 context_menu.addAction(tr("Clear"), [&] {
341 analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
342 analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
343 });
344 context_menu.addAction(tr("Restore Default"), [&] {
345 Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
346 Config::default_analogs[analog_id][sub_button_id])};
347 SetAnalogButton(params, analogs_param[analog_id],
348 analog_sub_buttons[sub_button_id]);
349 analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText(
350 analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
351 });
352 context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(
353 menu_location));
354 });
355 } 318 }
356 connect(analog_map_stick[analog_id], &QPushButton::clicked, [=, this] { 319
357 if (QMessageBox::information( 320 connect(analog_map_modifier_button[analog_id], &QPushButton::clicked, [=, this] {
358 this, tr("Information"), 321 HandleClick(
359 tr("After pressing OK, first move your joystick horizontally, " 322 analog_map_modifier_button[analog_id],
360 "and then vertically."), 323 [=, this](const Common::ParamPackage& params) {
361 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { 324 SetAnalogParam(params, analogs_param[analog_id], "modifier");
362 HandleClick( 325 },
363 analog_map_stick[analog_id], 326 InputCommon::Polling::DeviceType::AnalogPreferred);
364 [=, this](const Common::ParamPackage& params) {
365 analogs_param[analog_id] = params;
366 },
367 InputCommon::Polling::DeviceType::Analog);
368 }
369 }); 327 });
370 328
371 connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, 329 connect(analog_map_range_spinbox[analog_id], qOverload<int>(&QSpinBox::valueChanged),
372 [=, this] { 330 [=, this] {
373 const float slider_value = 331 const auto spinbox_value = analog_map_range_spinbox[analog_id]->value();
374 analog_map_deadzone_and_modifier_slider[analog_id]->value(); 332 analogs_param[analog_id].Set("range", spinbox_value / 100.0f);
375 if (analogs_param[analog_id].Get("engine", "") == "sdl" ||
376 analogs_param[analog_id].Get("engine", "") == "gcpad") {
377 analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
378 tr("Deadzone: %1%").arg(slider_value));
379 analogs_param[analog_id].Set("deadzone", slider_value / 100.0f);
380 } else {
381 analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
382 tr("Modifier Scale: %1%").arg(slider_value));
383 analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f);
384 }
385 }); 333 });
334
335 connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] {
336 const auto slider_value = analog_map_deadzone_slider[analog_id]->value();
337 analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value));
338 analogs_param[analog_id].Set("deadzone", slider_value / 100.0f);
339 });
340
341 connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] {
342 const auto slider_value = analog_map_modifier_slider[analog_id]->value();
343 analog_map_modifier_label[analog_id]->setText(
344 tr("Modifier Range: %1%").arg(slider_value));
345 analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f);
346 });
386 } 347 }
387 348
388 connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); }); 349 // Player Connected checkbox
389 connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); }); 350 connect(ui->groupConnectedController, &QGroupBox::toggled,
351 [&](bool checked) { emit Connected(checked); });
352
353 // Set up controller type. Only Player 1 can choose Handheld.
354 ui->comboControllerType->clear();
355
356 QStringList controller_types = {
357 QStringLiteral("Pro Controller"),
358 QStringLiteral("Dual Joycons"),
359 QStringLiteral("Left Joycon"),
360 QStringLiteral("Right Joycon"),
361 };
362
363 if (player_index == 0) {
364 controller_types.append(QStringLiteral("Handheld"));
365 connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged),
366 [&](int index) {
367 emit HandheldStateChanged(GetControllerTypeFromIndex(index) ==
368 Settings::ControllerType::Handheld);
369 });
370 }
371
372 // The Debug Controller can only choose the Pro Controller.
373 if (debug) {
374 ui->buttonScreenshot->setEnabled(false);
375 ui->buttonHome->setEnabled(false);
376 ui->groupConnectedController->setCheckable(false);
377 QStringList debug_controller_types = {
378 QStringLiteral("Pro Controller"),
379 };
380 ui->comboControllerType->addItems(debug_controller_types);
381 } else {
382 ui->comboControllerType->addItems(controller_types);
383 }
384
385 UpdateControllerIcon();
386 UpdateControllerAvailableButtons();
387 connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), [&](int) {
388 UpdateControllerIcon();
389 UpdateControllerAvailableButtons();
390 });
391
392 connect(ui->comboDevices, qOverload<int>(&QComboBox::currentIndexChanged),
393 [&] { UpdateMappingWithDefaults(); });
394
395 ui->buttonRefreshDevices->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
396 UpdateInputDevices();
397 connect(ui->buttonRefreshDevices, &QPushButton::clicked, [&] { emit RefreshInputDevices(); });
390 398
391 timeout_timer->setSingleShot(true); 399 timeout_timer->setSingleShot(true);
392 connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); }); 400 connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); });
@@ -416,20 +424,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
416 } 424 }
417 }); 425 });
418 426
419 controller_color_buttons = {
420 ui->left_body_button,
421 ui->left_buttons_button,
422 ui->right_body_button,
423 ui->right_buttons_button,
424 };
425
426 for (std::size_t i = 0; i < controller_color_buttons.size(); ++i) {
427 connect(controller_color_buttons[i], &QPushButton::clicked, this,
428 [this, i] { OnControllerButtonClick(static_cast<int>(i)); });
429 }
430
431 LoadConfiguration(); 427 LoadConfiguration();
432 resize(0, 0);
433 428
434 // TODO(wwylele): enable this when we actually emulate it 429 // TODO(wwylele): enable this when we actually emulate it
435 ui->buttonHome->setEnabled(false); 430 ui->buttonHome->setEnabled(false);
@@ -438,27 +433,43 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
438ConfigureInputPlayer::~ConfigureInputPlayer() = default; 433ConfigureInputPlayer::~ConfigureInputPlayer() = default;
439 434
440void ConfigureInputPlayer::ApplyConfiguration() { 435void ConfigureInputPlayer::ApplyConfiguration() {
441 auto& buttons = 436 auto& player = Settings::values.players[player_index];
442 debug ? Settings::values.debug_pad_buttons : Settings::values.players[player_index].buttons; 437 auto& buttons = debug ? Settings::values.debug_pad_buttons : player.buttons;
443 auto& analogs = 438 auto& analogs = debug ? Settings::values.debug_pad_analogs : player.analogs;
444 debug ? Settings::values.debug_pad_analogs : Settings::values.players[player_index].analogs;
445 439
446 std::transform(buttons_param.begin(), buttons_param.end(), buttons.begin(), 440 std::transform(buttons_param.begin(), buttons_param.end(), buttons.begin(),
447 [](const Common::ParamPackage& param) { return param.Serialize(); }); 441 [](const Common::ParamPackage& param) { return param.Serialize(); });
448 std::transform(analogs_param.begin(), analogs_param.end(), analogs.begin(), 442 std::transform(analogs_param.begin(), analogs_param.end(), analogs.begin(),
449 [](const Common::ParamPackage& param) { return param.Serialize(); }); 443 [](const Common::ParamPackage& param) { return param.Serialize(); });
450 444
451 if (debug) 445 if (debug) {
452 return; 446 return;
447 }
453 448
454 std::array<u32, 4> colors{}; 449 player.controller_type =
455 std::transform(controller_colors.begin(), controller_colors.end(), colors.begin(), 450 static_cast<Settings::ControllerType>(ui->comboControllerType->currentIndex());
456 [](QColor color) { return color.rgb(); }); 451 player.connected = ui->groupConnectedController->isChecked();
457 452
458 Settings::values.players[player_index].body_color_left = colors[0]; 453 // Player 2-8
459 Settings::values.players[player_index].button_color_left = colors[1]; 454 if (player_index != 0) {
460 Settings::values.players[player_index].body_color_right = colors[2]; 455 UpdateController(player.controller_type, player_index, player.connected);
461 Settings::values.players[player_index].button_color_right = colors[3]; 456 return;
457 }
458
459 // Player 1 and Handheld
460 auto& handheld = Settings::values.players[HANDHELD_INDEX];
461 // If Handheld is selected, copy all the settings from Player 1 to Handheld.
462 if (player.controller_type == Settings::ControllerType::Handheld) {
463 handheld = player;
464 handheld.connected = ui->groupConnectedController->isChecked();
465 player.connected = false; // Disconnect Player 1
466 } else {
467 player.connected = ui->groupConnectedController->isChecked();
468 handheld.connected = false; // Disconnect Handheld
469 }
470
471 UpdateController(player.controller_type, player_index, player.connected);
472 UpdateController(Settings::ControllerType::Handheld, HANDHELD_INDEX, handheld.connected);
462} 473}
463 474
464void ConfigureInputPlayer::changeEvent(QEvent* event) { 475void ConfigureInputPlayer::changeEvent(QEvent* event) {
@@ -466,24 +477,16 @@ void ConfigureInputPlayer::changeEvent(QEvent* event) {
466 RetranslateUI(); 477 RetranslateUI();
467 } 478 }
468 479
469 QDialog::changeEvent(event); 480 QWidget::changeEvent(event);
470} 481}
471 482
472void ConfigureInputPlayer::RetranslateUI() { 483void ConfigureInputPlayer::RetranslateUI() {
473 ui->retranslateUi(this); 484 ui->retranslateUi(this);
474 UpdateButtonLabels(); 485 UpdateUI();
475}
476
477void ConfigureInputPlayer::OnControllerButtonClick(int i) {
478 const QColor new_bg_color = QColorDialog::getColor(controller_colors[i]);
479 if (!new_bg_color.isValid())
480 return;
481 controller_colors[i] = new_bg_color;
482 controller_color_buttons[i]->setStyleSheet(
483 QStringLiteral("QPushButton { background-color: %1 }").arg(controller_colors[i].name()));
484} 486}
485 487
486void ConfigureInputPlayer::LoadConfiguration() { 488void ConfigureInputPlayer::LoadConfiguration() {
489 auto& player = Settings::values.players[player_index];
487 if (debug) { 490 if (debug) {
488 std::transform(Settings::values.debug_pad_buttons.begin(), 491 std::transform(Settings::values.debug_pad_buttons.begin(),
489 Settings::values.debug_pad_buttons.end(), buttons_param.begin(), 492 Settings::values.debug_pad_buttons.end(), buttons_param.begin(),
@@ -492,56 +495,53 @@ void ConfigureInputPlayer::LoadConfiguration() {
492 Settings::values.debug_pad_analogs.end(), analogs_param.begin(), 495 Settings::values.debug_pad_analogs.end(), analogs_param.begin(),
493 [](const std::string& str) { return Common::ParamPackage(str); }); 496 [](const std::string& str) { return Common::ParamPackage(str); });
494 } else { 497 } else {
495 std::transform(Settings::values.players[player_index].buttons.begin(), 498 std::transform(player.buttons.begin(), player.buttons.end(), buttons_param.begin(),
496 Settings::values.players[player_index].buttons.end(), buttons_param.begin(),
497 [](const std::string& str) { return Common::ParamPackage(str); }); 499 [](const std::string& str) { return Common::ParamPackage(str); });
498 std::transform(Settings::values.players[player_index].analogs.begin(), 500 std::transform(player.analogs.begin(), player.analogs.end(), analogs_param.begin(),
499 Settings::values.players[player_index].analogs.end(), analogs_param.begin(),
500 [](const std::string& str) { return Common::ParamPackage(str); }); 501 [](const std::string& str) { return Common::ParamPackage(str); });
501 } 502 }
502 503
503 UpdateButtonLabels(); 504 UpdateUI();
504 505
505 if (debug) 506 if (debug) {
506 return; 507 return;
508 }
507 509
508 std::array<u32, 4> colors = { 510 ui->comboControllerType->setCurrentIndex(static_cast<int>(player.controller_type));
509 Settings::values.players[player_index].body_color_left, 511 ui->groupConnectedController->setChecked(
510 Settings::values.players[player_index].button_color_left, 512 player.connected ||
511 Settings::values.players[player_index].body_color_right, 513 (player_index == 0 && Settings::values.players[HANDHELD_INDEX].connected));
512 Settings::values.players[player_index].button_color_right, 514}
513 };
514
515 std::transform(colors.begin(), colors.end(), controller_colors.begin(),
516 [](u32 rgb) { return QColor::fromRgb(rgb); });
517 515
518 for (std::size_t i = 0; i < colors.size(); ++i) { 516void ConfigureInputPlayer::UpdateInputDevices() {
519 controller_color_buttons[i]->setStyleSheet( 517 input_devices = InputCommon::GetInputDevices();
520 QStringLiteral("QPushButton { background-color: %1 }") 518 ui->comboDevices->clear();
521 .arg(controller_colors[i].name())); 519 for (auto device : input_devices) {
520 ui->comboDevices->addItem(QString::fromStdString(device.Get("display", "Unknown")), {});
522 } 521 }
523} 522}
524 523
525void ConfigureInputPlayer::RestoreDefaults() { 524void ConfigureInputPlayer::RestoreDefaults() {
526 for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { 525 // Reset Buttons
526 for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
527 buttons_param[button_id] = Common::ParamPackage{ 527 buttons_param[button_id] = Common::ParamPackage{
528 InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; 528 InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
529 } 529 }
530 530 // Reset Analogs
531 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { 531 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
532 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { 532 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
533 Common::ParamPackage params{InputCommon::GenerateKeyboardParam( 533 Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
534 Config::default_analogs[analog_id][sub_button_id])}; 534 Config::default_analogs[analog_id][sub_button_id])};
535 SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]); 535 SetAnalogParam(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
536 } 536 }
537 } 537 }
538 538 UpdateUI();
539 UpdateButtonLabels(); 539 UpdateInputDevices();
540 ApplyConfiguration(); 540 ui->comboControllerType->setCurrentIndex(0);
541} 541}
542 542
543void ConfigureInputPlayer::ClearAll() { 543void ConfigureInputPlayer::ClearAll() {
544 for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { 544 for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
545 const auto* const button = button_map[button_id]; 545 const auto* const button = button_map[button_id];
546 if (button == nullptr || !button->isEnabled()) { 546 if (button == nullptr || !button->isEnabled()) {
547 continue; 547 continue;
@@ -550,8 +550,8 @@ void ConfigureInputPlayer::ClearAll() {
550 buttons_param[button_id].Clear(); 550 buttons_param[button_id].Clear();
551 } 551 }
552 552
553 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { 553 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
554 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { 554 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
555 const auto* const analog_button = analog_map_buttons[analog_id][sub_button_id]; 555 const auto* const analog_button = analog_map_buttons[analog_id][sub_button_id];
556 if (analog_button == nullptr || !analog_button->isEnabled()) { 556 if (analog_button == nullptr || !analog_button->isEnabled()) {
557 continue; 557 continue;
@@ -561,17 +561,17 @@ void ConfigureInputPlayer::ClearAll() {
561 } 561 }
562 } 562 }
563 563
564 UpdateButtonLabels(); 564 UpdateUI();
565 ApplyConfiguration(); 565 UpdateInputDevices();
566} 566}
567 567
568void ConfigureInputPlayer::UpdateButtonLabels() { 568void ConfigureInputPlayer::UpdateUI() {
569 for (int button = 0; button < Settings::NativeButton::NumButtons; button++) { 569 for (int button = 0; button < Settings::NativeButton::NumButtons; ++button) {
570 button_map[button]->setText(ButtonToText(buttons_param[button])); 570 button_map[button]->setText(ButtonToText(buttons_param[button]));
571 } 571 }
572 572
573 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { 573 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
574 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { 574 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
575 auto* const analog_button = analog_map_buttons[analog_id][sub_button_id]; 575 auto* const analog_button = analog_map_buttons[analog_id][sub_button_id];
576 576
577 if (analog_button == nullptr) { 577 if (analog_button == nullptr) {
@@ -581,52 +581,75 @@ void ConfigureInputPlayer::UpdateButtonLabels() {
581 analog_button->setText( 581 analog_button->setText(
582 AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id])); 582 AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
583 } 583 }
584 analog_map_stick[analog_id]->setText(tr("Set Analog Stick"));
585 584
585 const auto deadzone_label = analog_map_deadzone_label[analog_id];
586 const auto deadzone_slider = analog_map_deadzone_slider[analog_id];
587 const auto modifier_groupbox = analog_map_modifier_groupbox[analog_id];
588 const auto modifier_label = analog_map_modifier_label[analog_id];
589 const auto modifier_slider = analog_map_modifier_slider[analog_id];
590 const auto range_groupbox = analog_map_range_groupbox[analog_id];
591 const auto range_spinbox = analog_map_range_spinbox[analog_id];
592
593 int slider_value;
586 auto& param = analogs_param[analog_id]; 594 auto& param = analogs_param[analog_id];
587 auto* const analog_stick_slider = analog_map_deadzone_and_modifier_slider[analog_id]; 595 const bool is_controller =
588 auto* const analog_stick_slider_label = 596 param.Get("engine", "") == "sdl" || param.Get("engine", "") == "gcpad";
589 analog_map_deadzone_and_modifier_slider_label[analog_id]; 597
590 598 if (is_controller) {
591 if (param.Has("engine")) { 599 if (!param.Has("deadzone")) {
592 if (param.Get("engine", "") == "sdl" || param.Get("engine", "") == "gcpad") { 600 param.Set("deadzone", 0.1f);
593 if (!param.Has("deadzone")) {
594 param.Set("deadzone", 0.1f);
595 }
596
597 analog_stick_slider->setValue(static_cast<int>(param.Get("deadzone", 0.1f) * 100));
598 if (analog_stick_slider->value() == 0) {
599 analog_stick_slider_label->setText(tr("Deadzone: 0%"));
600 }
601 } else {
602 if (!param.Has("modifier_scale")) {
603 param.Set("modifier_scale", 0.5f);
604 }
605
606 analog_stick_slider->setValue(
607 static_cast<int>(param.Get("modifier_scale", 0.5f) * 100));
608 if (analog_stick_slider->value() == 0) {
609 analog_stick_slider_label->setText(tr("Modifier Scale: 0%"));
610 }
611 } 601 }
602 slider_value = static_cast<int>(param.Get("deadzone", 0.1f) * 100);
603 deadzone_label->setText(tr("Deadzone: %1%").arg(slider_value));
604 deadzone_slider->setValue(slider_value);
605 if (!param.Has("range")) {
606 param.Set("range", 1.0f);
607 }
608 range_spinbox->setValue(static_cast<int>(param.Get("range", 1.0f) * 100));
609 } else {
610 if (!param.Has("modifier_scale")) {
611 param.Set("modifier_scale", 0.5f);
612 }
613 slider_value = static_cast<int>(param.Get("modifier_scale", 0.5f) * 100);
614 modifier_label->setText(tr("Modifier Range: %1%").arg(slider_value));
615 modifier_slider->setValue(slider_value);
612 } 616 }
617
618 deadzone_label->setVisible(is_controller);
619 deadzone_slider->setVisible(is_controller);
620 modifier_groupbox->setVisible(!is_controller);
621 modifier_label->setVisible(!is_controller);
622 modifier_slider->setVisible(!is_controller);
623 range_groupbox->setVisible(is_controller);
613 } 624 }
614} 625}
615 626
627void ConfigureInputPlayer::UpdateMappingWithDefaults() {
628 if (ui->comboDevices->currentIndex() < 2) {
629 return;
630 }
631 const auto& device = input_devices[ui->comboDevices->currentIndex()];
632 auto button_mapping = InputCommon::GetButtonMappingForDevice(device);
633 auto analog_mapping = InputCommon::GetAnalogMappingForDevice(device);
634 for (int i = 0; i < buttons_param.size(); ++i) {
635 buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)];
636 }
637 for (int i = 0; i < analogs_param.size(); ++i) {
638 analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)];
639 }
640
641 UpdateUI();
642}
643
616void ConfigureInputPlayer::HandleClick( 644void ConfigureInputPlayer::HandleClick(
617 QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter, 645 QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
618 InputCommon::Polling::DeviceType type) { 646 InputCommon::Polling::DeviceType type) {
619 button->setText(tr("[press key]")); 647 button->setText(tr("[waiting]"));
620 button->setFocus(); 648 button->setFocus();
621 649
622 // Keyboard keys can only be used as button devices 650 // The first two input devices are always Any and Keyboard. If the user filtered to a
623 want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button; 651 // controller, then they don't want keyboard input
624 if (want_keyboard_keys) { 652 want_keyboard_keys = ui->comboDevices->currentIndex() < 2;
625 const auto iter = std::find(button_map.begin(), button_map.end(), button);
626 ASSERT(iter != button_map.end());
627 const auto index = std::distance(button_map.begin(), iter);
628 ASSERT(index < Settings::NativeButton::NumButtons && index >= 0);
629 }
630 653
631 input_setter = new_input_setter; 654 input_setter = new_input_setter;
632 655
@@ -636,20 +659,17 @@ void ConfigureInputPlayer::HandleClick(
636 poller->Start(); 659 poller->Start();
637 } 660 }
638 661
639 grabKeyboard();
640 grabMouse();
641 if (type == InputCommon::Polling::DeviceType::Button) { 662 if (type == InputCommon::Polling::DeviceType::Button) {
642 InputCommon::GetGCButtons()->BeginConfiguration(); 663 InputCommon::GetGCButtons()->BeginConfiguration();
643 } else { 664 } else {
644 InputCommon::GetGCAnalogs()->BeginConfiguration(); 665 InputCommon::GetGCAnalogs()->BeginConfiguration();
645 } 666 }
646 timeout_timer->start(5000); // Cancel after 5 seconds 667
647 poll_timer->start(200); // Check for new inputs every 200ms 668 timeout_timer->start(2500); // Cancel after 2.5 seconds
669 poll_timer->start(50); // Check for new inputs every 50ms
648} 670}
649 671
650void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, bool abort) { 672void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, bool abort) {
651 releaseKeyboard();
652 releaseMouse();
653 timeout_timer->stop(); 673 timeout_timer->stop();
654 poll_timer->stop(); 674 poll_timer->stop();
655 for (auto& poller : device_pollers) { 675 for (auto& poller : device_pollers) {
@@ -663,7 +683,7 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params,
663 (*input_setter)(params); 683 (*input_setter)(params);
664 } 684 }
665 685
666 UpdateButtonLabels(); 686 UpdateUI();
667 input_setter = std::nullopt; 687 input_setter = std::nullopt;
668} 688}
669 689
@@ -683,3 +703,114 @@ void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
683 } 703 }
684 SetPollingResult({}, true); 704 SetPollingResult({}, true);
685} 705}
706
707void ConfigureInputPlayer::UpdateControllerIcon() {
708 // We aren't using Qt's built in theme support here since we aren't drawing an icon (and its
709 // "nonstandard" to use an image through the icon support)
710 QString stylesheet{};
711 switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) {
712 case Settings::ControllerType::ProController:
713 stylesheet = QStringLiteral("image: url(:/controller/pro_controller%0)");
714 break;
715 case Settings::ControllerType::DualJoyconDetached:
716 stylesheet = QStringLiteral("image: url(:/controller/dual_joycon%0)");
717 break;
718 case Settings::ControllerType::LeftJoycon:
719 stylesheet = QStringLiteral("image: url(:/controller/single_joycon_left_vertical%0)");
720 break;
721 case Settings::ControllerType::RightJoycon:
722 stylesheet = QStringLiteral("image: url(:/controller/single_joycon_right_vertical%0)");
723 break;
724 case Settings::ControllerType::Handheld:
725 stylesheet = QStringLiteral("image: url(:/controller/handheld%0)");
726 break;
727 default:
728 break;
729 }
730
731 const QString theme = [this] {
732 if (QIcon::themeName().contains(QStringLiteral("dark"))) {
733 return QStringLiteral("_dark");
734 } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
735 return QStringLiteral("_midnight");
736 } else {
737 return QString{};
738 }
739 }();
740
741 ui->controllerFrame->setStyleSheet(stylesheet.arg(theme));
742}
743
744void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
745 auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
746 if (debug) {
747 layout = Settings::ControllerType::DualJoyconDetached;
748 }
749
750 // List of all the widgets that will be hidden by any of the following layouts that need
751 // "unhidden" after the controller type changes
752 const std::vector<QWidget*> layout_show = {
753 ui->buttonShoulderButtonsSLSR,
754 ui->horizontalSpacerShoulderButtonsWidget,
755 ui->horizontalSpacerShoulderButtonsWidget2,
756 ui->buttonShoulderButtonsLeft,
757 ui->buttonMiscButtonsMinusScreenshot,
758 ui->bottomLeft,
759 ui->buttonShoulderButtonsRight,
760 ui->buttonMiscButtonsPlusHome,
761 ui->bottomRight,
762 };
763
764 for (auto* widget : layout_show) {
765 widget->show();
766 }
767
768 std::vector<QWidget*> layout_hidden;
769 switch (layout) {
770 case Settings::ControllerType::ProController:
771 layout_hidden = {
772 ui->buttonShoulderButtonsSLSR,
773 ui->horizontalSpacerShoulderButtonsWidget2,
774 };
775 break;
776 case Settings::ControllerType::DualJoyconDetached:
777 case Settings::ControllerType::Handheld:
778 layout_hidden = {
779 ui->buttonShoulderButtonsSLSR,
780 ui->horizontalSpacerShoulderButtonsWidget2,
781 };
782 break;
783 case Settings::ControllerType::LeftJoycon:
784 layout_hidden = {
785 ui->horizontalSpacerShoulderButtonsWidget2,
786 ui->buttonShoulderButtonsRight,
787 ui->buttonMiscButtonsPlusHome,
788 ui->bottomRight,
789 };
790 break;
791 case Settings::ControllerType::RightJoycon:
792 layout_hidden = {
793 ui->horizontalSpacerShoulderButtonsWidget,
794 ui->buttonShoulderButtonsLeft,
795 ui->buttonMiscButtonsMinusScreenshot,
796 ui->bottomLeft,
797 };
798 break;
799 }
800
801 for (auto* widget : layout_hidden) {
802 widget->hide();
803 }
804}
805
806void ConfigureInputPlayer::showEvent(QShowEvent* event) {
807 if (bottom_row == nullptr) {
808 return;
809 }
810 QWidget::showEvent(event);
811 ui->main->addWidget(bottom_row);
812}
813
814void ConfigureInputPlayer::ConnectPlayer(bool connected) {
815 ui->groupConnectedController->setChecked(connected);
816}
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index 95afa5375..a86db8200 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -15,11 +15,17 @@
15#include "common/param_package.h" 15#include "common/param_package.h"
16#include "core/settings.h" 16#include "core/settings.h"
17#include "ui_configure_input.h" 17#include "ui_configure_input.h"
18#include "yuzu/uisettings.h"
18 19
20class QCheckBox;
19class QKeyEvent; 21class QKeyEvent;
22class QLabel;
20class QPushButton; 23class QPushButton;
24class QSlider;
25class QSpinBox;
21class QString; 26class QString;
22class QTimer; 27class QTimer;
28class QWidget;
23 29
24namespace InputCommon::Polling { 30namespace InputCommon::Polling {
25class DevicePoller; 31class DevicePoller;
@@ -30,43 +36,73 @@ namespace Ui {
30class ConfigureInputPlayer; 36class ConfigureInputPlayer;
31} 37}
32 38
33class ConfigureInputPlayer : public QDialog { 39class ConfigureInputPlayer : public QWidget {
34 Q_OBJECT 40 Q_OBJECT
35 41
36public: 42public:
37 explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug = false); 43 explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row,
44 bool debug = false);
38 ~ConfigureInputPlayer() override; 45 ~ConfigureInputPlayer() override;
39 46
40 /// Save all button configurations to settings file 47 /// Save all button configurations to settings file.
41 void ApplyConfiguration(); 48 void ApplyConfiguration();
42 49
50 /// Update the input devices combobox.
51 void UpdateInputDevices();
52
53 /// Restore all buttons to their default values.
54 void RestoreDefaults();
55
56 /// Clear all input configuration.
57 void ClearAll();
58
59 /// Set the connection state checkbox (used to sync state).
60 void ConnectPlayer(bool connected);
61
62signals:
63 /// Emitted when this controller is connected by the user.
64 void Connected(bool connected);
65 /// Emitted when the Handheld mode is selected (undocked with dual joycons attached).
66 void HandheldStateChanged(bool is_handheld);
67 /// Emitted when the input devices combobox is being refreshed.
68 void RefreshInputDevices();
69
70protected:
71 void showEvent(QShowEvent* event) override;
72
43private: 73private:
44 void changeEvent(QEvent* event) override; 74 void changeEvent(QEvent* event) override;
45 void RetranslateUI(); 75 void RetranslateUI();
46 76
47 void OnControllerButtonClick(int i);
48
49 /// Load configuration settings. 77 /// Load configuration settings.
50 void LoadConfiguration(); 78 void LoadConfiguration();
51 /// Restore all buttons to their default values.
52 void RestoreDefaults();
53 /// Clear all input configuration
54 void ClearAll();
55
56 /// Update UI to reflect current configuration.
57 void UpdateButtonLabels();
58 79
59 /// Called when the button was pressed. 80 /// Called when the button was pressed.
60 void HandleClick(QPushButton* button, 81 void HandleClick(QPushButton* button,
61 std::function<void(const Common::ParamPackage&)> new_input_setter, 82 std::function<void(const Common::ParamPackage&)> new_input_setter,
62 InputCommon::Polling::DeviceType type); 83 InputCommon::Polling::DeviceType type);
63 84
64 /// Finish polling and configure input using the input_setter 85 /// Finish polling and configure input using the input_setter.
65 void SetPollingResult(const Common::ParamPackage& params, bool abort); 86 void SetPollingResult(const Common::ParamPackage& params, bool abort);
66 87
67 /// Handle key press events. 88 /// Handle key press events.
68 void keyPressEvent(QKeyEvent* event) override; 89 void keyPressEvent(QKeyEvent* event) override;
69 90
91 /// Update UI to reflect current configuration.
92 void UpdateUI();
93
94 /// Update the controller selection combobox
95 void UpdateControllerCombobox();
96
97 /// Update the current controller icon.
98 void UpdateControllerIcon();
99
100 /// Hides and disables controller settings based on the current controller type.
101 void UpdateControllerAvailableButtons();
102
103 /// Gets the default controller mapping for this device and auto configures the input to match.
104 void UpdateMappingWithDefaults();
105
70 std::unique_ptr<Ui::ConfigureInputPlayer> ui; 106 std::unique_ptr<Ui::ConfigureInputPlayer> ui;
71 107
72 std::size_t player_index; 108 std::size_t player_index;
@@ -75,32 +111,38 @@ private:
75 std::unique_ptr<QTimer> timeout_timer; 111 std::unique_ptr<QTimer> timeout_timer;
76 std::unique_ptr<QTimer> poll_timer; 112 std::unique_ptr<QTimer> poll_timer;
77 113
114 static constexpr int PLAYER_COUNT = 8;
115 std::array<QCheckBox*, PLAYER_COUNT> player_connected_checkbox;
116
78 /// This will be the the setting function when an input is awaiting configuration. 117 /// This will be the the setting function when an input is awaiting configuration.
79 std::optional<std::function<void(const Common::ParamPackage&)>> input_setter; 118 std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
80 119
81 std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param; 120 std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param;
82 std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param; 121 std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param;
83 122
84 static constexpr int ANALOG_SUB_BUTTONS_NUM = 5; 123 static constexpr int ANALOG_SUB_BUTTONS_NUM = 4;
124 // Adds room for two extra push buttons LStick Modifier and RStick Modifier.
125 static constexpr int BUTTON_MAP_COUNT = Settings::NativeButton::NumButtons + 2;
85 126
86 /// Each button input is represented by a QPushButton. 127 /// Each button input is represented by a QPushButton.
87 std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map; 128 std::array<QPushButton*, BUTTON_MAP_COUNT> button_map;
88 129 /// Extra buttons for the modifiers.
89 std::vector<QWidget*> debug_hidden; 130 Common::ParamPackage lstick_mod;
90 std::vector<QWidget*> layout_hidden; 131 Common::ParamPackage rstick_mod;
91 132
92 /// A group of five QPushButtons represent one analog input. The buttons each represent up, 133 /// A group of four QPushButtons represent one analog input. The buttons each represent up,
93 /// down, left, right, and modifier, respectively. 134 /// down, left, right, respectively.
94 std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs> 135 std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs>
95 analog_map_buttons; 136 analog_map_buttons;
96 137
97 /// Analog inputs are also represented each with a single button, used to configure with an 138 std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone_label;
98 /// actual analog stick 139 std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone_slider;
99 std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick; 140 std::array<QGroupBox*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_groupbox;
100 std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> 141 std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_button;
101 analog_map_deadzone_and_modifier_slider; 142 std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_label;
102 std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> 143 std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_slider;
103 analog_map_deadzone_and_modifier_slider_label; 144 std::array<QGroupBox*, Settings::NativeAnalog::NumAnalogs> analog_map_range_groupbox;
145 std::array<QSpinBox*, Settings::NativeAnalog::NumAnalogs> analog_map_range_spinbox;
104 146
105 static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons; 147 static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons;
106 148
@@ -110,6 +152,12 @@ private:
110 /// keyboard events are ignored. 152 /// keyboard events are ignored.
111 bool want_keyboard_keys = false; 153 bool want_keyboard_keys = false;
112 154
113 std::array<QPushButton*, 4> controller_color_buttons; 155 /// List of physical devices users can map with. If a SDL backed device is selected, then you
114 std::array<QColor, 4> controller_colors; 156 /// can usue this device to get a default mapping.
157 std::vector<Common::ParamPackage> input_devices;
158
159 /// Bottom row is where console wide settings are held, and its "owned" by the parent
160 /// ConfigureInput widget. On show, add this widget to the main layout. This will change the
161 /// parent of the widget to this widget (but thats fine).
162 QWidget* bottom_row;
115}; 163};
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui
index f27a77180..eb826a935 100644
--- a/src/yuzu/configuration/configure_input_player.ui
+++ b/src/yuzu/configuration/configure_input_player.ui
@@ -1,1243 +1,2974 @@
1<?xml version="1.0" encoding="UTF-8"?> 1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0"> 2<ui version="4.0">
3 <class>ConfigureInputPlayer</class> 3 <class>ConfigureInputPlayer</class>
4 <widget class="QDialog" name="ConfigureInputPlayer"> 4 <widget class="QWidget" name="ConfigureInputPlayer">
5 <property name="geometry"> 5 <property name="geometry">
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>408</width> 9 <width>780</width>
10 <height>731</height> 10 <height>487</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Configure Input</string> 14 <string>Configure Input</string>
15 </property> 15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout_5"> 16 <layout class="QHBoxLayout" name="horizontalLayout_2">
17 <property name="spacing">
18 <number>0</number>
19 </property>
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>
17 <item> 32 <item>
18 <layout class="QGridLayout" name="buttons"> 33 <layout class="QVBoxLayout" name="main">
19 <item row="1" column="1"> 34 <property name="spacing">
20 <widget class="QGroupBox" name="RStick"> 35 <number>0</number>
21 <property name="title"> 36 </property>
22 <string>Right Stick</string> 37 <property name="leftMargin">
23 </property> 38 <number>0</number>
24 <property name="alignment"> 39 </property>
25 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> 40 <property name="topMargin">
26 </property> 41 <number>0</number>
27 <property name="flat"> 42 </property>
28 <bool>false</bool> 43 <property name="rightMargin">
44 <number>0</number>
45 </property>
46 <property name="bottomMargin">
47 <number>0</number>
48 </property>
49 <item>
50 <layout class="QHBoxLayout" name="top" stretch="0,1,2">
51 <property name="spacing">
52 <number>3</number>
29 </property> 53 </property>
30 <property name="checkable"> 54 <property name="topMargin">
31 <bool>false</bool> 55 <number>0</number>
32 </property> 56 </property>
33 <layout class="QGridLayout" name="gridLayout_5"> 57 <item>
34 <item row="1" column="1"> 58 <widget class="QGroupBox" name="groupConnectedController">
35 <layout class="QVBoxLayout" name="buttonRStickDownVerticalLayout"> 59 <property name="layoutDirection">
60 <enum>Qt::LeftToRight</enum>
61 </property>
62 <property name="title">
63 <string>Connect Controller</string>
64 </property>
65 <property name="flat">
66 <bool>false</bool>
67 </property>
68 <property name="checkable">
69 <bool>true</bool>
70 </property>
71 <layout class="QHBoxLayout" name="horizontalLayout_3">
72 <property name="leftMargin">
73 <number>5</number>
74 </property>
75 <property name="topMargin">
76 <number>5</number>
77 </property>
78 <property name="rightMargin">
79 <number>5</number>
80 </property>
81 <property name="bottomMargin">
82 <number>5</number>
83 </property>
36 <item> 84 <item>
37 <layout class="QHBoxLayout" name="buttonRStickDownHorizontalLayout"> 85 <widget class="QComboBox" name="comboControllerType">
38 <item> 86 <item>
39 <widget class="QLabel" name="labelRStickDown"> 87 <property name="text">
40 <property name="text"> 88 <string>Pro Controller</string>
41 <string>Down:</string> 89 </property>
42 </property>
43 </widget>
44 </item> 90 </item>
45 </layout>
46 </item>
47 <item>
48 <widget class="QPushButton" name="buttonRStickDown">
49 <property name="text">
50 <string/>
51 </property>
52 </widget>
53 </item>
54 </layout>
55 </item>
56 <item row="0" column="1">
57 <layout class="QVBoxLayout" name="buttonRStickRightVerticalLayout">
58 <item>
59 <layout class="QHBoxLayout" name="buttonRStickRightHorizontalLayout">
60 <item> 91 <item>
61 <widget class="QLabel" name="labelRStickRight"> 92 <property name="text">
62 <property name="text"> 93 <string>Dual Joycons</string>
63 <string>Right:</string> 94 </property>
64 </property>
65 </widget>
66 </item> 95 </item>
67 </layout>
68 </item>
69 <item>
70 <widget class="QPushButton" name="buttonRStickRight">
71 <property name="text">
72 <string/>
73 </property>
74 </widget>
75 </item>
76 </layout>
77 </item>
78 <item row="3" column="0" colspan="2">
79 <widget class="QPushButton" name="buttonRStickAnalog">
80 <property name="text">
81 <string>Set Analog Stick</string>
82 </property>
83 </widget>
84 </item>
85 <item row="0" column="0">
86 <layout class="QVBoxLayout" name="buttonRStickLeftVerticalLayout">
87 <item>
88 <layout class="QHBoxLayout" name="buttonRStickLeftHorizontalLayout">
89 <item> 96 <item>
90 <widget class="QLabel" name="labelRStickLeft"> 97 <property name="text">
91 <property name="text"> 98 <string>Left Joycon</string>
92 <string>Left:</string> 99 </property>
93 </property>
94 </widget>
95 </item> 100 </item>
96 </layout>
97 </item>
98 <item>
99 <widget class="QPushButton" name="buttonRStickLeft">
100 <property name="text">
101 <string/>
102 </property>
103 </widget>
104 </item>
105 </layout>
106 </item>
107 <item row="1" column="0">
108 <layout class="QVBoxLayout" name="buttonRStickUpVerticalLayout">
109 <item>
110 <layout class="QHBoxLayout" name="buttonRStickUpHorizontalLayout">
111 <item> 101 <item>
112 <widget class="QLabel" name="labelRStickUp"> 102 <property name="text">
113 <property name="text"> 103 <string>Right Joycon</string>
114 <string>Up:</string> 104 </property>
115 </property>
116 </widget>
117 </item> 105 </item>
118 </layout>
119 </item>
120 <item>
121 <widget class="QPushButton" name="buttonRStickUp">
122 <property name="text">
123 <string/>
124 </property>
125 </widget>
126 </item>
127 </layout>
128 </item>
129 <item row="2" column="0">
130 <layout class="QVBoxLayout" name="buttonRStickPressedVerticalLayout">
131 <item>
132 <layout class="QHBoxLayout" name="buttonRStickPressedHorizontalLayout">
133 <item> 106 <item>
134 <widget class="QLabel" name="labelRStickPressed"> 107 <property name="text">
135 <property name="text"> 108 <string>Handheld</string>
136 <string>Pressed:</string> 109 </property>
137 </property>
138 </widget>
139 </item> 110 </item>
140 </layout>
141 </item>
142 <item>
143 <widget class="QPushButton" name="buttonRStick">
144 <property name="text">
145 <string/>
146 </property>
147 </widget> 111 </widget>
148 </item> 112 </item>
149 </layout> 113 </layout>
150 </item> 114 </widget>
151 <item row="2" column="1"> 115 </item>
152 <layout class="QVBoxLayout" name="buttonRStickModVerticalLayout"> 116 <item>
117 <widget class="QGroupBox" name="devicesGroup">
118 <property name="title">
119 <string>Input Device</string>
120 </property>
121 <layout class="QHBoxLayout" name="horizontalLayout_5">
122 <property name="spacing">
123 <number>3</number>
124 </property>
125 <property name="leftMargin">
126 <number>5</number>
127 </property>
128 <property name="topMargin">
129 <number>5</number>
130 </property>
131 <property name="rightMargin">
132 <number>5</number>
133 </property>
134 <property name="bottomMargin">
135 <number>5</number>
136 </property>
153 <item> 137 <item>
154 <layout class="QHBoxLayout" name="buttonRStickModHorizontalLayout"> 138 <widget class="QComboBox" name="comboDevices">
155 <item> 139 <item>
156 <widget class="QLabel" name="labelRStickMod"> 140 <property name="text">
157 <property name="text"> 141 <string>Any</string>
158 <string>Modifier:</string> 142 </property>
159 </property>
160 </widget>
161 </item> 143 </item>
162 </layout>
163 </item>
164 <item>
165 <widget class="QPushButton" name="buttonRStickMod">
166 <property name="text">
167 <string/>
168 </property>
169 </widget>
170 </item>
171 </layout>
172 </item>
173 <item row="4" column="0" colspan="2">
174 <layout class="QVBoxLayout" name="sliderRStickDeadzoneAndModifierVerticalLayout">
175 <item>
176 <layout class="QHBoxLayout" name="sliderRStickDeadzoneAndModifierHorizontalLayout">
177 <item> 144 <item>
178 <widget class="QLabel" name="labelRStickDeadzoneAndModifier"> 145 <property name="text">
179 <property name="text"> 146 <string>Keyboard</string>
180 <string>Deadzone: 0</string> 147 </property>
181 </property>
182 <property name="alignment">
183 <enum>Qt::AlignHCenter</enum>
184 </property>
185 </widget>
186 </item> 148 </item>
187 </layout> 149 </widget>
188 </item> 150 </item>
189 <item> 151 <item>
190 <widget class="QSlider" name="sliderRStickDeadzoneAndModifier"> 152 <widget class="QPushButton" name="buttonRefreshDevices">
191 <property name="orientation"> 153 <property name="minimumSize">
192 <enum>Qt::Horizontal</enum> 154 <size>
155 <width>24</width>
156 <height>22</height>
157 </size>
158 </property>
159 <property name="maximumSize">
160 <size>
161 <width>24</width>
162 <height>22</height>
163 </size>
164 </property>
165 <property name="styleSheet">
166 <string notr="true"/>
193 </property> 167 </property>
194 </widget> 168 </widget>
195 </item> 169 </item>
196 </layout> 170 </layout>
197 </item> 171 </widget>
198 <item row="5" column="0"> 172 </item>
199 <spacer name="RStick_verticalSpacer"> 173 <item>
200 <property name="orientation"> 174 <widget class="QGroupBox" name="profilesGroup">
201 <enum>Qt::Vertical</enum> 175 <property name="minimumSize">
176 <size>
177 <width>0</width>
178 <height>0</height>
179 </size>
180 </property>
181 <property name="title">
182 <string>Profile</string>
183 </property>
184 <layout class="QHBoxLayout" name="horizontalLayout_4" stretch="2,0,0,0">
185 <property name="spacing">
186 <number>3</number>
202 </property> 187 </property>
203 <property name="sizeHint" stdset="0"> 188 <property name="leftMargin">
204 <size> 189 <number>5</number>
205 <width>0</width> 190 </property>
206 <height>0</height> 191 <property name="topMargin">
207 </size> 192 <number>5</number>
193 </property>
194 <property name="rightMargin">
195 <number>5</number>
196 </property>
197 <property name="bottomMargin">
198 <number>5</number>
208 </property> 199 </property>
209 </spacer>
210 </item>
211 </layout>
212 </widget>
213 </item>
214 <item row="0" column="1">
215 <widget class="QGroupBox" name="Dpad">
216 <property name="title">
217 <string>Directional Pad</string>
218 </property>
219 <property name="flat">
220 <bool>false</bool>
221 </property>
222 <property name="checkable">
223 <bool>false</bool>
224 </property>
225 <layout class="QGridLayout" name="gridLayout_2">
226 <item row="1" column="0">
227 <layout class="QVBoxLayout" name="buttonDpadUpVerticalLayout">
228 <item> 200 <item>
229 <layout class="QHBoxLayout" name="buttonDpadUpHorizontalLayout"> 201 <widget class="QComboBox" name="comboProfiles"/>
230 <item>
231 <widget class="QLabel" name="labelDpadUp">
232 <property name="text">
233 <string>Up:</string>
234 </property>
235 </widget>
236 </item>
237 </layout>
238 </item> 202 </item>
239 <item> 203 <item>
240 <widget class="QPushButton" name="buttonDpadUp"> 204 <widget class="QPushButton" name="buttonProfilesSave">
241 <property name="text"> 205 <property name="maximumSize">
242 <string/> 206 <size>
207 <width>55</width>
208 <height>16777215</height>
209 </size>
210 </property>
211 <property name="styleSheet">
212 <string notr="true">min-width: 55px;</string>
243 </property> 213 </property>
244 </widget>
245 </item>
246 </layout>
247 </item>
248 <item row="1" column="1">
249 <layout class="QVBoxLayout" name="buttonDpadDownVerticalLayout">
250 <item>
251 <layout class="QHBoxLayout" name="buttonDpadDownHorizontalLayout">
252 <item>
253 <widget class="QLabel" name="labelDpadDown">
254 <property name="text">
255 <string>Down:</string>
256 </property>
257 </widget>
258 </item>
259 </layout>
260 </item>
261 <item>
262 <widget class="QPushButton" name="buttonDpadDown">
263 <property name="text"> 214 <property name="text">
264 <string/> 215 <string>Save</string>
265 </property> 216 </property>
266 </widget> 217 </widget>
267 </item> 218 </item>
268 </layout>
269 </item>
270 <item row="0" column="0">
271 <layout class="QVBoxLayout" name="buttonDpadLeftVerticalLayout">
272 <item>
273 <layout class="QHBoxLayout" name="buttonDpadLeftHorizontalLayout">
274 <item>
275 <widget class="QLabel" name="labelDpadLeft">
276 <property name="minimumSize">
277 <size>
278 <width>80</width>
279 <height>0</height>
280 </size>
281 </property>
282 <property name="text">
283 <string>Left:</string>
284 </property>
285 </widget>
286 </item>
287 </layout>
288 </item>
289 <item> 219 <item>
290 <widget class="QPushButton" name="buttonDpadLeft"> 220 <widget class="QPushButton" name="buttonProfilesNew">
221 <property name="maximumSize">
222 <size>
223 <width>55</width>
224 <height>16777215</height>
225 </size>
226 </property>
227 <property name="styleSheet">
228 <string notr="true">min-width: 55px;</string>
229 </property>
291 <property name="text"> 230 <property name="text">
292 <string/> 231 <string>New</string>
293 </property> 232 </property>
294 </widget> 233 </widget>
295 </item> 234 </item>
296 </layout>
297 </item>
298 <item row="0" column="1">
299 <layout class="QVBoxLayout" name="buttonDpadRightVerticalLayout">
300 <item>
301 <layout class="QHBoxLayout" name="buttonDpadRightHorizontalLayout">
302 <item>
303 <widget class="QLabel" name="labelDpadRight">
304 <property name="minimumSize">
305 <size>
306 <width>80</width>
307 <height>0</height>
308 </size>
309 </property>
310 <property name="text">
311 <string>Right:</string>
312 </property>
313 </widget>
314 </item>
315 </layout>
316 </item>
317 <item> 235 <item>
318 <widget class="QPushButton" name="buttonDpadRight"> 236 <widget class="QPushButton" name="buttonProfilesDelete">
237 <property name="maximumSize">
238 <size>
239 <width>55</width>
240 <height>16777215</height>
241 </size>
242 </property>
243 <property name="styleSheet">
244 <string notr="true">min-width: 55px;</string>
245 </property>
319 <property name="text"> 246 <property name="text">
320 <string/> 247 <string>Delete</string>
321 </property> 248 </property>
322 </widget> 249 </widget>
323 </item> 250 </item>
324 </layout> 251 </layout>
325 </item> 252 </widget>
326 </layout> 253 </item>
327 </widget> 254 </layout>
328 </item> 255 </item>
329 <item row="0" column="0"> 256 <item>
330 <widget class="QGroupBox" name="faceButtons"> 257 <widget class="QFrame" name="bottom">
331 <property name="title"> 258 <property name="sizePolicy">
332 <string>Face Buttons</string> 259 <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
333 </property> 260 <horstretch>0</horstretch>
334 <property name="flat"> 261 <verstretch>0</verstretch>
335 <bool>false</bool> 262 </sizepolicy>
336 </property>
337 <property name="checkable">
338 <bool>false</bool>
339 </property> 263 </property>
340 <layout class="QGridLayout" name="gridLayout"> 264 <layout class="QHBoxLayout" name="_2">
341 <item row="0" column="0"> 265 <property name="sizeConstraint">
342 <layout class="QVBoxLayout" name="buttonFaceButtonsAVerticalLayout"> 266 <enum>QLayout::SetMinimumSize</enum>
343 <item> 267 </property>
344 <layout class="QHBoxLayout" name="buttonFaceButtonsAHorizontalLayout"> 268 <property name="leftMargin">
345 <item> 269 <number>0</number>
346 <widget class="QLabel" name="labelA"> 270 </property>
347 <property name="minimumSize"> 271 <property name="topMargin">
348 <size> 272 <number>0</number>
349 <width>80</width> 273 </property>
350 <height>0</height> 274 <property name="rightMargin">
351 </size> 275 <number>0</number>
276 </property>
277 <property name="bottomMargin">
278 <number>0</number>
279 </property>
280 <item>
281 <widget class="QWidget" name="bottomLeft" native="true">
282 <layout class="QVBoxLayout" name="bottomLeftLayout" stretch="0,0,0,0">
283 <property name="spacing">
284 <number>0</number>
285 </property>
286 <property name="sizeConstraint">
287 <enum>QLayout::SetDefaultConstraint</enum>
288 </property>
289 <property name="leftMargin">
290 <number>0</number>
291 </property>
292 <property name="topMargin">
293 <number>0</number>
294 </property>
295 <property name="rightMargin">
296 <number>0</number>
297 </property>
298 <property name="bottomMargin">
299 <number>0</number>
300 </property>
301 <item>
302 <widget class="QGroupBox" name="LStick">
303 <property name="sizePolicy">
304 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
305 <horstretch>0</horstretch>
306 <verstretch>0</verstretch>
307 </sizepolicy>
308 </property>
309 <property name="title">
310 <string>Left Stick</string>
311 </property>
312 <property name="alignment">
313 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
314 </property>
315 <layout class="QVBoxLayout" name="verticalLayout_3">
316 <property name="spacing">
317 <number>0</number>
352 </property> 318 </property>
353 <property name="text"> 319 <property name="sizeConstraint">
354 <string>A:</string> 320 <enum>QLayout::SetDefaultConstraint</enum>
355 </property> 321 </property>
356 </widget> 322 <property name="leftMargin">
357 </item> 323 <number>3</number>
358 </layout>
359 </item>
360 <item>
361 <widget class="QPushButton" name="buttonA">
362 <property name="text">
363 <string/>
364 </property>
365 </widget>
366 </item>
367 </layout>
368 </item>
369 <item row="0" column="1">
370 <layout class="QVBoxLayout" name="buttonFaceButtonsBVerticalLayout">
371 <item>
372 <layout class="QHBoxLayout" name="buttonFaceButtonsBHorizontalLayout">
373 <item>
374 <widget class="QLabel" name="labelB">
375 <property name="minimumSize">
376 <size>
377 <width>80</width>
378 <height>0</height>
379 </size>
380 </property> 324 </property>
381 <property name="text"> 325 <property name="topMargin">
382 <string>B:</string> 326 <number>0</number>
383 </property> 327 </property>
384 </widget> 328 <property name="rightMargin">
385 </item> 329 <number>3</number>
386 </layout>
387 </item>
388 <item>
389 <widget class="QPushButton" name="buttonB">
390 <property name="text">
391 <string/>
392 </property>
393 </widget>
394 </item>
395 </layout>
396 </item>
397 <item row="1" column="0">
398 <layout class="QVBoxLayout" name="buttonFaceButtonsXVerticalLayout">
399 <item>
400 <layout class="QHBoxLayout" name="buttonFaceButtonsXHorizontalLayout">
401 <item>
402 <widget class="QLabel" name="labelX">
403 <property name="text">
404 <string>X:</string>
405 </property> 330 </property>
406 </widget> 331 <property name="bottomMargin">
407 </item> 332 <number>0</number>
408 </layout>
409 </item>
410 <item>
411 <widget class="QPushButton" name="buttonX">
412 <property name="text">
413 <string/>
414 </property>
415 </widget>
416 </item>
417 </layout>
418 </item>
419 <item row="1" column="1">
420 <layout class="QVBoxLayout" name="buttonFaceButtonsYVerticalLayout">
421 <item>
422 <layout class="QHBoxLayout" name="buttonFaceButtonsYHorizontalLayout">
423 <item>
424 <widget class="QLabel" name="labelY">
425 <property name="text">
426 <string>Y:</string>
427 </property> 333 </property>
428 </widget> 334 <item>
429 </item> 335 <widget class="QWidget" name="buttonLStickUpWidget" native="true">
430 </layout> 336 <layout class="QHBoxLayout" name="horizontalLayout_20">
431 </item> 337 <property name="spacing">
432 <item> 338 <number>0</number>
433 <widget class="QPushButton" name="buttonY"> 339 </property>
434 <property name="text"> 340 <property name="leftMargin">
435 <string/> 341 <number>0</number>
436 </property> 342 </property>
437 </widget> 343 <property name="topMargin">
438 </item> 344 <number>0</number>
439 </layout> 345 </property>
440 </item> 346 <property name="rightMargin">
441 </layout> 347 <number>0</number>
442 </widget> 348 </property>
443 </item> 349 <property name="bottomMargin">
444 <item row="5" column="0" colspan="2"> 350 <number>0</number>
445 <widget class="QGroupBox" name="controller_color"> 351 </property>
446 <property name="title"> 352 <item>
447 <string>Controller Color</string> 353 <spacer name="horizontalSpacerLStickUpLeft">
448 </property> 354 <property name="orientation">
449 <layout class="QGridLayout" name="gridLayout_10" columnstretch="0,0,0,0,0,0,0"> 355 <enum>Qt::Horizontal</enum>
450 <item row="0" column="0"> 356 </property>
451 <spacer name="horizontalSpacer_2"> 357 <property name="sizeHint" stdset="0">
452 <property name="orientation"> 358 <size>
453 <enum>Qt::Horizontal</enum> 359 <width>20</width>
454 </property> 360 <height>20</height>
455 <property name="sizeHint" stdset="0"> 361 </size>
456 <size> 362 </property>
457 <width>40</width> 363 </spacer>
458 <height>20</height> 364 </item>
459 </size> 365 <item alignment="Qt::AlignHCenter">
460 </property> 366 <widget class="QGroupBox" name="buttonLStickUpGroup">
461 </spacer> 367 <property name="title">
462 </item> 368 <string>Up</string>
463 <item row="0" column="1"> 369 </property>
464 <widget class="QLabel" name="left_body_label"> 370 <property name="alignment">
465 <property name="text"> 371 <set>Qt::AlignCenter</set>
466 <string>Left Body</string> 372 </property>
467 </property> 373 <property name="flat">
468 </widget> 374 <bool>false</bool>
469 </item> 375 </property>
470 <item row="0" column="6"> 376 <layout class="QVBoxLayout" name="buttonLStickUpVerticalLayout">
471 <spacer name="horizontalSpacer_3"> 377 <property name="spacing">
472 <property name="orientation"> 378 <number>3</number>
473 <enum>Qt::Horizontal</enum> 379 </property>
474 </property> 380 <property name="leftMargin">
475 <property name="sizeHint" stdset="0"> 381 <number>3</number>
476 <size> 382 </property>
477 <width>40</width> 383 <property name="topMargin">
478 <height>20</height> 384 <number>3</number>
479 </size> 385 </property>
480 </property> 386 <property name="rightMargin">
481 </spacer> 387 <number>3</number>
482 </item> 388 </property>
483 <item row="1" column="1"> 389 <property name="bottomMargin">
484 <widget class="QLabel" name="left_buttons_label"> 390 <number>3</number>
485 <property name="minimumSize"> 391 </property>
486 <size> 392 <item>
487 <width>90</width> 393 <widget class="QPushButton" name="buttonLStickUp">
488 <height>0</height> 394 <property name="minimumSize">
489 </size> 395 <size>
490 </property> 396 <width>57</width>
491 <property name="text"> 397 <height>0</height>
492 <string>Left Buttons</string> 398 </size>
493 </property> 399 </property>
494 </widget> 400 <property name="maximumSize">
495 </item> 401 <size>
496 <item row="1" column="5"> 402 <width>55</width>
497 <widget class="QPushButton" name="right_buttons_button"> 403 <height>16777215</height>
498 <property name="sizePolicy"> 404 </size>
499 <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> 405 </property>
500 <horstretch>0</horstretch> 406 <property name="styleSheet">
501 <verstretch>0</verstretch> 407 <string notr="true">min-width: 55px;</string>
502 </sizepolicy> 408 </property>
503 </property> 409 <property name="text">
504 <property name="minimumSize"> 410 <string>Up</string>
505 <size> 411 </property>
506 <width>32</width> 412 </widget>
507 <height>0</height> 413 </item>
508 </size> 414 </layout>
509 </property> 415 </widget>
510 <property name="maximumSize"> 416 </item>
511 <size> 417 <item>
512 <width>40</width> 418 <spacer name="horizontalSpacerLStickUpRight">
513 <height>16777215</height> 419 <property name="orientation">
514 </size> 420 <enum>Qt::Horizontal</enum>
515 </property> 421 </property>
516 <property name="text"> 422 <property name="sizeHint" stdset="0">
517 <string/> 423 <size>
518 </property> 424 <width>20</width>
519 </widget> 425 <height>20</height>
520 </item> 426 </size>
521 <item row="0" column="4"> 427 </property>
522 <widget class="QLabel" name="right_body_label"> 428 </spacer>
523 <property name="text"> 429 </item>
524 <string>Right Body</string> 430 </layout>
525 </property> 431 </widget>
526 </widget> 432 </item>
527 </item> 433 <item>
528 <item row="1" column="4"> 434 <layout class="QHBoxLayout" name="buttonLStickLeftRightHorizontaLayout">
529 <widget class="QLabel" name="right_buttons_label"> 435 <property name="spacing">
530 <property name="minimumSize"> 436 <number>3</number>
531 <size> 437 </property>
532 <width>90</width> 438 <item alignment="Qt::AlignHCenter">
533 <height>0</height> 439 <widget class="QGroupBox" name="buttonLStickLeftGroup">
534 </size> 440 <property name="title">
535 </property> 441 <string>Left</string>
536 <property name="text"> 442 </property>
537 <string>Right Buttons</string> 443 <property name="alignment">
538 </property> 444 <set>Qt::AlignCenter</set>
539 </widget> 445 </property>
540 </item> 446 <layout class="QVBoxLayout" name="buttonLStickLeftVerticalLayout">
541 <item row="1" column="2"> 447 <property name="spacing">
542 <widget class="QPushButton" name="left_buttons_button"> 448 <number>3</number>
543 <property name="sizePolicy"> 449 </property>
544 <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> 450 <property name="leftMargin">
545 <horstretch>0</horstretch> 451 <number>3</number>
546 <verstretch>0</verstretch> 452 </property>
547 </sizepolicy> 453 <property name="topMargin">
548 </property> 454 <number>3</number>
549 <property name="minimumSize"> 455 </property>
550 <size> 456 <property name="rightMargin">
551 <width>32</width> 457 <number>3</number>
552 <height>0</height> 458 </property>
553 </size> 459 <property name="bottomMargin">
554 </property> 460 <number>3</number>
555 <property name="maximumSize"> 461 </property>
556 <size> 462 <item>
557 <width>40</width> 463 <widget class="QPushButton" name="buttonLStickLeft">
558 <height>16777215</height> 464 <property name="minimumSize">
559 </size> 465 <size>
560 </property> 466 <width>57</width>
561 <property name="text"> 467 <height>0</height>
562 <string/> 468 </size>
563 </property> 469 </property>
564 </widget> 470 <property name="maximumSize">
565 </item> 471 <size>
566 <item row="0" column="2"> 472 <width>55</width>
567 <widget class="QPushButton" name="left_body_button"> 473 <height>16777215</height>
568 <property name="sizePolicy"> 474 </size>
569 <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> 475 </property>
570 <horstretch>0</horstretch> 476 <property name="styleSheet">
571 <verstretch>0</verstretch> 477 <string notr="true">min-width: 55px;</string>
572 </sizepolicy> 478 </property>
573 </property> 479 <property name="text">
574 <property name="minimumSize"> 480 <string>Left</string>
575 <size> 481 </property>
576 <width>32</width> 482 </widget>
577 <height>0</height> 483 </item>
578 </size> 484 </layout>
579 </property> 485 </widget>
580 <property name="maximumSize"> 486 </item>
581 <size> 487 <item alignment="Qt::AlignHCenter">
582 <width>40</width> 488 <widget class="QGroupBox" name="buttonLStickRightGroup">
583 <height>16777215</height> 489 <property name="title">
584 </size> 490 <string>Right</string>
585 </property> 491 </property>
586 <property name="text"> 492 <property name="alignment">
587 <string/> 493 <set>Qt::AlignCenter</set>
588 </property> 494 </property>
589 </widget> 495 <layout class="QVBoxLayout" name="buttonLStickRightVerticalLayout">
590 </item> 496 <property name="spacing">
591 <item row="0" column="5"> 497 <number>3</number>
592 <widget class="QPushButton" name="right_body_button"> 498 </property>
593 <property name="sizePolicy"> 499 <property name="leftMargin">
594 <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> 500 <number>3</number>
595 <horstretch>0</horstretch> 501 </property>
596 <verstretch>0</verstretch> 502 <property name="topMargin">
597 </sizepolicy> 503 <number>3</number>
598 </property> 504 </property>
599 <property name="minimumSize"> 505 <property name="rightMargin">
600 <size> 506 <number>3</number>
601 <width>32</width> 507 </property>
602 <height>0</height> 508 <property name="bottomMargin">
603 </size> 509 <number>3</number>
604 </property> 510 </property>
605 <property name="maximumSize"> 511 <item>
606 <size> 512 <widget class="QPushButton" name="buttonLStickRight">
607 <width>40</width> 513 <property name="minimumSize">
608 <height>16777215</height> 514 <size>
609 </size> 515 <width>57</width>
610 </property> 516 <height>0</height>
611 <property name="text"> 517 </size>
612 <string/> 518 </property>
613 </property> 519 <property name="maximumSize">
614 </widget> 520 <size>
615 </item> 521 <width>55</width>
616 <item row="0" column="3"> 522 <height>16777215</height>
617 <spacer name="horizontalSpacer_4"> 523 </size>
618 <property name="orientation"> 524 </property>
619 <enum>Qt::Horizontal</enum> 525 <property name="styleSheet">
620 </property> 526 <string notr="true">min-width: 55px;</string>
621 <property name="sizeType"> 527 </property>
622 <enum>QSizePolicy::Fixed</enum> 528 <property name="text">
623 </property> 529 <string>Right</string>
624 <property name="sizeHint" stdset="0"> 530 </property>
625 <size> 531 </widget>
626 <width>20</width> 532 </item>
627 <height>20</height> 533 </layout>
628 </size> 534 </widget>
629 </property> 535 </item>
630 </spacer> 536 </layout>
631 </item> 537 </item>
632 </layout> 538 <item>
633 </widget> 539 <widget class="QWidget" name="buttonLStickDownWidget" native="true">
634 </item> 540 <layout class="QHBoxLayout" name="horizontalLayout_22">
635 <item row="1" column="0"> 541 <property name="spacing">
636 <widget class="QGroupBox" name="LStick"> 542 <number>0</number>
637 <property name="title"> 543 </property>
638 <string>Left Stick</string> 544 <property name="leftMargin">
639 </property> 545 <number>0</number>
640 <property name="flat"> 546 </property>
641 <bool>false</bool> 547 <property name="topMargin">
642 </property> 548 <number>0</number>
643 <property name="checkable"> 549 </property>
644 <bool>false</bool> 550 <property name="rightMargin">
645 </property> 551 <number>0</number>
646 <layout class="QGridLayout" name="gridLayout_4"> 552 </property>
647 <item row="1" column="1"> 553 <property name="bottomMargin">
648 <layout class="QVBoxLayout" name="buttonLStickUpVerticalLayout"> 554 <number>0</number>
649 <item> 555 </property>
650 <layout class="QHBoxLayout" name="buttonLStickUpHorizontalLayout"> 556 <item>
651 <item> 557 <spacer name="horizontalSpacerLStickDownLeft">
652 <widget class="QLabel" name="labelLStickUp"> 558 <property name="orientation">
653 <property name="text"> 559 <enum>Qt::Horizontal</enum>
654 <string>Up:</string> 560 </property>
561 <property name="sizeHint" stdset="0">
562 <size>
563 <width>20</width>
564 <height>20</height>
565 </size>
566 </property>
567 </spacer>
568 </item>
569 <item alignment="Qt::AlignHCenter">
570 <widget class="QGroupBox" name="buttonLStickDownGroup">
571 <property name="title">
572 <string>Down</string>
573 </property>
574 <property name="alignment">
575 <set>Qt::AlignCenter</set>
576 </property>
577 <layout class="QVBoxLayout" name="buttonLStickDownVerticalLayout">
578 <property name="spacing">
579 <number>3</number>
580 </property>
581 <property name="leftMargin">
582 <number>3</number>
583 </property>
584 <property name="topMargin">
585 <number>3</number>
586 </property>
587 <property name="rightMargin">
588 <number>3</number>
589 </property>
590 <property name="bottomMargin">
591 <number>3</number>
592 </property>
593 <item>
594 <widget class="QPushButton" name="buttonLStickDown">
595 <property name="minimumSize">
596 <size>
597 <width>57</width>
598 <height>0</height>
599 </size>
600 </property>
601 <property name="maximumSize">
602 <size>
603 <width>55</width>
604 <height>16777215</height>
605 </size>
606 </property>
607 <property name="styleSheet">
608 <string notr="true">min-width: 55px;</string>
609 </property>
610 <property name="text">
611 <string>Down</string>
612 </property>
613 </widget>
614 </item>
615 </layout>
616 </widget>
617 </item>
618 <item>
619 <spacer name="horizontalSpacerLStickDownRight">
620 <property name="orientation">
621 <enum>Qt::Horizontal</enum>
622 </property>
623 <property name="sizeHint" stdset="0">
624 <size>
625 <width>20</width>
626 <height>20</height>
627 </size>
628 </property>
629 </spacer>
630 </item>
631 </layout>
632 </widget>
633 </item>
634 <item>
635 <layout class="QHBoxLayout" name="buttonLStickPressedModifierHorizontalLayout">
636 <property name="spacing">
637 <number>3</number>
638 </property>
639 <item alignment="Qt::AlignHCenter">
640 <widget class="QGroupBox" name="buttonLStickPressedGroup">
641 <property name="title">
642 <string>Pressed</string>
643 </property>
644 <property name="alignment">
645 <set>Qt::AlignCenter</set>
646 </property>
647 <layout class="QVBoxLayout" name="buttonLStickPressedVerticalLayout" stretch="0">
648 <property name="spacing">
649 <number>3</number>
650 </property>
651 <property name="leftMargin">
652 <number>3</number>
653 </property>
654 <property name="topMargin">
655 <number>3</number>
656 </property>
657 <property name="rightMargin">
658 <number>3</number>
659 </property>
660 <property name="bottomMargin">
661 <number>3</number>
662 </property>
663 <item>
664 <widget class="QPushButton" name="buttonLStick">
665 <property name="minimumSize">
666 <size>
667 <width>57</width>
668 <height>0</height>
669 </size>
670 </property>
671 <property name="maximumSize">
672 <size>
673 <width>55</width>
674 <height>16777215</height>
675 </size>
676 </property>
677 <property name="styleSheet">
678 <string notr="true">min-width: 55px;</string>
679 </property>
680 <property name="text">
681 <string>Pressed</string>
682 </property>
683 </widget>
684 </item>
685 </layout>
686 </widget>
687 </item>
688 <item alignment="Qt::AlignHCenter">
689 <widget class="QGroupBox" name="buttonLStickModGroup">
690 <property name="title">
691 <string>Modifier</string>
692 </property>
693 <property name="alignment">
694 <set>Qt::AlignCenter</set>
695 </property>
696 <layout class="QVBoxLayout" name="buttonLStickModVerticalLayout">
697 <property name="spacing">
698 <number>3</number>
699 </property>
700 <property name="leftMargin">
701 <number>3</number>
702 </property>
703 <property name="topMargin">
704 <number>3</number>
705 </property>
706 <property name="rightMargin">
707 <number>3</number>
708 </property>
709 <property name="bottomMargin">
710 <number>3</number>
711 </property>
712 <item>
713 <widget class="QPushButton" name="buttonLStickMod">
714 <property name="minimumSize">
715 <size>
716 <width>57</width>
717 <height>0</height>
718 </size>
719 </property>
720 <property name="maximumSize">
721 <size>
722 <width>55</width>
723 <height>16777215</height>
724 </size>
725 </property>
726 <property name="styleSheet">
727 <string notr="true">min-width: 55px;</string>
728 </property>
729 <property name="text">
730 <string>Modifier</string>
731 </property>
732 </widget>
733 </item>
734 </layout>
735 </widget>
736 </item>
737 <item>
738 <widget class="QGroupBox" name="buttonLStickRangeGroup">
739 <property name="title">
740 <string>Range</string>
741 </property>
742 <layout class="QHBoxLayout" name="buttonLStickRangeGroupHorizontalLayout">
743 <property name="spacing">
744 <number>3</number>
745 </property>
746 <property name="leftMargin">
747 <number>3</number>
748 </property>
749 <property name="topMargin">
750 <number>3</number>
751 </property>
752 <property name="rightMargin">
753 <number>3</number>
754 </property>
755 <property name="bottomMargin">
756 <number>3</number>
757 </property>
758 <item>
759 <widget class="QSpinBox" name="spinboxLStickRange">
760 <property name="minimumSize">
761 <size>
762 <width>55</width>
763 <height>21</height>
764 </size>
765 </property>
766 <property name="maximumSize">
767 <size>
768 <width>55</width>
769 <height>16777215</height>
770 </size>
771 </property>
772 <property name="suffix">
773 <string>%</string>
774 </property>
775 <property name="minimum">
776 <number>50</number>
777 </property>
778 <property name="maximum">
779 <number>150</number>
780 </property>
781 <property name="value">
782 <number>100</number>
783 </property>
784 </widget>
785 </item>
786 </layout>
787 </widget>
788 </item>
789 </layout>
790 </item>
791 <item>
792 <layout class="QVBoxLayout" name="sliderLStickDeadzoneModifierRangeVerticalLayout">
793 <property name="spacing">
794 <number>3</number>
795 </property>
796 <property name="sizeConstraint">
797 <enum>QLayout::SetDefaultConstraint</enum>
798 </property>
799 <property name="leftMargin">
800 <number>0</number>
801 </property>
802 <property name="topMargin">
803 <number>2</number>
804 </property>
805 <property name="rightMargin">
806 <number>0</number>
807 </property>
808 <property name="bottomMargin">
809 <number>3</number>
810 </property>
811 <item>
812 <layout class="QHBoxLayout" name="sliderLStickDeadzoneHorizontalLayout">
813 <item>
814 <widget class="QLabel" name="labelLStickDeadzone">
815 <property name="text">
816 <string>Deadzone: 0%</string>
817 </property>
818 <property name="alignment">
819 <set>Qt::AlignHCenter</set>
820 </property>
821 </widget>
822 </item>
823 </layout>
824 </item>
825 <item>
826 <widget class="QSlider" name="sliderLStickDeadzone">
827 <property name="maximum">
828 <number>100</number>
829 </property>
830 <property name="orientation">
831 <enum>Qt::Horizontal</enum>
832 </property>
833 </widget>
834 </item>
835 <item>
836 <layout class="QHBoxLayout" name="sliderLStickModifierRangeHorizontalLayout">
837 <item>
838 <widget class="QLabel" name="labelLStickModifierRange">
839 <property name="text">
840 <string>Modifier Range: 0%</string>
841 </property>
842 <property name="alignment">
843 <set>Qt::AlignHCenter</set>
844 </property>
845 </widget>
846 </item>
847 </layout>
848 </item>
849 <item>
850 <widget class="QSlider" name="sliderLStickModifierRange">
851 <property name="maximum">
852 <number>100</number>
853 </property>
854 <property name="orientation">
855 <enum>Qt::Horizontal</enum>
856 </property>
857 </widget>
858 </item>
859 </layout>
860 </item>
861 </layout>
862 </widget>
863 </item>
864 <item>
865 <spacer name="verticalSpacerBottomLeft">
866 <property name="orientation">
867 <enum>Qt::Vertical</enum>
868 </property>
869 <property name="sizeHint" stdset="0">
870 <size>
871 <width>20</width>
872 <height>0</height>
873 </size>
874 </property>
875 </spacer>
876 </item>
877 <item>
878 <widget class="QGroupBox" name="Dpad">
879 <property name="sizePolicy">
880 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
881 <horstretch>0</horstretch>
882 <verstretch>0</verstretch>
883 </sizepolicy>
884 </property>
885 <property name="title">
886 <string>D-Pad</string>
887 </property>
888 <property name="flat">
889 <bool>false</bool>
890 </property>
891 <property name="checkable">
892 <bool>false</bool>
893 </property>
894 <layout class="QVBoxLayout" name="verticalLayout_5">
895 <property name="spacing">
896 <number>0</number>
655 </property> 897 </property>
656 </widget> 898 <property name="leftMargin">
657 </item> 899 <number>3</number>
658 </layout>
659 </item>
660 <item>
661 <widget class="QPushButton" name="buttonLStickUp">
662 <property name="text">
663 <string/>
664 </property>
665 </widget>
666 </item>
667 </layout>
668 </item>
669 <item row="0" column="2">
670 <layout class="QVBoxLayout" name="buttonLStickRightVerticalLayout">
671 <item>
672 <layout class="QHBoxLayout" name="buttonLStickRightHorizontalLayout">
673 <item>
674 <widget class="QLabel" name="labelLStickRight">
675 <property name="text">
676 <string>Right:</string>
677 </property> 900 </property>
678 </widget> 901 <property name="topMargin">
679 </item> 902 <number>0</number>
680 </layout>
681 </item>
682 <item>
683 <widget class="QPushButton" name="buttonLStickRight">
684 <property name="text">
685 <string/>
686 </property>
687 </widget>
688 </item>
689 </layout>
690 </item>
691 <item row="4" column="1" colspan="2">
692 <widget class="QPushButton" name="buttonLStickAnalog">
693 <property name="text">
694 <string>Set Analog Stick</string>
695 </property>
696 </widget>
697 </item>
698 <item row="0" column="1">
699 <layout class="QVBoxLayout" name="buttonLStickLeftVerticalLayout">
700 <item>
701 <layout class="QHBoxLayout" name="buttonLStickLeftHorizontalLayout_2">
702 <item>
703 <widget class="QLabel" name="labelLStickLeft">
704 <property name="text">
705 <string>Left:</string>
706 </property> 903 </property>
707 </widget> 904 <property name="rightMargin">
708 </item> 905 <number>3</number>
709 </layout>
710 </item>
711 <item>
712 <widget class="QPushButton" name="buttonLStickLeft">
713 <property name="text">
714 <string/>
715 </property>
716 </widget>
717 </item>
718 </layout>
719 </item>
720 <item row="1" column="2">
721 <layout class="QVBoxLayout" name="buttonLStickDownVerticalLayout">
722 <item>
723 <layout class="QHBoxLayout" name="buttonLStickDownHorizontalLayout">
724 <item>
725 <widget class="QLabel" name="labelLStickDown">
726 <property name="text">
727 <string>Down:</string>
728 </property> 906 </property>
729 </widget> 907 <property name="bottomMargin">
730 </item> 908 <number>3</number>
731 </layout>
732 </item>
733 <item>
734 <widget class="QPushButton" name="buttonLStickDown">
735 <property name="text">
736 <string/>
737 </property>
738 </widget>
739 </item>
740 </layout>
741 </item>
742 <item row="3" column="2">
743 <layout class="QVBoxLayout" name="buttonLStickModVerticalLayout">
744 <item>
745 <layout class="QHBoxLayout" name="buttonLStickModHorizontalLayout">
746 <item>
747 <widget class="QLabel" name="labelLStickMod">
748 <property name="text">
749 <string>Modifier:</string>
750 </property> 909 </property>
751 </widget> 910 <item>
752 </item> 911 <widget class="QWidget" name="buttonDpadUpWidget" native="true">
753 </layout> 912 <layout class="QHBoxLayout" name="horizontalLayout_23">
754 </item> 913 <property name="spacing">
755 <item> 914 <number>0</number>
756 <widget class="QPushButton" name="buttonLStickMod"> 915 </property>
757 <property name="text"> 916 <property name="leftMargin">
758 <string/> 917 <number>0</number>
759 </property> 918 </property>
760 </widget> 919 <property name="topMargin">
761 </item> 920 <number>0</number>
762 </layout> 921 </property>
922 <property name="rightMargin">
923 <number>0</number>
924 </property>
925 <property name="bottomMargin">
926 <number>0</number>
927 </property>
928 <item>
929 <spacer name="horizontalSpacerDpadUpLeft">
930 <property name="orientation">
931 <enum>Qt::Horizontal</enum>
932 </property>
933 <property name="sizeHint" stdset="0">
934 <size>
935 <width>20</width>
936 <height>20</height>
937 </size>
938 </property>
939 </spacer>
940 </item>
941 <item alignment="Qt::AlignHCenter">
942 <widget class="QGroupBox" name="buttonDpadUpGroup">
943 <property name="title">
944 <string>Up</string>
945 </property>
946 <property name="alignment">
947 <set>Qt::AlignCenter</set>
948 </property>
949 <layout class="QVBoxLayout" name="buttonDpadUpVerticalLayout">
950 <property name="spacing">
951 <number>3</number>
952 </property>
953 <property name="leftMargin">
954 <number>3</number>
955 </property>
956 <property name="topMargin">
957 <number>3</number>
958 </property>
959 <property name="rightMargin">
960 <number>3</number>
961 </property>
962 <property name="bottomMargin">
963 <number>3</number>
964 </property>
965 <item>
966 <widget class="QPushButton" name="buttonDpadUp">
967 <property name="minimumSize">
968 <size>
969 <width>57</width>
970 <height>0</height>
971 </size>
972 </property>
973 <property name="maximumSize">
974 <size>
975 <width>55</width>
976 <height>16777215</height>
977 </size>
978 </property>
979 <property name="styleSheet">
980 <string notr="true">min-width: 55px;</string>
981 </property>
982 <property name="text">
983 <string>Up</string>
984 </property>
985 </widget>
986 </item>
987 </layout>
988 </widget>
989 </item>
990 <item>
991 <spacer name="horizontalSpacerDpadUpRight">
992 <property name="orientation">
993 <enum>Qt::Horizontal</enum>
994 </property>
995 <property name="sizeHint" stdset="0">
996 <size>
997 <width>20</width>
998 <height>20</height>
999 </size>
1000 </property>
1001 </spacer>
1002 </item>
1003 </layout>
1004 </widget>
1005 </item>
1006 <item>
1007 <layout class="QHBoxLayout" name="buttonDpadLeftRightHorizontalLayout">
1008 <property name="spacing">
1009 <number>3</number>
1010 </property>
1011 <item alignment="Qt::AlignHCenter">
1012 <widget class="QGroupBox" name="buttonDpadLeftGroup">
1013 <property name="title">
1014 <string>Left</string>
1015 </property>
1016 <property name="alignment">
1017 <set>Qt::AlignCenter</set>
1018 </property>
1019 <layout class="QVBoxLayout" name="buttonDpadLeftVerticalLayout">
1020 <property name="spacing">
1021 <number>3</number>
1022 </property>
1023 <property name="leftMargin">
1024 <number>3</number>
1025 </property>
1026 <property name="topMargin">
1027 <number>3</number>
1028 </property>
1029 <property name="rightMargin">
1030 <number>3</number>
1031 </property>
1032 <property name="bottomMargin">
1033 <number>3</number>
1034 </property>
1035 <item>
1036 <widget class="QPushButton" name="buttonDpadLeft">
1037 <property name="minimumSize">
1038 <size>
1039 <width>57</width>
1040 <height>0</height>
1041 </size>
1042 </property>
1043 <property name="maximumSize">
1044 <size>
1045 <width>55</width>
1046 <height>16777215</height>
1047 </size>
1048 </property>
1049 <property name="styleSheet">
1050 <string notr="true">min-width: 55px;</string>
1051 </property>
1052 <property name="text">
1053 <string>Left</string>
1054 </property>
1055 </widget>
1056 </item>
1057 </layout>
1058 </widget>
1059 </item>
1060 <item alignment="Qt::AlignHCenter">
1061 <widget class="QGroupBox" name="buttonDpadRightGroup">
1062 <property name="title">
1063 <string>Right</string>
1064 </property>
1065 <property name="alignment">
1066 <set>Qt::AlignCenter</set>
1067 </property>
1068 <layout class="QVBoxLayout" name="buttonDpadRightVerticalLayout">
1069 <property name="spacing">
1070 <number>3</number>
1071 </property>
1072 <property name="leftMargin">
1073 <number>3</number>
1074 </property>
1075 <property name="topMargin">
1076 <number>3</number>
1077 </property>
1078 <property name="rightMargin">
1079 <number>3</number>
1080 </property>
1081 <property name="bottomMargin">
1082 <number>3</number>
1083 </property>
1084 <item>
1085 <widget class="QPushButton" name="buttonDpadRight">
1086 <property name="minimumSize">
1087 <size>
1088 <width>57</width>
1089 <height>0</height>
1090 </size>
1091 </property>
1092 <property name="maximumSize">
1093 <size>
1094 <width>55</width>
1095 <height>16777215</height>
1096 </size>
1097 </property>
1098 <property name="styleSheet">
1099 <string notr="true">min-width: 55px;</string>
1100 </property>
1101 <property name="text">
1102 <string>Right</string>
1103 </property>
1104 </widget>
1105 </item>
1106 </layout>
1107 </widget>
1108 </item>
1109 </layout>
1110 </item>
1111 <item>
1112 <widget class="QWidget" name="buttonDpadDownWidget" native="true">
1113 <layout class="QHBoxLayout" name="horizontalLayout_24">
1114 <property name="spacing">
1115 <number>0</number>
1116 </property>
1117 <property name="leftMargin">
1118 <number>0</number>
1119 </property>
1120 <property name="topMargin">
1121 <number>0</number>
1122 </property>
1123 <property name="rightMargin">
1124 <number>0</number>
1125 </property>
1126 <property name="bottomMargin">
1127 <number>0</number>
1128 </property>
1129 <item>
1130 <spacer name="horizontalSpacerDpadDownLeft">
1131 <property name="orientation">
1132 <enum>Qt::Horizontal</enum>
1133 </property>
1134 <property name="sizeHint" stdset="0">
1135 <size>
1136 <width>20</width>
1137 <height>20</height>
1138 </size>
1139 </property>
1140 </spacer>
1141 </item>
1142 <item alignment="Qt::AlignHCenter">
1143 <widget class="QGroupBox" name="buttonDpadDownGroup">
1144 <property name="title">
1145 <string>Down</string>
1146 </property>
1147 <property name="alignment">
1148 <set>Qt::AlignCenter</set>
1149 </property>
1150 <layout class="QVBoxLayout" name="buttonDpadDownVerticalLayout">
1151 <property name="spacing">
1152 <number>3</number>
1153 </property>
1154 <property name="leftMargin">
1155 <number>3</number>
1156 </property>
1157 <property name="topMargin">
1158 <number>3</number>
1159 </property>
1160 <property name="rightMargin">
1161 <number>3</number>
1162 </property>
1163 <property name="bottomMargin">
1164 <number>3</number>
1165 </property>
1166 <item>
1167 <widget class="QPushButton" name="buttonDpadDown">
1168 <property name="minimumSize">
1169 <size>
1170 <width>57</width>
1171 <height>0</height>
1172 </size>
1173 </property>
1174 <property name="maximumSize">
1175 <size>
1176 <width>55</width>
1177 <height>16777215</height>
1178 </size>
1179 </property>
1180 <property name="styleSheet">
1181 <string notr="true">min-width: 55px;</string>
1182 </property>
1183 <property name="text">
1184 <string>Down</string>
1185 </property>
1186 </widget>
1187 </item>
1188 </layout>
1189 </widget>
1190 </item>
1191 <item>
1192 <spacer name="horizontalSpacerDpadDownRight">
1193 <property name="orientation">
1194 <enum>Qt::Horizontal</enum>
1195 </property>
1196 <property name="sizeHint" stdset="0">
1197 <size>
1198 <width>20</width>
1199 <height>20</height>
1200 </size>
1201 </property>
1202 </spacer>
1203 </item>
1204 </layout>
1205 </widget>
1206 </item>
1207 </layout>
1208 </widget>
1209 </item>
1210 <item>
1211 <spacer name="verticalSpacerBottomLeft_2">
1212 <property name="orientation">
1213 <enum>Qt::Vertical</enum>
1214 </property>
1215 <property name="sizeHint" stdset="0">
1216 <size>
1217 <width>20</width>
1218 <height>0</height>
1219 </size>
1220 </property>
1221 </spacer>
1222 </item>
1223 </layout>
1224 </widget>
763 </item> 1225 </item>
764 <item row="3" column="1"> 1226 <item>
765 <layout class="QVBoxLayout" name="buttonLStickPressedVerticalLayout" stretch="0,0"> 1227 <widget class="QWidget" name="bottomMiddle" native="true">
766 <item> 1228 <layout class="QVBoxLayout" stretch="0,0,0">
767 <layout class="QHBoxLayout" name="buttonLStickPressedHorizontalLayout"> 1229 <property name="spacing">
768 <item> 1230 <number>6</number>
769 <widget class="QLabel" name="labelLStickPressed"> 1231 </property>
770 <property name="text"> 1232 <property name="leftMargin">
771 <string>Pressed:</string> 1233 <number>0</number>
1234 </property>
1235 <property name="topMargin">
1236 <number>0</number>
1237 </property>
1238 <property name="rightMargin">
1239 <number>0</number>
1240 </property>
1241 <property name="bottomMargin">
1242 <number>0</number>
1243 </property>
1244 <item>
1245 <layout class="QHBoxLayout" name="shoulderButtons">
1246 <property name="spacing">
1247 <number>3</number>
1248 </property>
1249 <item>
1250 <widget class="QWidget" name="buttonShoulderButtonsLeft" native="true">
1251 <layout class="QVBoxLayout" name="buttonShoulderButtonsLeftVerticalLayout">
1252 <property name="spacing">
1253 <number>0</number>
1254 </property>
1255 <property name="leftMargin">
1256 <number>0</number>
1257 </property>
1258 <property name="topMargin">
1259 <number>0</number>
1260 </property>
1261 <property name="rightMargin">
1262 <number>0</number>
1263 </property>
1264 <property name="bottomMargin">
1265 <number>0</number>
1266 </property>
1267 <item>
1268 <widget class="QGroupBox" name="buttonShoulderButtonsButtonLGroup">
1269 <property name="title">
1270 <string>L</string>
1271 </property>
1272 <property name="alignment">
1273 <set>Qt::AlignCenter</set>
1274 </property>
1275 <layout class="QVBoxLayout" name="buttonShoulderButtonsLVerticalLayout">
1276 <property name="spacing">
1277 <number>3</number>
1278 </property>
1279 <property name="leftMargin">
1280 <number>3</number>
1281 </property>
1282 <property name="topMargin">
1283 <number>3</number>
1284 </property>
1285 <property name="rightMargin">
1286 <number>3</number>
1287 </property>
1288 <property name="bottomMargin">
1289 <number>3</number>
1290 </property>
1291 <item>
1292 <widget class="QPushButton" name="buttonL">
1293 <property name="minimumSize">
1294 <size>
1295 <width>57</width>
1296 <height>0</height>
1297 </size>
1298 </property>
1299 <property name="maximumSize">
1300 <size>
1301 <width>55</width>
1302 <height>16777215</height>
1303 </size>
1304 </property>
1305 <property name="styleSheet">
1306 <string notr="true">min-width: 55px;</string>
1307 </property>
1308 <property name="text">
1309 <string>L</string>
1310 </property>
1311 </widget>
1312 </item>
1313 </layout>
1314 </widget>
1315 </item>
1316 <item>
1317 <widget class="QGroupBox" name="buttonShoulderButtonsButtonZLGroup">
1318 <property name="title">
1319 <string>ZL</string>
1320 </property>
1321 <property name="alignment">
1322 <set>Qt::AlignCenter</set>
1323 </property>
1324 <layout class="QVBoxLayout" name="buttonShoulderButtonsZLVerticalLayout">
1325 <property name="spacing">
1326 <number>3</number>
1327 </property>
1328 <property name="leftMargin">
1329 <number>3</number>
1330 </property>
1331 <property name="topMargin">
1332 <number>3</number>
1333 </property>
1334 <property name="rightMargin">
1335 <number>3</number>
1336 </property>
1337 <property name="bottomMargin">
1338 <number>3</number>
1339 </property>
1340 <item>
1341 <widget class="QPushButton" name="buttonZL">
1342 <property name="minimumSize">
1343 <size>
1344 <width>57</width>
1345 <height>0</height>
1346 </size>
1347 </property>
1348 <property name="maximumSize">
1349 <size>
1350 <width>55</width>
1351 <height>16777215</height>
1352 </size>
1353 </property>
1354 <property name="styleSheet">
1355 <string notr="true">min-width: 55px;</string>
1356 </property>
1357 <property name="text">
1358 <string>ZL</string>
1359 </property>
1360 </widget>
1361 </item>
1362 </layout>
1363 </widget>
1364 </item>
1365 </layout>
1366 </widget>
1367 </item>
1368 <item>
1369 <widget class="QWidget" name="horizontalSpacerShoulderButtonsWidget" native="true">
1370 <layout class="QHBoxLayout" name="horizontalSpacerShoulderButtonsWidgetLayout">
1371 <property name="spacing">
1372 <number>0</number>
1373 </property>
1374 <property name="leftMargin">
1375 <number>0</number>
1376 </property>
1377 <property name="topMargin">
1378 <number>0</number>
1379 </property>
1380 <property name="rightMargin">
1381 <number>0</number>
1382 </property>
1383 <property name="bottomMargin">
1384 <number>0</number>
1385 </property>
1386 <item>
1387 <spacer name="horizontalSpacerShoulderButtons1">
1388 <property name="orientation">
1389 <enum>Qt::Horizontal</enum>
1390 </property>
1391 <property name="sizeHint" stdset="0">
1392 <size>
1393 <width>0</width>
1394 <height>20</height>
1395 </size>
1396 </property>
1397 </spacer>
1398 </item>
1399 </layout>
1400 </widget>
1401 </item>
1402 <item>
1403 <widget class="QWidget" name="buttonMiscButtonsMinusScreenshot" native="true">
1404 <layout class="QVBoxLayout" name="buttonMiscButtonsMinusScreenshotVerticalLayout">
1405 <property name="spacing">
1406 <number>0</number>
1407 </property>
1408 <property name="leftMargin">
1409 <number>0</number>
1410 </property>
1411 <property name="topMargin">
1412 <number>0</number>
1413 </property>
1414 <property name="rightMargin">
1415 <number>0</number>
1416 </property>
1417 <property name="bottomMargin">
1418 <number>0</number>
1419 </property>
1420 <item alignment="Qt::AlignHCenter">
1421 <widget class="QGroupBox" name="buttonMiscButtonsMinusGroup">
1422 <property name="title">
1423 <string>Minus</string>
1424 </property>
1425 <property name="alignment">
1426 <set>Qt::AlignCenter</set>
1427 </property>
1428 <layout class="QVBoxLayout" name="buttonMiscMinusVerticalLayout">
1429 <property name="spacing">
1430 <number>3</number>
1431 </property>
1432 <property name="leftMargin">
1433 <number>3</number>
1434 </property>
1435 <property name="topMargin">
1436 <number>3</number>
1437 </property>
1438 <property name="rightMargin">
1439 <number>3</number>
1440 </property>
1441 <property name="bottomMargin">
1442 <number>3</number>
1443 </property>
1444 <item>
1445 <widget class="QPushButton" name="buttonMinus">
1446 <property name="minimumSize">
1447 <size>
1448 <width>57</width>
1449 <height>0</height>
1450 </size>
1451 </property>
1452 <property name="maximumSize">
1453 <size>
1454 <width>55</width>
1455 <height>16777215</height>
1456 </size>
1457 </property>
1458 <property name="styleSheet">
1459 <string notr="true">min-width: 55px;</string>
1460 </property>
1461 <property name="text">
1462 <string>Minus</string>
1463 </property>
1464 </widget>
1465 </item>
1466 </layout>
1467 </widget>
1468 </item>
1469 <item alignment="Qt::AlignHCenter">
1470 <widget class="QGroupBox" name="buttonMiscButtonsScreenshotGroup">
1471 <property name="title">
1472 <string>Capture</string>
1473 </property>
1474 <property name="alignment">
1475 <set>Qt::AlignCenter</set>
1476 </property>
1477 <layout class="QVBoxLayout" name="buttonMiscScrCapVerticalLayout">
1478 <property name="spacing">
1479 <number>3</number>
1480 </property>
1481 <property name="leftMargin">
1482 <number>3</number>
1483 </property>
1484 <property name="topMargin">
1485 <number>3</number>
1486 </property>
1487 <property name="rightMargin">
1488 <number>3</number>
1489 </property>
1490 <property name="bottomMargin">
1491 <number>3</number>
1492 </property>
1493 <item>
1494 <widget class="QPushButton" name="buttonScreenshot">
1495 <property name="minimumSize">
1496 <size>
1497 <width>57</width>
1498 <height>0</height>
1499 </size>
1500 </property>
1501 <property name="maximumSize">
1502 <size>
1503 <width>55</width>
1504 <height>16777215</height>
1505 </size>
1506 </property>
1507 <property name="styleSheet">
1508 <string notr="true">min-width: 55px;</string>
1509 </property>
1510 <property name="text">
1511 <string>Capture</string>
1512 </property>
1513 </widget>
1514 </item>
1515 </layout>
1516 </widget>
1517 </item>
1518 </layout>
1519 </widget>
1520 </item>
1521 <item>
1522 <widget class="QWidget" name="buttonMiscButtonsPlusHome" native="true">
1523 <layout class="QVBoxLayout" name="buttonMiscButtonsPlusHomeVerticalLayout">
1524 <property name="spacing">
1525 <number>0</number>
1526 </property>
1527 <property name="leftMargin">
1528 <number>0</number>
1529 </property>
1530 <property name="topMargin">
1531 <number>0</number>
1532 </property>
1533 <property name="rightMargin">
1534 <number>0</number>
1535 </property>
1536 <property name="bottomMargin">
1537 <number>0</number>
1538 </property>
1539 <item alignment="Qt::AlignHCenter">
1540 <widget class="QGroupBox" name="buttonMiscButtonsPlusGroup">
1541 <property name="title">
1542 <string>Plus</string>
1543 </property>
1544 <property name="alignment">
1545 <set>Qt::AlignCenter</set>
1546 </property>
1547 <layout class="QVBoxLayout" name="buttonMiscPlusVerticalLayout">
1548 <property name="spacing">
1549 <number>3</number>
1550 </property>
1551 <property name="leftMargin">
1552 <number>3</number>
1553 </property>
1554 <property name="topMargin">
1555 <number>3</number>
1556 </property>
1557 <property name="rightMargin">
1558 <number>3</number>
1559 </property>
1560 <property name="bottomMargin">
1561 <number>3</number>
1562 </property>
1563 <item>
1564 <widget class="QPushButton" name="buttonPlus">
1565 <property name="minimumSize">
1566 <size>
1567 <width>57</width>
1568 <height>0</height>
1569 </size>
1570 </property>
1571 <property name="maximumSize">
1572 <size>
1573 <width>55</width>
1574 <height>16777215</height>
1575 </size>
1576 </property>
1577 <property name="styleSheet">
1578 <string notr="true">min-width: 55px;</string>
1579 </property>
1580 <property name="text">
1581 <string>Plus</string>
1582 </property>
1583 </widget>
1584 </item>
1585 </layout>
1586 </widget>
1587 </item>
1588 <item alignment="Qt::AlignHCenter">
1589 <widget class="QGroupBox" name="buttonMiscButtonsHomeGroup">
1590 <property name="title">
1591 <string>Home</string>
1592 </property>
1593 <property name="alignment">
1594 <set>Qt::AlignCenter</set>
1595 </property>
1596 <layout class="QVBoxLayout" name="buttonMiscHomeVerticalLayout">
1597 <property name="spacing">
1598 <number>3</number>
1599 </property>
1600 <property name="leftMargin">
1601 <number>3</number>
1602 </property>
1603 <property name="topMargin">
1604 <number>3</number>
1605 </property>
1606 <property name="rightMargin">
1607 <number>3</number>
1608 </property>
1609 <property name="bottomMargin">
1610 <number>3</number>
1611 </property>
1612 <item>
1613 <widget class="QPushButton" name="buttonHome">
1614 <property name="minimumSize">
1615 <size>
1616 <width>57</width>
1617 <height>0</height>
1618 </size>
1619 </property>
1620 <property name="maximumSize">
1621 <size>
1622 <width>55</width>
1623 <height>16777215</height>
1624 </size>
1625 </property>
1626 <property name="styleSheet">
1627 <string notr="true">min-width: 55px;</string>
1628 </property>
1629 <property name="text">
1630 <string>Home</string>
1631 </property>
1632 </widget>
1633 </item>
1634 </layout>
1635 </widget>
1636 </item>
1637 </layout>
1638 </widget>
1639 </item>
1640 <item>
1641 <widget class="QWidget" name="horizontalSpacerShoulderButtonsWidget3" native="true">
1642 <layout class="QHBoxLayout" name="horizontalSpacerShoulderButtonsWidget3Layout">
1643 <property name="spacing">
1644 <number>0</number>
1645 </property>
1646 <property name="leftMargin">
1647 <number>0</number>
1648 </property>
1649 <property name="topMargin">
1650 <number>0</number>
1651 </property>
1652 <property name="rightMargin">
1653 <number>0</number>
1654 </property>
1655 <property name="bottomMargin">
1656 <number>0</number>
1657 </property>
1658 <item>
1659 <spacer name="horizontalSpacerShoulderButtons2">
1660 <property name="orientation">
1661 <enum>Qt::Horizontal</enum>
1662 </property>
1663 <property name="sizeHint" stdset="0">
1664 <size>
1665 <width>0</width>
1666 <height>20</height>
1667 </size>
1668 </property>
1669 </spacer>
1670 </item>
1671 </layout>
1672 </widget>
1673 </item>
1674 <item>
1675 <widget class="QWidget" name="buttonShoulderButtonsRight" native="true">
1676 <layout class="QVBoxLayout" name="buttonShoulderButtonsRightVerticalLayout">
1677 <property name="spacing">
1678 <number>0</number>
1679 </property>
1680 <property name="leftMargin">
1681 <number>0</number>
1682 </property>
1683 <property name="topMargin">
1684 <number>0</number>
1685 </property>
1686 <property name="rightMargin">
1687 <number>0</number>
1688 </property>
1689 <property name="bottomMargin">
1690 <number>0</number>
1691 </property>
1692 <item>
1693 <widget class="QGroupBox" name="buttonShoulderButtonsRGroup">
1694 <property name="title">
1695 <string>R</string>
1696 </property>
1697 <property name="alignment">
1698 <set>Qt::AlignCenter</set>
1699 </property>
1700 <layout class="QVBoxLayout" name="buttonShoulderButtonsRVerticalLayout">
1701 <property name="spacing">
1702 <number>3</number>
1703 </property>
1704 <property name="leftMargin">
1705 <number>3</number>
1706 </property>
1707 <property name="topMargin">
1708 <number>3</number>
1709 </property>
1710 <property name="rightMargin">
1711 <number>3</number>
1712 </property>
1713 <property name="bottomMargin">
1714 <number>3</number>
1715 </property>
1716 <item>
1717 <widget class="QPushButton" name="buttonR">
1718 <property name="minimumSize">
1719 <size>
1720 <width>57</width>
1721 <height>0</height>
1722 </size>
1723 </property>
1724 <property name="maximumSize">
1725 <size>
1726 <width>55</width>
1727 <height>16777215</height>
1728 </size>
1729 </property>
1730 <property name="styleSheet">
1731 <string notr="true">min-width: 55px;</string>
1732 </property>
1733 <property name="text">
1734 <string>R</string>
1735 </property>
1736 </widget>
1737 </item>
1738 </layout>
1739 </widget>
1740 </item>
1741 <item>
1742 <widget class="QGroupBox" name="buttonShoulderButtonsZRGroup">
1743 <property name="title">
1744 <string>ZR</string>
1745 </property>
1746 <property name="alignment">
1747 <set>Qt::AlignCenter</set>
1748 </property>
1749 <layout class="QVBoxLayout" name="buttonShoulderButtonsZRVerticalLayout">
1750 <property name="spacing">
1751 <number>3</number>
1752 </property>
1753 <property name="leftMargin">
1754 <number>3</number>
1755 </property>
1756 <property name="topMargin">
1757 <number>3</number>
1758 </property>
1759 <property name="rightMargin">
1760 <number>3</number>
1761 </property>
1762 <property name="bottomMargin">
1763 <number>3</number>
1764 </property>
1765 <item>
1766 <widget class="QPushButton" name="buttonZR">
1767 <property name="minimumSize">
1768 <size>
1769 <width>57</width>
1770 <height>0</height>
1771 </size>
1772 </property>
1773 <property name="maximumSize">
1774 <size>
1775 <width>55</width>
1776 <height>16777215</height>
1777 </size>
1778 </property>
1779 <property name="styleSheet">
1780 <string notr="true">min-width: 55px;</string>
1781 </property>
1782 <property name="text">
1783 <string>ZR</string>
1784 </property>
1785 </widget>
1786 </item>
1787 </layout>
1788 </widget>
1789 </item>
1790 </layout>
1791 </widget>
1792 </item>
1793 <item>
1794 <widget class="QWidget" name="horizontalSpacerShoulderButtonsWidget2" native="true">
1795 <layout class="QHBoxLayout" name="horizontalSpacerShoulderButtonsWidget2Layout">
1796 <property name="spacing">
1797 <number>0</number>
1798 </property>
1799 <property name="leftMargin">
1800 <number>0</number>
1801 </property>
1802 <property name="topMargin">
1803 <number>0</number>
1804 </property>
1805 <property name="rightMargin">
1806 <number>0</number>
1807 </property>
1808 <property name="bottomMargin">
1809 <number>0</number>
1810 </property>
1811 <item>
1812 <spacer name="horizontalSpacerShoulderButtons3">
1813 <property name="orientation">
1814 <enum>Qt::Horizontal</enum>
1815 </property>
1816 <property name="sizeHint" stdset="0">
1817 <size>
1818 <width>0</width>
1819 <height>20</height>
1820 </size>
1821 </property>
1822 </spacer>
1823 </item>
1824 </layout>
1825 </widget>
1826 </item>
1827 <item>
1828 <widget class="QWidget" name="buttonShoulderButtonsSLSR" native="true">
1829 <layout class="QVBoxLayout" name="buttonShoulderButtonsSLSRVerticalLayout">
1830 <property name="spacing">
1831 <number>0</number>
1832 </property>
1833 <property name="leftMargin">
1834 <number>0</number>
1835 </property>
1836 <property name="topMargin">
1837 <number>0</number>
1838 </property>
1839 <property name="rightMargin">
1840 <number>0</number>
1841 </property>
1842 <property name="bottomMargin">
1843 <number>0</number>
1844 </property>
1845 <item alignment="Qt::AlignHCenter">
1846 <widget class="QGroupBox" name="buttonShoulderButtonsSLGroup">
1847 <property name="title">
1848 <string>SL</string>
1849 </property>
1850 <property name="alignment">
1851 <set>Qt::AlignCenter</set>
1852 </property>
1853 <layout class="QVBoxLayout" name="buttonShoulderButtonsSLVerticalLayout">
1854 <property name="spacing">
1855 <number>3</number>
1856 </property>
1857 <property name="leftMargin">
1858 <number>3</number>
1859 </property>
1860 <property name="topMargin">
1861 <number>3</number>
1862 </property>
1863 <property name="rightMargin">
1864 <number>3</number>
1865 </property>
1866 <property name="bottomMargin">
1867 <number>3</number>
1868 </property>
1869 <item>
1870 <widget class="QPushButton" name="buttonSL">
1871 <property name="minimumSize">
1872 <size>
1873 <width>57</width>
1874 <height>0</height>
1875 </size>
1876 </property>
1877 <property name="maximumSize">
1878 <size>
1879 <width>55</width>
1880 <height>16777215</height>
1881 </size>
1882 </property>
1883 <property name="styleSheet">
1884 <string notr="true">min-width: 55px;</string>
1885 </property>
1886 <property name="text">
1887 <string>SL</string>
1888 </property>
1889 </widget>
1890 </item>
1891 </layout>
1892 </widget>
1893 </item>
1894 <item alignment="Qt::AlignHCenter">
1895 <widget class="QGroupBox" name="buttonShoulderButtonsSRGroup">
1896 <property name="title">
1897 <string>SR</string>
1898 </property>
1899 <property name="alignment">
1900 <set>Qt::AlignCenter</set>
1901 </property>
1902 <layout class="QVBoxLayout" name="buttonShoulderButtonsSRVerticalLayout">
1903 <property name="spacing">
1904 <number>3</number>
1905 </property>
1906 <property name="leftMargin">
1907 <number>3</number>
1908 </property>
1909 <property name="topMargin">
1910 <number>3</number>
1911 </property>
1912 <property name="rightMargin">
1913 <number>3</number>
1914 </property>
1915 <property name="bottomMargin">
1916 <number>3</number>
1917 </property>
1918 <item>
1919 <widget class="QPushButton" name="buttonSR">
1920 <property name="minimumSize">
1921 <size>
1922 <width>57</width>
1923 <height>0</height>
1924 </size>
1925 </property>
1926 <property name="maximumSize">
1927 <size>
1928 <width>55</width>
1929 <height>16777215</height>
1930 </size>
1931 </property>
1932 <property name="styleSheet">
1933 <string notr="true">min-width: 55px;</string>
1934 </property>
1935 <property name="text">
1936 <string>SR</string>
1937 </property>
1938 </widget>
1939 </item>
1940 </layout>
1941 </widget>
1942 </item>
1943 </layout>
1944 </widget>
1945 </item>
1946 </layout>
1947 </item>
1948 <item>
1949 <widget class="QFrame" name="controllerFrame">
1950 <property name="sizePolicy">
1951 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1952 <horstretch>0</horstretch>
1953 <verstretch>0</verstretch>
1954 </sizepolicy>
1955 </property>
1956 <property name="font">
1957 <font>
1958 <weight>75</weight>
1959 <bold>true</bold>
1960 </font>
1961 </property>
1962 <property name="styleSheet">
1963 <string notr="true">image: url(:/controller/pro);</string>
1964 </property>
1965 <layout class="QVBoxLayout" name="verticalLayout_4">
1966 <property name="leftMargin">
1967 <number>0</number>
772 </property> 1968 </property>
773 </widget> 1969 <property name="topMargin">
774 </item> 1970 <number>0</number>
775 </layout>
776 </item>
777 <item>
778 <widget class="QPushButton" name="buttonLStick">
779 <property name="text">
780 <string/>
781 </property>
782 </widget>
783 </item>
784 </layout>
785 </item>
786 <item row="5" column="1" colspan="2">
787 <layout class="QVBoxLayout" name="sliderLStickDeadzoneAndModifierVerticalLayout">
788 <property name="sizeConstraint">
789 <enum>QLayout::SetDefaultConstraint</enum>
790 </property>
791 <item>
792 <layout class="QHBoxLayout" name="sliderLStickDeadzoneAndModifierHorizontalLayout">
793 <item>
794 <widget class="QLabel" name="labelLStickDeadzoneAndModifier">
795 <property name="text">
796 <string>Deadzone: 0</string>
797 </property> 1971 </property>
798 <property name="alignment"> 1972 <property name="rightMargin">
799 <enum>Qt::AlignHCenter</enum> 1973 <number>0</number>
800 </property> 1974 </property>
801 </widget> 1975 <property name="bottomMargin">
802 </item> 1976 <number>0</number>
803 </layout>
804 </item>
805 <item>
806 <widget class="QSlider" name="sliderLStickDeadzoneAndModifier">
807 <property name="orientation">
808 <enum>Qt::Horizontal</enum>
809 </property>
810 </widget>
811 </item>
812 </layout>
813 </item>
814 <item row="6" column="1">
815 <spacer name="LStick_verticalSpacer">
816 <property name="orientation">
817 <enum>Qt::Vertical</enum>
818 </property>
819 <property name="sizeHint" stdset="0">
820 <size>
821 <width>0</width>
822 <height>0</height>
823 </size>
824 </property>
825 </spacer>
826 </item>
827 </layout>
828 </widget>
829 </item>
830 <item row="3" column="0">
831 <widget class="QGroupBox" name="shoulderButtons">
832 <property name="title">
833 <string>Shoulder Buttons</string>
834 </property>
835 <property name="flat">
836 <bool>false</bool>
837 </property>
838 <property name="checkable">
839 <bool>false</bool>
840 </property>
841 <layout class="QGridLayout" name="gridLayout_3">
842 <item row="0" column="0">
843 <layout class="QVBoxLayout" name="buttonShoulderButtonsLVerticalLayout">
844 <item>
845 <layout class="QHBoxLayout" name="buttonShoulderButtonsLHorizontalLayout">
846 <item>
847 <widget class="QLabel" name="labelL">
848 <property name="text">
849 <string>L:</string>
850 </property> 1977 </property>
851 </widget> 1978 </layout>
852 </item> 1979 </widget>
853 </layout> 1980 </item>
854 </item> 1981 <item>
855 <item> 1982 <layout class="QHBoxLayout" name="miscButtons">
856 <widget class="QPushButton" name="buttonL"> 1983 <property name="spacing">
857 <property name="text"> 1984 <number>3</number>
858 <string/> 1985 </property>
859 </property> 1986 <item>
860 </widget> 1987 <spacer name="horizontalSpacerMiscButtons1">
861 </item> 1988 <property name="orientation">
862 </layout> 1989 <enum>Qt::Horizontal</enum>
1990 </property>
1991 <property name="sizeHint" stdset="0">
1992 <size>
1993 <width>40</width>
1994 <height>0</height>
1995 </size>
1996 </property>
1997 </spacer>
1998 </item>
1999 <item>
2000 <spacer name="horizontalSpacerMiscButtons4">
2001 <property name="orientation">
2002 <enum>Qt::Horizontal</enum>
2003 </property>
2004 <property name="sizeHint" stdset="0">
2005 <size>
2006 <width>40</width>
2007 <height>0</height>
2008 </size>
2009 </property>
2010 </spacer>
2011 </item>
2012 </layout>
2013 </item>
2014 </layout>
2015 </widget>
863 </item> 2016 </item>
864 <item row="0" column="1"> 2017 <item>
865 <layout class="QVBoxLayout" name="buttonShoulderButtonsRVerticalLayout"> 2018 <widget class="QWidget" name="bottomRight" native="true">
866 <item> 2019 <layout class="QVBoxLayout" name="bottomRightLayout">
867 <layout class="QHBoxLayout" name="buttonShoulderButtonsRHorizontalLayout"> 2020 <property name="spacing">
868 <item> 2021 <number>0</number>
869 <widget class="QLabel" name="labelR"> 2022 </property>
870 <property name="text"> 2023 <property name="leftMargin">
871 <string>R:</string> 2024 <number>0</number>
2025 </property>
2026 <property name="topMargin">
2027 <number>0</number>
2028 </property>
2029 <property name="rightMargin">
2030 <number>0</number>
2031 </property>
2032 <property name="bottomMargin">
2033 <number>0</number>
2034 </property>
2035 <item>
2036 <widget class="QGroupBox" name="faceButtons">
2037 <property name="sizePolicy">
2038 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
2039 <horstretch>0</horstretch>
2040 <verstretch>0</verstretch>
2041 </sizepolicy>
2042 </property>
2043 <property name="title">
2044 <string>Face Buttons</string>
2045 </property>
2046 <property name="flat">
2047 <bool>false</bool>
2048 </property>
2049 <property name="checkable">
2050 <bool>false</bool>
2051 </property>
2052 <layout class="QVBoxLayout" name="verticalLayout">
2053 <property name="spacing">
2054 <number>0</number>
872 </property> 2055 </property>
873 </widget> 2056 <property name="leftMargin">
874 </item> 2057 <number>3</number>
875 </layout>
876 </item>
877 <item>
878 <widget class="QPushButton" name="buttonR">
879 <property name="text">
880 <string/>
881 </property>
882 </widget>
883 </item>
884 </layout>
885 </item>
886 <item row="1" column="0">
887 <layout class="QVBoxLayout" name="buttonShoulderButtonsZLVerticalLayout">
888 <item>
889 <layout class="QHBoxLayout" name="buttonShoulderButtonsZLHorizontalLayout">
890 <item>
891 <widget class="QLabel" name="labelZL">
892 <property name="text">
893 <string>ZL:</string>
894 </property> 2058 </property>
895 </widget> 2059 <property name="topMargin">
896 </item> 2060 <number>0</number>
897 </layout>
898 </item>
899 <item>
900 <widget class="QPushButton" name="buttonZL">
901 <property name="text">
902 <string/>
903 </property>
904 </widget>
905 </item>
906 </layout>
907 </item>
908 <item row="1" column="1">
909 <layout class="QVBoxLayout" name="buttonShoulderButtonsZRVerticalLayout">
910 <item>
911 <layout class="QHBoxLayout" name="buttonShoulderButtonsZRHorizontalLayout">
912 <item>
913 <widget class="QLabel" name="labelZR">
914 <property name="text">
915 <string>ZR:</string>
916 </property> 2061 </property>
917 </widget> 2062 <property name="rightMargin">
918 </item> 2063 <number>3</number>
919 </layout>
920 </item>
921 <item>
922 <widget class="QPushButton" name="buttonZR">
923 <property name="text">
924 <string/>
925 </property>
926 </widget>
927 </item>
928 </layout>
929 </item>
930 <item row="0" column="2">
931 <layout class="QVBoxLayout" name="buttonShoulderButtonsSLVerticalLayout">
932 <item>
933 <layout class="QHBoxLayout" name="buttonShoulderButtonsSLHorizontalLayout">
934 <item>
935 <widget class="QLabel" name="labelSL">
936 <property name="text">
937 <string>SL:</string>
938 </property> 2064 </property>
939 </widget> 2065 <property name="bottomMargin">
940 </item> 2066 <number>3</number>
941 </layout>
942 </item>
943 <item>
944 <widget class="QPushButton" name="buttonSL">
945 <property name="text">
946 <string/>
947 </property>
948 </widget>
949 </item>
950 </layout>
951 </item>
952 <item row="1" column="2">
953 <layout class="QVBoxLayout" name="buttonShoulderButtonsSRVerticalLayout">
954 <item>
955 <layout class="QHBoxLayout" name="buttonShoulderButtonsSRHorizontalLayout">
956 <item>
957 <widget class="QLabel" name="labelSR">
958 <property name="text">
959 <string>SR:</string>
960 </property> 2067 </property>
961 </widget> 2068 <item>
962 </item> 2069 <widget class="QWidget" name="buttonFaceButtonsBWidget" native="true">
963 </layout> 2070 <layout class="QHBoxLayout" name="horizontalLayout_6">
964 </item> 2071 <property name="spacing">
965 <item> 2072 <number>0</number>
966 <widget class="QPushButton" name="buttonSR"> 2073 </property>
967 <property name="text"> 2074 <property name="leftMargin">
968 <string/> 2075 <number>0</number>
969 </property> 2076 </property>
970 </widget> 2077 <property name="topMargin">
971 </item> 2078 <number>0</number>
972 </layout> 2079 </property>
973 </item> 2080 <property name="rightMargin">
974 </layout> 2081 <number>0</number>
975 </widget> 2082 </property>
976 </item> 2083 <property name="bottomMargin">
977 <item row="3" column="1"> 2084 <number>0</number>
978 <widget class="QGroupBox" name="misc"> 2085 </property>
979 <property name="title"> 2086 <item>
980 <string>Misc.</string> 2087 <spacer name="horizontalSpacerBLeft">
981 </property> 2088 <property name="orientation">
982 <property name="flat"> 2089 <enum>Qt::Horizontal</enum>
983 <bool>false</bool> 2090 </property>
984 </property> 2091 <property name="sizeHint" stdset="0">
985 <property name="checkable"> 2092 <size>
986 <bool>false</bool> 2093 <width>20</width>
987 </property> 2094 <height>20</height>
988 <layout class="QGridLayout" name="gridLayout_6"> 2095 </size>
989 <item row="1" column="0"> 2096 </property>
990 <layout class="QVBoxLayout" name="buttonMiscMinusVerticalLayout"> 2097 </spacer>
991 <item> 2098 </item>
992 <layout class="QHBoxLayout" name="buttonMiscMinusHorizontalLayout"> 2099 <item alignment="Qt::AlignHCenter">
993 <item> 2100 <widget class="QGroupBox" name="buttonFaceButtonsXGroup">
994 <widget class="QLabel" name="labelMinus"> 2101 <property name="title">
995 <property name="text"> 2102 <string>X</string>
996 <string>Minus:</string> 2103 </property>
2104 <property name="alignment">
2105 <set>Qt::AlignCenter</set>
2106 </property>
2107 <layout class="QVBoxLayout" name="buttonFaceButtonsXVerticalLayout">
2108 <property name="spacing">
2109 <number>3</number>
2110 </property>
2111 <property name="leftMargin">
2112 <number>3</number>
2113 </property>
2114 <property name="topMargin">
2115 <number>3</number>
2116 </property>
2117 <property name="rightMargin">
2118 <number>3</number>
2119 </property>
2120 <property name="bottomMargin">
2121 <number>3</number>
2122 </property>
2123 <item>
2124 <widget class="QPushButton" name="buttonX">
2125 <property name="minimumSize">
2126 <size>
2127 <width>57</width>
2128 <height>0</height>
2129 </size>
2130 </property>
2131 <property name="maximumSize">
2132 <size>
2133 <width>55</width>
2134 <height>16777215</height>
2135 </size>
2136 </property>
2137 <property name="styleSheet">
2138 <string notr="true">min-width: 55px;</string>
2139 </property>
2140 <property name="text">
2141 <string>X</string>
2142 </property>
2143 </widget>
2144 </item>
2145 </layout>
2146 </widget>
2147 </item>
2148 <item>
2149 <spacer name="horizontalSpacerBRight">
2150 <property name="orientation">
2151 <enum>Qt::Horizontal</enum>
2152 </property>
2153 <property name="sizeHint" stdset="0">
2154 <size>
2155 <width>20</width>
2156 <height>20</height>
2157 </size>
2158 </property>
2159 </spacer>
2160 </item>
2161 </layout>
2162 </widget>
2163 </item>
2164 <item>
2165 <layout class="QHBoxLayout" name="buttonFaceButtonsYAHorizontalLayout">
2166 <property name="spacing">
2167 <number>3</number>
2168 </property>
2169 <item alignment="Qt::AlignHCenter">
2170 <widget class="QGroupBox" name="buttonFaceButtonsYGroup">
2171 <property name="title">
2172 <string>Y</string>
2173 </property>
2174 <property name="alignment">
2175 <set>Qt::AlignCenter</set>
2176 </property>
2177 <layout class="QVBoxLayout" name="buttonFaceButtonsYVerticalLayout">
2178 <property name="spacing">
2179 <number>3</number>
2180 </property>
2181 <property name="leftMargin">
2182 <number>3</number>
2183 </property>
2184 <property name="topMargin">
2185 <number>3</number>
2186 </property>
2187 <property name="rightMargin">
2188 <number>3</number>
2189 </property>
2190 <property name="bottomMargin">
2191 <number>3</number>
2192 </property>
2193 <item>
2194 <widget class="QPushButton" name="buttonY">
2195 <property name="minimumSize">
2196 <size>
2197 <width>57</width>
2198 <height>0</height>
2199 </size>
2200 </property>
2201 <property name="maximumSize">
2202 <size>
2203 <width>55</width>
2204 <height>16777215</height>
2205 </size>
2206 </property>
2207 <property name="styleSheet">
2208 <string notr="true">min-width: 55px;</string>
2209 </property>
2210 <property name="text">
2211 <string>Y</string>
2212 </property>
2213 </widget>
2214 </item>
2215 </layout>
2216 </widget>
2217 </item>
2218 <item alignment="Qt::AlignHCenter">
2219 <widget class="QGroupBox" name="buttonFaceButtonsAGroup">
2220 <property name="title">
2221 <string>A</string>
2222 </property>
2223 <property name="alignment">
2224 <set>Qt::AlignCenter</set>
2225 </property>
2226 <layout class="QVBoxLayout" name="buttonFaceButtonsAVerticalLayout">
2227 <property name="spacing">
2228 <number>3</number>
2229 </property>
2230 <property name="leftMargin">
2231 <number>3</number>
2232 </property>
2233 <property name="topMargin">
2234 <number>3</number>
2235 </property>
2236 <property name="rightMargin">
2237 <number>3</number>
2238 </property>
2239 <property name="bottomMargin">
2240 <number>3</number>
2241 </property>
2242 <item>
2243 <widget class="QPushButton" name="buttonA">
2244 <property name="minimumSize">
2245 <size>
2246 <width>57</width>
2247 <height>0</height>
2248 </size>
2249 </property>
2250 <property name="maximumSize">
2251 <size>
2252 <width>55</width>
2253 <height>16777215</height>
2254 </size>
2255 </property>
2256 <property name="styleSheet">
2257 <string notr="true">min-width: 55px;</string>
2258 </property>
2259 <property name="text">
2260 <string>A</string>
2261 </property>
2262 </widget>
2263 </item>
2264 </layout>
2265 </widget>
2266 </item>
2267 </layout>
2268 </item>
2269 <item>
2270 <widget class="QWidget" name="buttonFaceButtonsXWidget" native="true">
2271 <layout class="QHBoxLayout" name="horizontalLayout_10">
2272 <property name="spacing">
2273 <number>0</number>
2274 </property>
2275 <property name="leftMargin">
2276 <number>0</number>
2277 </property>
2278 <property name="topMargin">
2279 <number>0</number>
2280 </property>
2281 <property name="rightMargin">
2282 <number>0</number>
2283 </property>
2284 <property name="bottomMargin">
2285 <number>0</number>
2286 </property>
2287 <item>
2288 <spacer name="horizontalSpacerXLeft">
2289 <property name="orientation">
2290 <enum>Qt::Horizontal</enum>
2291 </property>
2292 <property name="sizeHint" stdset="0">
2293 <size>
2294 <width>20</width>
2295 <height>20</height>
2296 </size>
2297 </property>
2298 </spacer>
2299 </item>
2300 <item alignment="Qt::AlignHCenter">
2301 <widget class="QGroupBox" name="buttonFaceButtonsBWidget_2">
2302 <property name="title">
2303 <string>B</string>
2304 </property>
2305 <property name="alignment">
2306 <set>Qt::AlignCenter</set>
2307 </property>
2308 <layout class="QVBoxLayout" name="buttonFaceButtonsBVerticalLayout">
2309 <property name="spacing">
2310 <number>3</number>
2311 </property>
2312 <property name="leftMargin">
2313 <number>3</number>
2314 </property>
2315 <property name="topMargin">
2316 <number>3</number>
2317 </property>
2318 <property name="rightMargin">
2319 <number>3</number>
2320 </property>
2321 <property name="bottomMargin">
2322 <number>3</number>
2323 </property>
2324 <item>
2325 <widget class="QPushButton" name="buttonB">
2326 <property name="minimumSize">
2327 <size>
2328 <width>57</width>
2329 <height>0</height>
2330 </size>
2331 </property>
2332 <property name="maximumSize">
2333 <size>
2334 <width>55</width>
2335 <height>16777215</height>
2336 </size>
2337 </property>
2338 <property name="styleSheet">
2339 <string notr="true">min-width: 55px;</string>
2340 </property>
2341 <property name="text">
2342 <string>B</string>
2343 </property>
2344 </widget>
2345 </item>
2346 </layout>
2347 </widget>
2348 </item>
2349 <item>
2350 <spacer name="horizontalSpacerXRight">
2351 <property name="orientation">
2352 <enum>Qt::Horizontal</enum>
2353 </property>
2354 <property name="sizeHint" stdset="0">
2355 <size>
2356 <width>20</width>
2357 <height>20</height>
2358 </size>
2359 </property>
2360 </spacer>
2361 </item>
2362 </layout>
2363 </widget>
2364 </item>
2365 </layout>
2366 </widget>
2367 </item>
2368 <item>
2369 <spacer name="verticalSpacerBottomRight">
2370 <property name="orientation">
2371 <enum>Qt::Vertical</enum>
2372 </property>
2373 <property name="sizeHint" stdset="0">
2374 <size>
2375 <width>20</width>
2376 <height>0</height>
2377 </size>
2378 </property>
2379 </spacer>
2380 </item>
2381 <item>
2382 <widget class="QGroupBox" name="RStick">
2383 <property name="sizePolicy">
2384 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
2385 <horstretch>0</horstretch>
2386 <verstretch>0</verstretch>
2387 </sizepolicy>
2388 </property>
2389 <property name="title">
2390 <string>Right Stick</string>
2391 </property>
2392 <property name="alignment">
2393 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
2394 </property>
2395 <property name="flat">
2396 <bool>false</bool>
2397 </property>
2398 <property name="checkable">
2399 <bool>false</bool>
2400 </property>
2401 <layout class="QVBoxLayout" name="verticalLayout_2">
2402 <property name="spacing">
2403 <number>0</number>
997 </property> 2404 </property>
998 </widget> 2405 <property name="leftMargin">
999 </item> 2406 <number>3</number>
1000 </layout>
1001 </item>
1002 <item>
1003 <widget class="QPushButton" name="buttonMinus">
1004 <property name="text">
1005 <string/>
1006 </property>
1007 </widget>
1008 </item>
1009 </layout>
1010 </item>
1011 <item row="3" column="1">
1012 <spacer name="verticalSpacer_2">
1013 <property name="orientation">
1014 <enum>Qt::Vertical</enum>
1015 </property>
1016 <property name="sizeHint" stdset="0">
1017 <size>
1018 <width>20</width>
1019 <height>40</height>
1020 </size>
1021 </property>
1022 </spacer>
1023 </item>
1024 <item row="0" column="0">
1025 <layout class="QVBoxLayout" name="buttonMiscPlusVerticalLayout">
1026 <item>
1027 <layout class="QHBoxLayout" name="buttonMiscPlusHorizontalLayout">
1028 <item>
1029 <widget class="QLabel" name="labelPlus">
1030 <property name="text">
1031 <string>Plus:</string>
1032 </property> 2407 </property>
1033 </widget> 2408 <property name="topMargin">
1034 </item> 2409 <number>0</number>
1035 </layout>
1036 </item>
1037 <item>
1038 <widget class="QPushButton" name="buttonPlus">
1039 <property name="text">
1040 <string/>
1041 </property>
1042 </widget>
1043 </item>
1044 </layout>
1045 </item>
1046 <item row="0" column="1">
1047 <layout class="QVBoxLayout" name="buttonMiscHomeVerticalLayout">
1048 <item>
1049 <layout class="QHBoxLayout" name="buttonMiscHomeHorizontalLayout">
1050 <item>
1051 <widget class="QLabel" name="labelHome">
1052 <property name="text">
1053 <string>Home:</string>
1054 </property> 2410 </property>
1055 </widget> 2411 <property name="rightMargin">
1056 </item> 2412 <number>3</number>
1057 </layout>
1058 </item>
1059 <item>
1060 <widget class="QPushButton" name="buttonHome">
1061 <property name="text">
1062 <string/>
1063 </property>
1064 </widget>
1065 </item>
1066 </layout>
1067 </item>
1068 <item row="1" column="1">
1069 <layout class="QVBoxLayout" name="buttonMiscScrCapVerticalLayout">
1070 <item>
1071 <layout class="QHBoxLayout" name="buttonMiscScrCapHorizontalLayout">
1072 <item>
1073 <widget class="QLabel" name="labelScreenshot">
1074 <property name="text">
1075 <string>Screen Capture:</string>
1076 </property> 2413 </property>
1077 <property name="wordWrap"> 2414 <property name="bottomMargin">
1078 <bool>false</bool> 2415 <number>0</number>
1079 </property> 2416 </property>
1080 </widget> 2417 <item>
1081 </item> 2418 <widget class="QWidget" name="buttonRStickUpWidget" native="true">
1082 </layout> 2419 <property name="minimumSize">
1083 </item> 2420 <size>
1084 <item> 2421 <width>0</width>
1085 <widget class="QPushButton" name="buttonScreenshot"> 2422 <height>0</height>
1086 <property name="sizePolicy"> 2423 </size>
1087 <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> 2424 </property>
1088 <horstretch>0</horstretch> 2425 <layout class="QHBoxLayout" name="horizontalLayout_9">
1089 <verstretch>0</verstretch> 2426 <property name="spacing">
1090 </sizepolicy> 2427 <number>0</number>
1091 </property> 2428 </property>
1092 <property name="maximumSize"> 2429 <property name="leftMargin">
1093 <size> 2430 <number>0</number>
1094 <width>80</width> 2431 </property>
1095 <height>16777215</height> 2432 <property name="topMargin">
1096 </size> 2433 <number>0</number>
1097 </property> 2434 </property>
1098 <property name="text"> 2435 <property name="rightMargin">
1099 <string/> 2436 <number>0</number>
1100 </property> 2437 </property>
1101 </widget> 2438 <property name="bottomMargin">
1102 </item> 2439 <number>0</number>
1103 </layout> 2440 </property>
2441 <item>
2442 <spacer name="horizontalSpacerRStickUpLeft">
2443 <property name="orientation">
2444 <enum>Qt::Horizontal</enum>
2445 </property>
2446 <property name="sizeHint" stdset="0">
2447 <size>
2448 <width>20</width>
2449 <height>20</height>
2450 </size>
2451 </property>
2452 </spacer>
2453 </item>
2454 <item alignment="Qt::AlignHCenter">
2455 <widget class="QGroupBox" name="buttonRStickUpGroup">
2456 <property name="title">
2457 <string>Up</string>
2458 </property>
2459 <property name="alignment">
2460 <set>Qt::AlignCenter</set>
2461 </property>
2462 <layout class="QVBoxLayout" name="buttonRStickUpVerticalLayout">
2463 <property name="spacing">
2464 <number>3</number>
2465 </property>
2466 <property name="leftMargin">
2467 <number>3</number>
2468 </property>
2469 <property name="topMargin">
2470 <number>3</number>
2471 </property>
2472 <property name="rightMargin">
2473 <number>3</number>
2474 </property>
2475 <property name="bottomMargin">
2476 <number>3</number>
2477 </property>
2478 <item>
2479 <widget class="QPushButton" name="buttonRStickUp">
2480 <property name="minimumSize">
2481 <size>
2482 <width>57</width>
2483 <height>0</height>
2484 </size>
2485 </property>
2486 <property name="maximumSize">
2487 <size>
2488 <width>55</width>
2489 <height>16777215</height>
2490 </size>
2491 </property>
2492 <property name="styleSheet">
2493 <string notr="true">min-width: 55px;</string>
2494 </property>
2495 <property name="text">
2496 <string>Up</string>
2497 </property>
2498 </widget>
2499 </item>
2500 </layout>
2501 </widget>
2502 </item>
2503 <item>
2504 <spacer name="horizontalSpacerRStickUpRight">
2505 <property name="orientation">
2506 <enum>Qt::Horizontal</enum>
2507 </property>
2508 <property name="sizeHint" stdset="0">
2509 <size>
2510 <width>20</width>
2511 <height>20</height>
2512 </size>
2513 </property>
2514 </spacer>
2515 </item>
2516 </layout>
2517 </widget>
2518 </item>
2519 <item>
2520 <layout class="QHBoxLayout" name="buttonRStickLeftRightHorizontalLayout">
2521 <property name="spacing">
2522 <number>3</number>
2523 </property>
2524 <item alignment="Qt::AlignHCenter">
2525 <widget class="QGroupBox" name="buttonRStickLeftGroup">
2526 <property name="title">
2527 <string>Left</string>
2528 </property>
2529 <property name="alignment">
2530 <set>Qt::AlignCenter</set>
2531 </property>
2532 <layout class="QVBoxLayout" name="buttonRStickLeftVerticalLayout">
2533 <property name="spacing">
2534 <number>3</number>
2535 </property>
2536 <property name="leftMargin">
2537 <number>3</number>
2538 </property>
2539 <property name="topMargin">
2540 <number>3</number>
2541 </property>
2542 <property name="rightMargin">
2543 <number>3</number>
2544 </property>
2545 <property name="bottomMargin">
2546 <number>3</number>
2547 </property>
2548 <item>
2549 <widget class="QPushButton" name="buttonRStickLeft">
2550 <property name="minimumSize">
2551 <size>
2552 <width>57</width>
2553 <height>0</height>
2554 </size>
2555 </property>
2556 <property name="maximumSize">
2557 <size>
2558 <width>55</width>
2559 <height>16777215</height>
2560 </size>
2561 </property>
2562 <property name="styleSheet">
2563 <string notr="true">min-width: 55px;</string>
2564 </property>
2565 <property name="text">
2566 <string>Left</string>
2567 </property>
2568 </widget>
2569 </item>
2570 </layout>
2571 </widget>
2572 </item>
2573 <item alignment="Qt::AlignHCenter">
2574 <widget class="QGroupBox" name="buttonRStickRightGroup">
2575 <property name="title">
2576 <string>Right</string>
2577 </property>
2578 <property name="alignment">
2579 <set>Qt::AlignCenter</set>
2580 </property>
2581 <layout class="QVBoxLayout" name="buttonRStickRightVerticalLayout">
2582 <property name="spacing">
2583 <number>3</number>
2584 </property>
2585 <property name="leftMargin">
2586 <number>3</number>
2587 </property>
2588 <property name="topMargin">
2589 <number>3</number>
2590 </property>
2591 <property name="rightMargin">
2592 <number>3</number>
2593 </property>
2594 <property name="bottomMargin">
2595 <number>3</number>
2596 </property>
2597 <item>
2598 <widget class="QPushButton" name="buttonRStickRight">
2599 <property name="minimumSize">
2600 <size>
2601 <width>57</width>
2602 <height>0</height>
2603 </size>
2604 </property>
2605 <property name="maximumSize">
2606 <size>
2607 <width>55</width>
2608 <height>16777215</height>
2609 </size>
2610 </property>
2611 <property name="styleSheet">
2612 <string notr="true">min-width: 55px;</string>
2613 </property>
2614 <property name="text">
2615 <string>Right</string>
2616 </property>
2617 </widget>
2618 </item>
2619 </layout>
2620 </widget>
2621 </item>
2622 </layout>
2623 </item>
2624 <item>
2625 <widget class="QWidget" name="buttonRStickDownWidget" native="true">
2626 <layout class="QHBoxLayout" name="horizontalLayout_11">
2627 <property name="spacing">
2628 <number>0</number>
2629 </property>
2630 <property name="leftMargin">
2631 <number>0</number>
2632 </property>
2633 <property name="topMargin">
2634 <number>0</number>
2635 </property>
2636 <property name="rightMargin">
2637 <number>0</number>
2638 </property>
2639 <property name="bottomMargin">
2640 <number>0</number>
2641 </property>
2642 <item>
2643 <spacer name="horizontalSpacerRStickDownLeft">
2644 <property name="orientation">
2645 <enum>Qt::Horizontal</enum>
2646 </property>
2647 <property name="sizeHint" stdset="0">
2648 <size>
2649 <width>20</width>
2650 <height>20</height>
2651 </size>
2652 </property>
2653 </spacer>
2654 </item>
2655 <item>
2656 <widget class="QGroupBox" name="buttonRStickDownGroup">
2657 <property name="title">
2658 <string>Down</string>
2659 </property>
2660 <property name="alignment">
2661 <set>Qt::AlignCenter</set>
2662 </property>
2663 <layout class="QVBoxLayout" name="buttonRStickDownVerticalLayout">
2664 <property name="spacing">
2665 <number>3</number>
2666 </property>
2667 <property name="leftMargin">
2668 <number>3</number>
2669 </property>
2670 <property name="topMargin">
2671 <number>3</number>
2672 </property>
2673 <property name="rightMargin">
2674 <number>3</number>
2675 </property>
2676 <property name="bottomMargin">
2677 <number>3</number>
2678 </property>
2679 <item>
2680 <widget class="QPushButton" name="buttonRStickDown">
2681 <property name="minimumSize">
2682 <size>
2683 <width>57</width>
2684 <height>0</height>
2685 </size>
2686 </property>
2687 <property name="maximumSize">
2688 <size>
2689 <width>55</width>
2690 <height>16777215</height>
2691 </size>
2692 </property>
2693 <property name="styleSheet">
2694 <string notr="true">min-width: 55px;</string>
2695 </property>
2696 <property name="text">
2697 <string>Down</string>
2698 </property>
2699 </widget>
2700 </item>
2701 </layout>
2702 </widget>
2703 </item>
2704 <item>
2705 <spacer name="horizontalSpacerRStickDownRight">
2706 <property name="orientation">
2707 <enum>Qt::Horizontal</enum>
2708 </property>
2709 <property name="sizeHint" stdset="0">
2710 <size>
2711 <width>20</width>
2712 <height>20</height>
2713 </size>
2714 </property>
2715 </spacer>
2716 </item>
2717 </layout>
2718 </widget>
2719 </item>
2720 <item>
2721 <layout class="QHBoxLayout" name="buttonRStickPressedModifierHorizontalLayout">
2722 <property name="spacing">
2723 <number>3</number>
2724 </property>
2725 <item alignment="Qt::AlignHCenter">
2726 <widget class="QGroupBox" name="groupRStickPressed">
2727 <property name="title">
2728 <string>Pressed</string>
2729 </property>
2730 <property name="alignment">
2731 <set>Qt::AlignCenter</set>
2732 </property>
2733 <layout class="QVBoxLayout" name="buttonRStickPressedVerticalLayout">
2734 <property name="spacing">
2735 <number>3</number>
2736 </property>
2737 <property name="leftMargin">
2738 <number>3</number>
2739 </property>
2740 <property name="topMargin">
2741 <number>3</number>
2742 </property>
2743 <property name="rightMargin">
2744 <number>3</number>
2745 </property>
2746 <property name="bottomMargin">
2747 <number>3</number>
2748 </property>
2749 <item>
2750 <widget class="QPushButton" name="buttonRStick">
2751 <property name="minimumSize">
2752 <size>
2753 <width>57</width>
2754 <height>0</height>
2755 </size>
2756 </property>
2757 <property name="maximumSize">
2758 <size>
2759 <width>55</width>
2760 <height>16777215</height>
2761 </size>
2762 </property>
2763 <property name="styleSheet">
2764 <string notr="true">min-width: 55px;</string>
2765 </property>
2766 <property name="text">
2767 <string>Pressed</string>
2768 </property>
2769 </widget>
2770 </item>
2771 </layout>
2772 </widget>
2773 </item>
2774 <item alignment="Qt::AlignHCenter">
2775 <widget class="QGroupBox" name="buttonRStickModGroup">
2776 <property name="title">
2777 <string>Modifier</string>
2778 </property>
2779 <property name="alignment">
2780 <set>Qt::AlignCenter</set>
2781 </property>
2782 <layout class="QVBoxLayout" name="buttonRStickModVerticalLayout">
2783 <property name="spacing">
2784 <number>3</number>
2785 </property>
2786 <property name="leftMargin">
2787 <number>3</number>
2788 </property>
2789 <property name="topMargin">
2790 <number>3</number>
2791 </property>
2792 <property name="rightMargin">
2793 <number>3</number>
2794 </property>
2795 <property name="bottomMargin">
2796 <number>3</number>
2797 </property>
2798 <item>
2799 <widget class="QPushButton" name="buttonRStickMod">
2800 <property name="minimumSize">
2801 <size>
2802 <width>57</width>
2803 <height>0</height>
2804 </size>
2805 </property>
2806 <property name="maximumSize">
2807 <size>
2808 <width>55</width>
2809 <height>16777215</height>
2810 </size>
2811 </property>
2812 <property name="styleSheet">
2813 <string notr="true">min-width: 55px;</string>
2814 </property>
2815 <property name="text">
2816 <string>Modifier</string>
2817 </property>
2818 </widget>
2819 </item>
2820 </layout>
2821 </widget>
2822 </item>
2823 <item>
2824 <widget class="QGroupBox" name="buttonRStickRangeGroup">
2825 <property name="title">
2826 <string>Range</string>
2827 </property>
2828 <layout class="QHBoxLayout" name="buttonRStickRangeGroupHorizontalLayout">
2829 <property name="spacing">
2830 <number>3</number>
2831 </property>
2832 <property name="leftMargin">
2833 <number>3</number>
2834 </property>
2835 <property name="topMargin">
2836 <number>3</number>
2837 </property>
2838 <property name="rightMargin">
2839 <number>3</number>
2840 </property>
2841 <property name="bottomMargin">
2842 <number>3</number>
2843 </property>
2844 <item>
2845 <widget class="QSpinBox" name="spinboxRStickRange">
2846 <property name="minimumSize">
2847 <size>
2848 <width>55</width>
2849 <height>21</height>
2850 </size>
2851 </property>
2852 <property name="maximumSize">
2853 <size>
2854 <width>55</width>
2855 <height>16777215</height>
2856 </size>
2857 </property>
2858 <property name="suffix">
2859 <string>%</string>
2860 </property>
2861 <property name="minimum">
2862 <number>50</number>
2863 </property>
2864 <property name="maximum">
2865 <number>150</number>
2866 </property>
2867 <property name="value">
2868 <number>100</number>
2869 </property>
2870 </widget>
2871 </item>
2872 </layout>
2873 </widget>
2874 </item>
2875 </layout>
2876 </item>
2877 <item>
2878 <layout class="QVBoxLayout" name="sliderRStickDeadzoneModifierRangeVerticalLayout">
2879 <property name="spacing">
2880 <number>3</number>
2881 </property>
2882 <property name="leftMargin">
2883 <number>0</number>
2884 </property>
2885 <property name="topMargin">
2886 <number>2</number>
2887 </property>
2888 <property name="rightMargin">
2889 <number>0</number>
2890 </property>
2891 <property name="bottomMargin">
2892 <number>3</number>
2893 </property>
2894 <item>
2895 <layout class="QHBoxLayout" name="sliderRStickDeadzoneHorizontalLayout">
2896 <item>
2897 <widget class="QLabel" name="labelRStickDeadzone">
2898 <property name="text">
2899 <string>Deadzone: 0%</string>
2900 </property>
2901 <property name="alignment">
2902 <set>Qt::AlignHCenter</set>
2903 </property>
2904 </widget>
2905 </item>
2906 </layout>
2907 </item>
2908 <item>
2909 <widget class="QSlider" name="sliderRStickDeadzone">
2910 <property name="maximum">
2911 <number>100</number>
2912 </property>
2913 <property name="orientation">
2914 <enum>Qt::Horizontal</enum>
2915 </property>
2916 </widget>
2917 </item>
2918 <item>
2919 <layout class="QHBoxLayout" name="sliderRStickModifierRangeHorizontalLayout">
2920 <item>
2921 <widget class="QLabel" name="labelRStickModifierRange">
2922 <property name="text">
2923 <string>Modifier Range: 0%</string>
2924 </property>
2925 <property name="alignment">
2926 <set>Qt::AlignHCenter</set>
2927 </property>
2928 </widget>
2929 </item>
2930 </layout>
2931 </item>
2932 <item>
2933 <widget class="QSlider" name="sliderRStickModifierRange">
2934 <property name="maximum">
2935 <number>100</number>
2936 </property>
2937 <property name="orientation">
2938 <enum>Qt::Horizontal</enum>
2939 </property>
2940 </widget>
2941 </item>
2942 </layout>
2943 </item>
2944 </layout>
2945 </widget>
2946 </item>
2947 <item>
2948 <spacer name="verticalSpacerBottomRight_2">
2949 <property name="orientation">
2950 <enum>Qt::Vertical</enum>
2951 </property>
2952 <property name="sizeHint" stdset="0">
2953 <size>
2954 <width>20</width>
2955 <height>0</height>
2956 </size>
2957 </property>
2958 </spacer>
2959 </item>
2960 </layout>
2961 </widget>
1104 </item> 2962 </item>
1105 </layout> 2963 </layout>
1106 </widget> 2964 </widget>
1107 </item> 2965 </item>
1108 </layout> 2966 </layout>
1109 </item> 2967 </item>
1110 <item>
1111 <spacer name="verticalSpacer">
1112 <property name="orientation">
1113 <enum>Qt::Vertical</enum>
1114 </property>
1115 <property name="sizeHint" stdset="0">
1116 <size>
1117 <width>20</width>
1118 <height>40</height>
1119 </size>
1120 </property>
1121 </spacer>
1122 </item>
1123 <item>
1124 <layout class="QHBoxLayout" name="horizontalLayout"/>
1125 </item>
1126 <item>
1127 <layout class="QHBoxLayout" name="horizontalLayout_2">
1128 <item>
1129 <widget class="QPushButton" name="buttonClearAll">
1130 <property name="sizePolicy">
1131 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
1132 <horstretch>0</horstretch>
1133 <verstretch>0</verstretch>
1134 </sizepolicy>
1135 </property>
1136 <property name="sizeIncrement">
1137 <size>
1138 <width>0</width>
1139 <height>0</height>
1140 </size>
1141 </property>
1142 <property name="baseSize">
1143 <size>
1144 <width>0</width>
1145 <height>0</height>
1146 </size>
1147 </property>
1148 <property name="layoutDirection">
1149 <enum>Qt::LeftToRight</enum>
1150 </property>
1151 <property name="text">
1152 <string>Clear All</string>
1153 </property>
1154 </widget>
1155 </item>
1156 <item>
1157 <widget class="QPushButton" name="buttonRestoreDefaults">
1158 <property name="sizePolicy">
1159 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
1160 <horstretch>0</horstretch>
1161 <verstretch>0</verstretch>
1162 </sizepolicy>
1163 </property>
1164 <property name="sizeIncrement">
1165 <size>
1166 <width>0</width>
1167 <height>0</height>
1168 </size>
1169 </property>
1170 <property name="baseSize">
1171 <size>
1172 <width>0</width>
1173 <height>0</height>
1174 </size>
1175 </property>
1176 <property name="layoutDirection">
1177 <enum>Qt::LeftToRight</enum>
1178 </property>
1179 <property name="text">
1180 <string>Restore Defaults</string>
1181 </property>
1182 </widget>
1183 </item>
1184 <item>
1185 <spacer name="horizontalSpacer">
1186 <property name="orientation">
1187 <enum>Qt::Horizontal</enum>
1188 </property>
1189 <property name="sizeHint" stdset="0">
1190 <size>
1191 <width>40</width>
1192 <height>20</height>
1193 </size>
1194 </property>
1195 </spacer>
1196 </item>
1197 <item>
1198 <widget class="QDialogButtonBox" name="buttonBox">
1199 <property name="standardButtons">
1200 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
1201 </property>
1202 </widget>
1203 </item>
1204 </layout>
1205 </item>
1206 </layout> 2968 </layout>
1207 </widget> 2969 </widget>
1208 <resources/> 2970 <resources>
1209 <connections> 2971 <include location="../../../dist/icons/controller/controller.qrc"/>
1210 <connection> 2972 </resources>
1211 <sender>buttonBox</sender> 2973 <connections/>
1212 <signal>accepted()</signal>
1213 <receiver>ConfigureInputPlayer</receiver>
1214 <slot>accept()</slot>
1215 <hints>
1216 <hint type="sourcelabel">
1217 <x>371</x>
1218 <y>730</y>
1219 </hint>
1220 <hint type="destinationlabel">
1221 <x>229</x>
1222 <y>375</y>
1223 </hint>
1224 </hints>
1225 </connection>
1226 <connection>
1227 <sender>buttonBox</sender>
1228 <signal>rejected()</signal>
1229 <receiver>ConfigureInputPlayer</receiver>
1230 <slot>reject()</slot>
1231 <hints>
1232 <hint type="sourcelabel">
1233 <x>371</x>
1234 <y>730</y>
1235 </hint>
1236 <hint type="destinationlabel">
1237 <x>229</x>
1238 <y>375</y>
1239 </hint>
1240 </hints>
1241 </connection>
1242 </connections>
1243</ui> 2974</ui>
diff --git a/src/yuzu/configuration/configure_input_simple.cpp b/src/yuzu/configuration/configure_input_simple.cpp
deleted file mode 100644
index 0e0e8f113..000000000
--- a/src/yuzu/configuration/configure_input_simple.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <tuple>
7
8#include "ui_configure_input_simple.h"
9#include "yuzu/configuration/configure_input.h"
10#include "yuzu/configuration/configure_input_player.h"
11#include "yuzu/configuration/configure_input_simple.h"
12#include "yuzu/uisettings.h"
13
14namespace {
15
16template <typename Dialog, typename... Args>
17void CallConfigureDialog(ConfigureInputSimple* caller, Args&&... args) {
18 caller->ApplyConfiguration();
19 Dialog dialog(caller, std::forward<Args>(args)...);
20
21 const auto res = dialog.exec();
22 if (res == QDialog::Accepted) {
23 dialog.ApplyConfiguration();
24 }
25}
26
27// OnProfileSelect functions should (when applicable):
28// - Set controller types
29// - Set controller enabled
30// - Set docked mode
31// - Set advanced controller config/enabled (i.e. debug, kbd, mouse, touch)
32//
33// OnProfileSelect function should NOT however:
34// - Reset any button mappings
35// - Open any dialogs
36// - Block in any way
37
38constexpr std::size_t PLAYER_0_INDEX = 0;
39constexpr std::size_t HANDHELD_INDEX = 8;
40
41void HandheldOnProfileSelect() {
42 Settings::values.players[HANDHELD_INDEX].connected = true;
43 Settings::values.players[HANDHELD_INDEX].type = Settings::ControllerType::DualJoycon;
44
45 for (std::size_t player = 0; player < HANDHELD_INDEX; ++player) {
46 Settings::values.players[player].connected = false;
47 }
48
49 Settings::values.use_docked_mode = false;
50 Settings::values.keyboard_enabled = false;
51 Settings::values.mouse_enabled = false;
52 Settings::values.debug_pad_enabled = false;
53 Settings::values.touchscreen.enabled = true;
54}
55
56void DualJoyconsDockedOnProfileSelect() {
57 Settings::values.players[PLAYER_0_INDEX].connected = true;
58 Settings::values.players[PLAYER_0_INDEX].type = Settings::ControllerType::DualJoycon;
59
60 for (std::size_t player = 1; player <= HANDHELD_INDEX; ++player) {
61 Settings::values.players[player].connected = false;
62 }
63
64 Settings::values.use_docked_mode = true;
65 Settings::values.keyboard_enabled = false;
66 Settings::values.mouse_enabled = false;
67 Settings::values.debug_pad_enabled = false;
68 Settings::values.touchscreen.enabled = true;
69}
70
71// Name, OnProfileSelect (called when selected in drop down), OnConfigure (called when configure
72// is clicked)
73using InputProfile = std::tuple<const char*, void (*)(), void (*)(ConfigureInputSimple*)>;
74
75constexpr std::array<InputProfile, 3> INPUT_PROFILES{{
76 {QT_TR_NOOP("Single Player - Handheld - Undocked"), HandheldOnProfileSelect,
77 [](ConfigureInputSimple* caller) {
78 CallConfigureDialog<ConfigureInputPlayer>(caller, HANDHELD_INDEX, false);
79 }},
80 {QT_TR_NOOP("Single Player - Dual Joycons - Docked"), DualJoyconsDockedOnProfileSelect,
81 [](ConfigureInputSimple* caller) {
82 CallConfigureDialog<ConfigureInputPlayer>(caller, PLAYER_0_INDEX, false);
83 }},
84 {QT_TR_NOOP("Custom"), [] {}, CallConfigureDialog<ConfigureInput>},
85}};
86
87} // namespace
88
89void ApplyInputProfileConfiguration(int profile_index) {
90 std::get<1>(
91 INPUT_PROFILES.at(std::min(profile_index, static_cast<int>(INPUT_PROFILES.size() - 1))))();
92}
93
94ConfigureInputSimple::ConfigureInputSimple(QWidget* parent)
95 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputSimple>()) {
96 ui->setupUi(this);
97
98 for (const auto& profile : INPUT_PROFILES) {
99 const QString label = tr(std::get<0>(profile));
100 ui->profile_combobox->addItem(label, label);
101 }
102
103 connect(ui->profile_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
104 &ConfigureInputSimple::OnSelectProfile);
105 connect(ui->profile_configure, &QPushButton::clicked, this, &ConfigureInputSimple::OnConfigure);
106
107 LoadConfiguration();
108}
109
110ConfigureInputSimple::~ConfigureInputSimple() = default;
111
112void ConfigureInputSimple::ApplyConfiguration() {
113 auto index = ui->profile_combobox->currentIndex();
114 // Make the stored index for "Custom" very large so that if new profiles are added it
115 // doesn't change.
116 if (index >= static_cast<int>(INPUT_PROFILES.size() - 1)) {
117 index = std::numeric_limits<int>::max();
118 }
119
120 UISettings::values.profile_index = index;
121}
122
123void ConfigureInputSimple::changeEvent(QEvent* event) {
124 if (event->type() == QEvent::LanguageChange) {
125 RetranslateUI();
126 }
127
128 QWidget::changeEvent(event);
129}
130
131void ConfigureInputSimple::RetranslateUI() {
132 ui->retranslateUi(this);
133}
134
135void ConfigureInputSimple::LoadConfiguration() {
136 const auto index = UISettings::values.profile_index;
137 if (index >= static_cast<int>(INPUT_PROFILES.size()) || index < 0) {
138 ui->profile_combobox->setCurrentIndex(static_cast<int>(INPUT_PROFILES.size() - 1));
139 } else {
140 ui->profile_combobox->setCurrentIndex(index);
141 }
142}
143
144void ConfigureInputSimple::OnSelectProfile(int index) {
145 const auto old_docked = Settings::values.use_docked_mode;
146 ApplyInputProfileConfiguration(index);
147 OnDockedModeChanged(old_docked, Settings::values.use_docked_mode);
148}
149
150void ConfigureInputSimple::OnConfigure() {
151 std::get<2>(INPUT_PROFILES.at(ui->profile_combobox->currentIndex()))(this);
152}
diff --git a/src/yuzu/configuration/configure_input_simple.h b/src/yuzu/configuration/configure_input_simple.h
deleted file mode 100644
index bb5050224..000000000
--- a/src/yuzu/configuration/configure_input_simple.h
+++ /dev/null
@@ -1,43 +0,0 @@
1// Copyright 2016 Citra 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
9#include <QWidget>
10
11class QPushButton;
12class QString;
13class QTimer;
14
15namespace Ui {
16class ConfigureInputSimple;
17}
18
19// Used by configuration loader to apply a profile if the input is invalid.
20void ApplyInputProfileConfiguration(int profile_index);
21
22class ConfigureInputSimple : public QWidget {
23 Q_OBJECT
24
25public:
26 explicit ConfigureInputSimple(QWidget* parent = nullptr);
27 ~ConfigureInputSimple() override;
28
29 /// Save all button configurations to settings file
30 void ApplyConfiguration();
31
32private:
33 void changeEvent(QEvent* event) override;
34 void RetranslateUI();
35
36 /// Load configuration settings.
37 void LoadConfiguration();
38
39 void OnSelectProfile(int index);
40 void OnConfigure();
41
42 std::unique_ptr<Ui::ConfigureInputSimple> ui;
43};
diff --git a/src/yuzu/configuration/configure_input_simple.ui b/src/yuzu/configuration/configure_input_simple.ui
deleted file mode 100644
index c4889caa9..000000000
--- a/src/yuzu/configuration/configure_input_simple.ui
+++ /dev/null
@@ -1,97 +0,0 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureInputSimple</class>
4 <widget class="QWidget" name="ConfigureInputSimple">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>473</width>
10 <height>685</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>ConfigureInputSimple</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout_5">
17 <item>
18 <layout class="QVBoxLayout" name="verticalLayout">
19 <item>
20 <widget class="QGroupBox" name="gridGroupBox">
21 <property name="title">
22 <string>Profile</string>
23 </property>
24 <layout class="QGridLayout" name="gridLayout">
25 <item row="1" column="2">
26 <widget class="QPushButton" name="profile_configure">
27 <property name="text">
28 <string>Configure</string>
29 </property>
30 </widget>
31 </item>
32 <item row="1" column="0">
33 <spacer name="horizontalSpacer">
34 <property name="orientation">
35 <enum>Qt::Horizontal</enum>
36 </property>
37 <property name="sizeHint" stdset="0">
38 <size>
39 <width>40</width>
40 <height>20</height>
41 </size>
42 </property>
43 </spacer>
44 </item>
45 <item row="1" column="3">
46 <spacer name="horizontalSpacer_2">
47 <property name="orientation">
48 <enum>Qt::Horizontal</enum>
49 </property>
50 <property name="sizeHint" stdset="0">
51 <size>
52 <width>40</width>
53 <height>20</height>
54 </size>
55 </property>
56 </spacer>
57 </item>
58 <item row="1" column="1">
59 <widget class="QComboBox" name="profile_combobox">
60 <property name="minimumSize">
61 <size>
62 <width>250</width>
63 <height>0</height>
64 </size>
65 </property>
66 </widget>
67 </item>
68 <item row="0" column="1" colspan="2">
69 <widget class="QLabel" name="label">
70 <property name="text">
71 <string>Choose a controller configuration:</string>
72 </property>
73 </widget>
74 </item>
75 </layout>
76 </widget>
77 </item>
78 </layout>
79 </item>
80 <item>
81 <spacer name="verticalSpacer">
82 <property name="orientation">
83 <enum>Qt::Vertical</enum>
84 </property>
85 <property name="sizeHint" stdset="0">
86 <size>
87 <width>20</width>
88 <height>40</height>
89 </size>
90 </property>
91 </spacer>
92 </item>
93 </layout>
94 </widget>
95 <resources/>
96 <connections/>
97</ui>
diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp
index 5bcf5ffa8..95e1ae873 100644
--- a/src/yuzu/configuration/configure_mouse_advanced.cpp
+++ b/src/yuzu/configuration/configure_mouse_advanced.cpp
@@ -205,15 +205,11 @@ void ConfigureMouseAdvanced::HandleClick(
205 poller->Start(); 205 poller->Start();
206 } 206 }
207 207
208 grabKeyboard(); 208 timeout_timer->start(2500); // Cancel after 2.5 seconds
209 grabMouse(); 209 poll_timer->start(50); // Check for new inputs every 50ms
210 timeout_timer->start(5000); // Cancel after 5 seconds
211 poll_timer->start(200); // Check for new inputs every 200ms
212} 210}
213 211
214void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params, bool abort) { 212void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params, bool abort) {
215 releaseKeyboard();
216 releaseMouse();
217 timeout_timer->stop(); 213 timeout_timer->stop();
218 poll_timer->stop(); 214 poll_timer->stop();
219 for (auto& poller : device_pollers) { 215 for (auto& poller : device_pollers) {
diff --git a/src/yuzu/configuration/configure_mouse_advanced.ui b/src/yuzu/configuration/configure_mouse_advanced.ui
index 08245ecf0..74552fdbd 100644
--- a/src/yuzu/configuration/configure_mouse_advanced.ui
+++ b/src/yuzu/configuration/configure_mouse_advanced.ui
@@ -6,13 +6,18 @@
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>250</width> 9 <width>310</width>
10 <height>261</height> 10 <height>193</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Configure Mouse</string> 14 <string>Configure Mouse</string>
15 </property> 15 </property>
16 <property name="styleSheet">
17 <string notr="true">QPushButton {
18 min-width: 55px;
19}</string>
20 </property>
16 <layout class="QVBoxLayout" name="verticalLayout"> 21 <layout class="QVBoxLayout" name="verticalLayout">
17 <item> 22 <item>
18 <widget class="QGroupBox" name="gridGroupBox"> 23 <widget class="QGroupBox" name="gridGroupBox">
@@ -20,81 +25,33 @@
20 <string>Mouse Buttons</string> 25 <string>Mouse Buttons</string>
21 </property> 26 </property>
22 <layout class="QGridLayout" name="gridLayout"> 27 <layout class="QGridLayout" name="gridLayout">
23 <item row="0" column="4"> 28 <item row="3" column="5">
24 <spacer name="horizontalSpacer_2"> 29 <layout class="QVBoxLayout" name="verticalLayout_6">
25 <property name="orientation">
26 <enum>Qt::Horizontal</enum>
27 </property>
28 <property name="sizeType">
29 <enum>QSizePolicy::Fixed</enum>
30 </property>
31 <property name="sizeHint" stdset="0">
32 <size>
33 <width>20</width>
34 <height>20</height>
35 </size>
36 </property>
37 </spacer>
38 </item>
39 <item row="0" column="3">
40 <layout class="QVBoxLayout" name="verticalLayout_4">
41 <item> 30 <item>
42 <layout class="QHBoxLayout" name="horizontalLayout_3"> 31 <layout class="QHBoxLayout" name="horizontalLayout_5">
43 <item> 32 <item>
44 <widget class="QLabel" name="label_3"> 33 <widget class="QLabel" name="label_5">
45 <property name="text"> 34 <property name="text">
46 <string>Right:</string> 35 <string>Forward:</string>
47 </property> 36 </property>
48 </widget> 37 </widget>
49 </item> 38 </item>
50 </layout> 39 </layout>
51 </item> 40 </item>
52 <item> 41 <item>
53 <widget class="QPushButton" name="right_button"> 42 <widget class="QPushButton" name="forward_button">
54 <property name="minimumSize"> 43 <property name="minimumSize">
55 <size> 44 <size>
56 <width>75</width> 45 <width>57</width>
57 <height>0</height> 46 <height>0</height>
58 </size> 47 </size>
59 </property> 48 </property>
60 <property name="text"> 49 <property name="maximumSize">
61 <string/> 50 <size>
51 <width>16777215</width>
52 <height>16777215</height>
53 </size>
62 </property> 54 </property>
63 </widget>
64 </item>
65 </layout>
66 </item>
67 <item row="0" column="0">
68 <spacer name="horizontalSpacer">
69 <property name="orientation">
70 <enum>Qt::Horizontal</enum>
71 </property>
72 <property name="sizeType">
73 <enum>QSizePolicy::Fixed</enum>
74 </property>
75 <property name="sizeHint" stdset="0">
76 <size>
77 <width>20</width>
78 <height>20</height>
79 </size>
80 </property>
81 </spacer>
82 </item>
83 <item row="2" column="1">
84 <layout class="QVBoxLayout" name="verticalLayout_3">
85 <item>
86 <layout class="QHBoxLayout" name="horizontalLayout_2">
87 <item>
88 <widget class="QLabel" name="label_2">
89 <property name="text">
90 <string>Middle:</string>
91 </property>
92 </widget>
93 </item>
94 </layout>
95 </item>
96 <item>
97 <widget class="QPushButton" name="middle_button">
98 <property name="text"> 55 <property name="text">
99 <string/> 56 <string/>
100 </property> 57 </property>
@@ -123,6 +80,12 @@
123 </item> 80 </item>
124 <item> 81 <item>
125 <widget class="QPushButton" name="back_button"> 82 <widget class="QPushButton" name="back_button">
83 <property name="minimumSize">
84 <size>
85 <width>57</width>
86 <height>0</height>
87 </size>
88 </property>
126 <property name="text"> 89 <property name="text">
127 <string/> 90 <string/>
128 </property> 91 </property>
@@ -147,7 +110,7 @@
147 <widget class="QPushButton" name="left_button"> 110 <widget class="QPushButton" name="left_button">
148 <property name="minimumSize"> 111 <property name="minimumSize">
149 <size> 112 <size>
150 <width>75</width> 113 <width>57</width>
151 <height>0</height> 114 <height>0</height>
152 </size> 115 </size>
153 </property> 116 </property>
@@ -158,21 +121,99 @@
158 </item> 121 </item>
159 </layout> 122 </layout>
160 </item> 123 </item>
161 <item row="3" column="3"> 124 <item row="0" column="3">
162 <layout class="QVBoxLayout" name="verticalLayout_6"> 125 <layout class="QVBoxLayout" name="verticalLayout_3">
163 <item> 126 <item>
164 <layout class="QHBoxLayout" name="horizontalLayout_5"> 127 <layout class="QHBoxLayout" name="horizontalLayout_2">
165 <item> 128 <item>
166 <widget class="QLabel" name="label_5"> 129 <widget class="QLabel" name="label_2">
167 <property name="text"> 130 <property name="text">
168 <string>Forward:</string> 131 <string>Middle:</string>
169 </property> 132 </property>
170 </widget> 133 </widget>
171 </item> 134 </item>
172 </layout> 135 </layout>
173 </item> 136 </item>
174 <item> 137 <item>
175 <widget class="QPushButton" name="forward_button"> 138 <widget class="QPushButton" name="middle_button">
139 <property name="minimumSize">
140 <size>
141 <width>57</width>
142 <height>0</height>
143 </size>
144 </property>
145 <property name="maximumSize">
146 <size>
147 <width>16777215</width>
148 <height>16777215</height>
149 </size>
150 </property>
151 <property name="text">
152 <string/>
153 </property>
154 </widget>
155 </item>
156 </layout>
157 </item>
158 <item row="0" column="6">
159 <spacer name="horizontalSpacer_2">
160 <property name="orientation">
161 <enum>Qt::Horizontal</enum>
162 </property>
163 <property name="sizeType">
164 <enum>QSizePolicy::Fixed</enum>
165 </property>
166 <property name="sizeHint" stdset="0">
167 <size>
168 <width>0</width>
169 <height>20</height>
170 </size>
171 </property>
172 </spacer>
173 </item>
174 <item row="0" column="0">
175 <spacer name="horizontalSpacer">
176 <property name="orientation">
177 <enum>Qt::Horizontal</enum>
178 </property>
179 <property name="sizeType">
180 <enum>QSizePolicy::Fixed</enum>
181 </property>
182 <property name="sizeHint" stdset="0">
183 <size>
184 <width>0</width>
185 <height>20</height>
186 </size>
187 </property>
188 </spacer>
189 </item>
190 <item row="0" column="5">
191 <layout class="QVBoxLayout" name="verticalLayout_4">
192 <item>
193 <layout class="QHBoxLayout" name="horizontalLayout_3">
194 <item>
195 <widget class="QLabel" name="label_3">
196 <property name="text">
197 <string>Right:</string>
198 </property>
199 </widget>
200 </item>
201 </layout>
202 </item>
203 <item>
204 <widget class="QPushButton" name="right_button">
205 <property name="minimumSize">
206 <size>
207 <width>57</width>
208 <height>0</height>
209 </size>
210 </property>
211 <property name="maximumSize">
212 <size>
213 <width>16777215</width>
214 <height>16777215</height>
215 </size>
216 </property>
176 <property name="text"> 217 <property name="text">
177 <string/> 218 <string/>
178 </property> 219 </property>
@@ -180,6 +221,32 @@
180 </item> 221 </item>
181 </layout> 222 </layout>
182 </item> 223 </item>
224 <item row="0" column="2">
225 <spacer name="horizontalSpacer_4">
226 <property name="orientation">
227 <enum>Qt::Horizontal</enum>
228 </property>
229 <property name="sizeHint" stdset="0">
230 <size>
231 <width>0</width>
232 <height>20</height>
233 </size>
234 </property>
235 </spacer>
236 </item>
237 <item row="0" column="4">
238 <spacer name="horizontalSpacer_5">
239 <property name="orientation">
240 <enum>Qt::Horizontal</enum>
241 </property>
242 <property name="sizeHint" stdset="0">
243 <size>
244 <width>0</width>
245 <height>20</height>
246 </size>
247 </property>
248 </spacer>
249 </item>
183 </layout> 250 </layout>
184 </widget> 251 </widget>
185 </item> 252 </item>
@@ -187,15 +254,39 @@
187 <layout class="QHBoxLayout" name="horizontalLayout_6"> 254 <layout class="QHBoxLayout" name="horizontalLayout_6">
188 <item> 255 <item>
189 <widget class="QPushButton" name="buttonClearAll"> 256 <widget class="QPushButton" name="buttonClearAll">
257 <property name="minimumSize">
258 <size>
259 <width>57</width>
260 <height>0</height>
261 </size>
262 </property>
263 <property name="maximumSize">
264 <size>
265 <width>16777215</width>
266 <height>16777215</height>
267 </size>
268 </property>
190 <property name="text"> 269 <property name="text">
191 <string>Clear All</string> 270 <string>Clear</string>
192 </property> 271 </property>
193 </widget> 272 </widget>
194 </item> 273 </item>
195 <item> 274 <item>
196 <widget class="QPushButton" name="buttonRestoreDefaults"> 275 <widget class="QPushButton" name="buttonRestoreDefaults">
276 <property name="minimumSize">
277 <size>
278 <width>57</width>
279 <height>0</height>
280 </size>
281 </property>
282 <property name="maximumSize">
283 <size>
284 <width>16777215</width>
285 <height>16777215</height>
286 </size>
287 </property>
197 <property name="text"> 288 <property name="text">
198 <string>Restore Defaults</string> 289 <string>Defaults</string>
199 </property> 290 </property>
200 </widget> 291 </widget>
201 </item> 292 </item>
@@ -206,21 +297,24 @@
206 </property> 297 </property>
207 <property name="sizeHint" stdset="0"> 298 <property name="sizeHint" stdset="0">
208 <size> 299 <size>
209 <width>40</width> 300 <width>0</width>
210 <height>20</height> 301 <height>20</height>
211 </size> 302 </size>
212 </property> 303 </property>
213 </spacer> 304 </spacer>
214 </item> 305 </item>
306 <item>
307 <widget class="QDialogButtonBox" name="buttonBox">
308 <property name="styleSheet">
309 <string notr="true"/>
310 </property>
311 <property name="standardButtons">
312 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
313 </property>
314 </widget>
315 </item>
215 </layout> 316 </layout>
216 </item> 317 </item>
217 <item>
218 <widget class="QDialogButtonBox" name="buttonBox">
219 <property name="standardButtons">
220 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
221 </property>
222 </widget>
223 </item>
224 </layout> 318 </layout>
225 </widget> 319 </widget>
226 <resources/> 320 <resources/>
diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp
index a51175f36..37499fc85 100644
--- a/src/yuzu/uisettings.cpp
+++ b/src/yuzu/uisettings.cpp
@@ -16,4 +16,5 @@ const Themes themes{{
16}}; 16}};
17 17
18Values values = {}; 18Values values = {};
19
19} // namespace UISettings 20} // namespace UISettings
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index 2d2e82f15..533815098 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -13,6 +13,7 @@
13#include <QStringList> 13#include <QStringList>
14#include <QVector> 14#include <QVector>
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "core/settings.h"
16 17
17namespace UISettings { 18namespace UISettings {
18 19
@@ -87,9 +88,6 @@ struct Values {
87 // logging 88 // logging
88 bool show_console; 89 bool show_console;
89 90
90 // Controllers
91 int profile_index;
92
93 // Game List 91 // Game List
94 bool show_add_ons; 92 bool show_add_ons;
95 uint32_t icon_size; 93 uint32_t icon_size;
@@ -100,6 +98,7 @@ struct Values {
100}; 98};
101 99
102extern Values values; 100extern Values values;
101
103} // namespace UISettings 102} // namespace UISettings
104 103
105Q_DECLARE_METATYPE(UISettings::GameDir*); 104Q_DECLARE_METATYPE(UISettings::GameDir*);
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 8a63fd191..e9f1c6500 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -288,6 +288,8 @@ void Config::ReadValues() {
288 Settings::values.debug_pad_analogs[i] = default_param; 288 Settings::values.debug_pad_analogs[i] = default_param;
289 } 289 }
290 290
291 Settings::values.vibration_enabled =
292 sdl2_config->GetBoolean("ControlsGeneral", "vibration_enabled", true);
291 Settings::values.touchscreen.enabled = 293 Settings::values.touchscreen.enabled =
292 sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true); 294 sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
293 Settings::values.touchscreen.device = 295 Settings::values.touchscreen.device =
diff --git a/src/yuzu_tester/config.cpp b/src/yuzu_tester/config.cpp
index 74022af23..aaf59129a 100644
--- a/src/yuzu_tester/config.cpp
+++ b/src/yuzu_tester/config.cpp
@@ -75,6 +75,7 @@ void Config::ReadValues() {
75 Settings::values.debug_pad_analogs[i] = ""; 75 Settings::values.debug_pad_analogs[i] = "";
76 } 76 }
77 77
78 Settings::values.vibration_enabled = true;
78 Settings::values.touchscreen.enabled = ""; 79 Settings::values.touchscreen.enabled = "";
79 Settings::values.touchscreen.device = ""; 80 Settings::values.touchscreen.device = "";
80 Settings::values.touchscreen.finger = 0; 81 Settings::values.touchscreen.finger = 0;