summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar german772021-10-11 00:43:11 -0500
committerGravatar Narr the Reg2021-11-24 20:30:24 -0600
commit06a5ef5874144a70e30e577a83ba68d1dad79e78 (patch)
tree867fa1153c7285c858cdb5bd7f60f08266532a88 /src
parentcore: Update input interpreter (diff)
downloadyuzu-06a5ef5874144a70e30e577a83ba68d1dad79e78.tar.gz
yuzu-06a5ef5874144a70e30e577a83ba68d1dad79e78.tar.xz
yuzu-06a5ef5874144a70e30e577a83ba68d1dad79e78.zip
core/hid: Add output devices
Diffstat (limited to 'src')
-rw-r--r--src/common/input.h39
-rw-r--r--src/core/hid/emulated_controller.cpp119
-rw-r--r--src/core/hid/emulated_controller.h13
-rw-r--r--src/core/hid/hid_types.h18
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp27
-rw-r--r--src/core/hle/service/hid/controllers/npad.h18
-rw-r--r--src/input_common/drivers/gc_adapter.cpp8
-rw-r--r--src/input_common/drivers/gc_adapter.h2
-rw-r--r--src/input_common/drivers/sdl_driver.cpp8
-rw-r--r--src/input_common/drivers/sdl_driver.h2
-rw-r--r--src/input_common/helpers/stick_from_buttons.cpp3
-rw-r--r--src/input_common/helpers/stick_from_buttons.h3
-rw-r--r--src/input_common/helpers/touch_from_buttons.cpp4
-rw-r--r--src/input_common/input_engine.h18
-rw-r--r--src/input_common/input_poller.cpp40
-rw-r--r--src/input_common/input_poller.h28
-rw-r--r--src/input_common/main.cpp30
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp7
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp59
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.h10
20 files changed, 312 insertions, 144 deletions
diff --git a/src/common/input.h b/src/common/input.h
index 6eefc55f9..3a28b77a7 100644
--- a/src/common/input.h
+++ b/src/common/input.h
@@ -38,6 +38,27 @@ enum class BatteryLevel {
38 Charging, 38 Charging,
39}; 39};
40 40
41enum class PollingMode {
42 Active,
43 Pasive,
44 Camera,
45 NCF,
46 IR,
47};
48
49enum class VibrationError {
50 None,
51 NotSupported,
52 Disabled,
53 Unknown,
54};
55
56enum class PollingError {
57 None,
58 NotSupported,
59 Unknown,
60};
61
41struct AnalogProperties { 62struct AnalogProperties {
42 float deadzone{}; 63 float deadzone{};
43 float range{1.0f}; 64 float range{1.0f};
@@ -149,6 +170,24 @@ private:
149 InputCallback callback; 170 InputCallback callback;
150}; 171};
151 172
173/// An abstract class template for an output device (rumble, LED pattern, polling mode).
174class OutputDevice {
175public:
176 virtual ~OutputDevice() = default;
177
178 virtual void SetLED([[maybe_unused]] LedStatus led_status) {
179 return;
180 }
181
182 virtual VibrationError SetVibration([[maybe_unused]] VibrationStatus vibration_status) {
183 return VibrationError::NotSupported;
184 }
185
186 virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) {
187 return PollingError::NotSupported;
188 }
189};
190
152/// An abstract class template for a factory that can create input devices. 191/// An abstract class template for a factory that can create input devices.
153template <typename InputDeviceType> 192template <typename InputDeviceType>
154class Factory { 193class Factory {
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 4eb5d99bc..b9d16657a 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -66,12 +66,32 @@ void EmulatedController::ReloadFromSettings() {
66 for (std::size_t index = 0; index < player.motions.size(); ++index) { 66 for (std::size_t index = 0; index < player.motions.size(); ++index) {
67 motion_params[index] = Common::ParamPackage(player.motions[index]); 67 motion_params[index] = Common::ParamPackage(player.motions[index]);
68 } 68 }
69
70 controller.colors_state.left = {
71 .body = player.body_color_left,
72 .button = player.button_color_left,
73 };
74
75 controller.colors_state.right = {
76 .body = player.body_color_right,
77 .button = player.button_color_right,
78 };
79
80 controller.colors_state.fullkey = controller.colors_state.left;
81
82 SetNpadType(MapSettingsTypeToNPad(player.controller_type));
83
84 if (player.connected) {
85 Connect();
86 } else {
87 Disconnect();
88 }
89
69 ReloadInput(); 90 ReloadInput();
70} 91}
71 92
72void EmulatedController::ReloadInput() { 93void EmulatedController::ReloadInput() {
73 const auto player_index = NpadIdTypeToIndex(npad_id_type); 94 const auto player_index = NpadIdTypeToIndex(npad_id_type);
74 const auto& player = Settings::values.players.GetValue()[player_index];
75 const auto left_side = button_params[Settings::NativeButton::ZL]; 95 const auto left_side = button_params[Settings::NativeButton::ZL];
76 const auto right_side = button_params[Settings::NativeButton::ZR]; 96 const auto right_side = button_params[Settings::NativeButton::ZR];
77 97
@@ -90,21 +110,13 @@ void EmulatedController::ReloadInput() {
90 trigger_devices[1] = 110 trigger_devices[1] =
91 Input::CreateDevice<Input::InputDevice>(button_params[Settings::NativeButton::ZR]); 111 Input::CreateDevice<Input::InputDevice>(button_params[Settings::NativeButton::ZR]);
92 112
93 controller.colors_state.left = {
94 .body = player.body_color_left,
95 .button = player.button_color_left,
96 };
97
98 controller.colors_state.right = {
99 .body = player.body_color_right,
100 .button = player.button_color_right,
101 };
102
103 controller.colors_state.fullkey = controller.colors_state.left;
104
105 battery_devices[0] = Input::CreateDevice<Input::InputDevice>(left_side); 113 battery_devices[0] = Input::CreateDevice<Input::InputDevice>(left_side);
106 battery_devices[1] = Input::CreateDevice<Input::InputDevice>(right_side); 114 battery_devices[1] = Input::CreateDevice<Input::InputDevice>(right_side);
107 115
116 button_params[Settings::NativeButton::ZL].Set("output",true);
117 output_devices[0] =
118 Input::CreateDevice<Input::OutputDevice>(button_params[Settings::NativeButton::ZL]);
119
108 for (std::size_t index = 0; index < button_devices.size(); ++index) { 120 for (std::size_t index = 0; index < button_devices.size(); ++index) {
109 if (!button_devices[index]) { 121 if (!button_devices[index]) {
110 continue; 122 continue;
@@ -149,14 +161,6 @@ void EmulatedController::ReloadInput() {
149 [this, index](Input::CallbackStatus callback) { SetMotion(callback, index); }}; 161 [this, index](Input::CallbackStatus callback) { SetMotion(callback, index); }};
150 motion_devices[index]->SetCallback(motion_callback); 162 motion_devices[index]->SetCallback(motion_callback);
151 } 163 }
152
153 SetNpadType(MapSettingsTypeToNPad(player.controller_type));
154
155 if (player.connected) {
156 Connect();
157 } else {
158 Disconnect();
159 }
160} 164}
161 165
162void EmulatedController::UnloadInput() { 166void EmulatedController::UnloadInput() {
@@ -197,7 +201,8 @@ void EmulatedController::SaveCurrentConfig() {
197 201
198 const auto player_index = NpadIdTypeToIndex(npad_id_type); 202 const auto player_index = NpadIdTypeToIndex(npad_id_type);
199 auto& player = Settings::values.players.GetValue()[player_index]; 203 auto& player = Settings::values.players.GetValue()[player_index];
200 204 player.connected = is_connected;
205 player.controller_type = MapNPadToSettingsType(npad_type);
201 for (std::size_t index = 0; index < player.buttons.size(); ++index) { 206 for (std::size_t index = 0; index < player.buttons.size(); ++index) {
202 player.buttons[index] = button_params[index].Serialize(); 207 player.buttons[index] = button_params[index].Serialize();
203 } 208 }
@@ -601,13 +606,50 @@ void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t
601 TriggerOnChange(ControllerTriggerType::Battery); 606 TriggerOnChange(ControllerTriggerType::Battery);
602} 607}
603 608
604bool EmulatedController::SetVibration([[maybe_unused]] std::size_t device_index, 609bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) {
605 [[maybe_unused]] VibrationValue vibration) { 610 if (!output_devices[device_index]) {
606 return false; 611 return false;
612 }
613
614 const Input::VibrationStatus status = {
615 .low_amplitude = vibration.high_amplitude,
616 .low_frequency = vibration.high_amplitude,
617 .high_amplitude = vibration.high_amplitude,
618 .high_frequency = vibration.high_amplitude,
619 };
620 return output_devices[device_index]->SetVibration(status) == Input::VibrationError::None;
621}
622
623bool EmulatedController::TestVibration(std::size_t device_index) {
624 if (!output_devices[device_index]) {
625 return false;
626 }
627
628 // Send a slight vibration to test for rumble support
629 constexpr Input::VibrationStatus status = {
630 .low_amplitude = 0.001f,
631 .low_frequency = 160.0f,
632 .high_amplitude = 0.001f,
633 .high_frequency = 320.0f,
634 };
635 return output_devices[device_index]->SetVibration(status) == Input::VibrationError::None;
607} 636}
608 637
609int EmulatedController::TestVibration(std::size_t device_index) { 638void EmulatedController::SetLedPattern() {
610 return 1; 639 for (auto& device : output_devices) {
640 if (!device) {
641 continue;
642 }
643
644 const LedPattern pattern = GetLedPattern();
645 const Input::LedStatus status = {
646 .led_1 = pattern.position1 != 0,
647 .led_2 = pattern.position2 != 0,
648 .led_3 = pattern.position3 != 0,
649 .led_4 = pattern.position4 != 0,
650 };
651 device->SetLED(status);
652 }
611} 653}
612 654
613void EmulatedController::Connect() { 655void EmulatedController::Connect() {
@@ -655,6 +697,29 @@ void EmulatedController::SetNpadType(NpadType npad_type_) {
655 TriggerOnChange(ControllerTriggerType::Type); 697 TriggerOnChange(ControllerTriggerType::Type);
656} 698}
657 699
700LedPattern EmulatedController::GetLedPattern() const {
701 switch (npad_id_type) {
702 case NpadIdType::Player1:
703 return LedPattern{1, 0, 0, 0};
704 case NpadIdType::Player2:
705 return LedPattern{1, 1, 0, 0};
706 case NpadIdType::Player3:
707 return LedPattern{1, 1, 1, 0};
708 case NpadIdType::Player4:
709 return LedPattern{1, 1, 1, 1};
710 case NpadIdType::Player5:
711 return LedPattern{1, 0, 0, 1};
712 case NpadIdType::Player6:
713 return LedPattern{1, 0, 1, 0};
714 case NpadIdType::Player7:
715 return LedPattern{1, 0, 1, 1};
716 case NpadIdType::Player8:
717 return LedPattern{0, 1, 1, 0};
718 default:
719 return LedPattern{0, 0, 0, 0};
720 }
721}
722
658ButtonValues EmulatedController::GetButtonsValues() const { 723ButtonValues EmulatedController::GetButtonsValues() const {
659 return controller.button_values; 724 return controller.button_values;
660} 725}
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 94db9b00b..322d2cab0 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -33,12 +33,14 @@ using ControllerMotionDevices =
33using TriggerDevices = 33using TriggerDevices =
34 std::array<std::unique_ptr<Input::InputDevice>, Settings::NativeTrigger::NumTriggers>; 34 std::array<std::unique_ptr<Input::InputDevice>, Settings::NativeTrigger::NumTriggers>;
35using BatteryDevices = std::array<std::unique_ptr<Input::InputDevice>, 2>; 35using BatteryDevices = std::array<std::unique_ptr<Input::InputDevice>, 2>;
36using OutputDevices = std::array<std::unique_ptr<Input::OutputDevice>, 2>;
36 37
37using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>; 38using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>;
38using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>; 39using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
39using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>; 40using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>;
40using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>; 41using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>;
41using BatteryParams = std::array<Common::ParamPackage, 2>; 42using BatteryParams = std::array<Common::ParamPackage, 2>;
43using OutputParams = std::array<Common::ParamPackage, 2>;
42 44
43using ButtonValues = std::array<Input::ButtonStatus, Settings::NativeButton::NumButtons>; 45using ButtonValues = std::array<Input::ButtonStatus, Settings::NativeButton::NumButtons>;
44using SticksValues = std::array<Input::StickStatus, Settings::NativeAnalog::NumAnalogs>; 46using SticksValues = std::array<Input::StickStatus, Settings::NativeAnalog::NumAnalogs>;
@@ -94,6 +96,7 @@ struct ControllerStatus {
94 ControllerColors colors_state{}; 96 ControllerColors colors_state{};
95 BatteryLevelState battery_state{}; 97 BatteryLevelState battery_state{};
96}; 98};
99
97enum class ControllerTriggerType { 100enum class ControllerTriggerType {
98 Button, 101 Button,
99 Stick, 102 Stick,
@@ -137,6 +140,9 @@ public:
137 /// Gets the NpadType for this controller. 140 /// Gets the NpadType for this controller.
138 NpadType GetNpadType() const; 141 NpadType GetNpadType() const;
139 142
143 /// Gets the NpadType for this controller.
144 LedPattern GetLedPattern() const;
145
140 void Connect(); 146 void Connect();
141 void Disconnect(); 147 void Disconnect();
142 148
@@ -179,7 +185,9 @@ public:
179 BatteryLevelState GetBattery() const; 185 BatteryLevelState GetBattery() const;
180 186
181 bool SetVibration(std::size_t device_index, VibrationValue vibration); 187 bool SetVibration(std::size_t device_index, VibrationValue vibration);
182 int TestVibration(std::size_t device_index); 188 bool TestVibration(std::size_t device_index);
189
190 void SetLedPattern();
183 191
184 int SetCallback(ControllerUpdateCallback update_callback); 192 int SetCallback(ControllerUpdateCallback update_callback);
185 void DeleteCallback(int key); 193 void DeleteCallback(int key);
@@ -215,13 +223,14 @@ private:
215 ControllerMotionParams motion_params; 223 ControllerMotionParams motion_params;
216 TriggerParams trigger_params; 224 TriggerParams trigger_params;
217 BatteryParams battery_params; 225 BatteryParams battery_params;
226 OutputParams output_params;
218 227
219 ButtonDevices button_devices; 228 ButtonDevices button_devices;
220 StickDevices stick_devices; 229 StickDevices stick_devices;
221 ControllerMotionDevices motion_devices; 230 ControllerMotionDevices motion_devices;
222 TriggerDevices trigger_devices; 231 TriggerDevices trigger_devices;
223 BatteryDevices battery_devices; 232 BatteryDevices battery_devices;
224 // VibrationDevices vibration_devices; 233 OutputDevices output_devices;
225 234
226 mutable std::mutex mutex; 235 mutable std::mutex mutex;
227 std::unordered_map<int, ControllerUpdateCallback> callback_list; 236 std::unordered_map<int, ControllerUpdateCallback> callback_list;
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index d3f7930c9..f12a14cb8 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -112,6 +112,8 @@ struct NpadStyleTag {
112 BitField<7, 1, u32> lark; 112 BitField<7, 1, u32> lark;
113 BitField<8, 1, u32> handheld_lark; 113 BitField<8, 1, u32> handheld_lark;
114 BitField<9, 1, u32> lucia; 114 BitField<9, 1, u32> lucia;
115 BitField<10, 1, u32> lagoon;
116 BitField<11, 1, u32> lager;
115 BitField<29, 1, u32> system_ext; 117 BitField<29, 1, u32> system_ext;
116 BitField<30, 1, u32> system; 118 BitField<30, 1, u32> system;
117 }; 119 };
@@ -175,6 +177,22 @@ struct NpadPowerInfo {
175}; 177};
176static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size"); 178static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size");
177 179
180struct LedPattern {
181 explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
182 position1.Assign(light1);
183 position2.Assign(light2);
184 position3.Assign(light3);
185 position4.Assign(light4);
186 }
187 union {
188 u64 raw{};
189 BitField<0, 1, u64> position1;
190 BitField<1, 1, u64> position2;
191 BitField<2, 1, u64> position3;
192 BitField<3, 1, u64> position4;
193 };
194};
195
178// This is nn::hid::NpadButton 196// This is nn::hid::NpadButton
179enum class NpadButton : u64 { 197enum class NpadButton : u64 {
180 None = 0, 198 None = 0,
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 03cbd42f4..a2e9ddf4d 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -796,7 +796,7 @@ void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index,
796 } 796 }
797 797
798 controller.vibration[device_index].device_mounted = 798 controller.vibration[device_index].device_mounted =
799 controller.device->TestVibration(device_index) == 1; 799 controller.device->TestVibration(device_index);
800} 800}
801 801
802void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { 802void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) {
@@ -954,31 +954,12 @@ bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) {
954 return true; 954 return true;
955} 955}
956 956
957Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { 957Core::HID::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
958 if (npad_id == npad_id_list.back() || npad_id == npad_id_list[npad_id_list.size() - 2]) { 958 if (npad_id == npad_id_list.back() || npad_id == npad_id_list[npad_id_list.size() - 2]) {
959 // These are controllers without led patterns 959 // These are controllers without led patterns
960 return LedPattern{0, 0, 0, 0}; 960 return Core::HID::LedPattern{0, 0, 0, 0};
961 }
962 switch (npad_id) {
963 case 0:
964 return LedPattern{1, 0, 0, 0};
965 case 1:
966 return LedPattern{1, 1, 0, 0};
967 case 2:
968 return LedPattern{1, 1, 1, 0};
969 case 3:
970 return LedPattern{1, 1, 1, 1};
971 case 4:
972 return LedPattern{1, 0, 0, 1};
973 case 5:
974 return LedPattern{1, 0, 1, 0};
975 case 6:
976 return LedPattern{1, 0, 1, 1};
977 case 7:
978 return LedPattern{0, 1, 1, 0};
979 default:
980 return LedPattern{0, 0, 0, 0};
981 } 961 }
962 return controller_data[npad_id].device->GetLedPattern();
982} 963}
983 964
984bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const { 965bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 483cae5b6..b0e2f8430 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -115,22 +115,6 @@ public:
115 .freq_high = 320.0f, 115 .freq_high = 320.0f,
116 }; 116 };
117 117
118 struct LedPattern {
119 explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
120 position1.Assign(light1);
121 position2.Assign(light2);
122 position3.Assign(light3);
123 position4.Assign(light4);
124 }
125 union {
126 u64 raw{};
127 BitField<0, 1, u64> position1;
128 BitField<1, 1, u64> position2;
129 BitField<2, 1, u64> position3;
130 BitField<3, 1, u64> position4;
131 };
132 };
133
134 void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); 118 void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
135 Core::HID::NpadStyleTag GetSupportedStyleSet() const; 119 Core::HID::NpadStyleTag GetSupportedStyleSet() const;
136 120
@@ -186,7 +170,7 @@ public:
186 void SetSixAxisFusionParameters(f32 parameter1, f32 parameter2); 170 void SetSixAxisFusionParameters(f32 parameter1, f32 parameter2);
187 std::pair<f32, f32> GetSixAxisFusionParameters(); 171 std::pair<f32, f32> GetSixAxisFusionParameters();
188 void ResetSixAxisFusionParameters(); 172 void ResetSixAxisFusionParameters();
189 LedPattern GetLedPattern(u32 npad_id); 173 Core::HID::LedPattern GetLedPattern(u32 npad_id);
190 bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const; 174 bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const;
191 void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); 175 void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id);
192 void SetAnalogStickUseCenterClamp(bool use_center_clamp); 176 void SetAnalogStickUseCenterClamp(bool use_center_clamp);
diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp
index 6721ba4f7..2aa5a16a6 100644
--- a/src/input_common/drivers/gc_adapter.cpp
+++ b/src/input_common/drivers/gc_adapter.cpp
@@ -322,13 +322,17 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) {
322 return true; 322 return true;
323} 323}
324 324
325bool GCAdapter::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { 325Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) {
326 const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; 326 const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f;
327 const auto processed_amplitude = 327 const auto processed_amplitude =
328 static_cast<u8>((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); 328 static_cast<u8>((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8);
329 329
330 pads[identifier.port].rumble_amplitude = processed_amplitude; 330 pads[identifier.port].rumble_amplitude = processed_amplitude;
331 return rumble_enabled; 331
332 if (!rumble_enabled) {
333 return Input::VibrationError::Disabled;
334 }
335 return Input::VibrationError::None;
332} 336}
333 337
334void GCAdapter::UpdateVibrations() { 338void GCAdapter::UpdateVibrations() {
diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h
index c0bf1ed7a..dd23dd9f3 100644
--- a/src/input_common/drivers/gc_adapter.h
+++ b/src/input_common/drivers/gc_adapter.h
@@ -24,7 +24,7 @@ public:
24 explicit GCAdapter(const std::string input_engine_); 24 explicit GCAdapter(const std::string input_engine_);
25 ~GCAdapter(); 25 ~GCAdapter();
26 26
27 bool SetRumble(const PadIdentifier& identifier, 27 Input::VibrationError SetRumble(const PadIdentifier& identifier,
28 const Input::VibrationStatus vibration) override; 28 const Input::VibrationStatus vibration) override;
29 29
30 /// Used for automapping features 30 /// Used for automapping features
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index efb4a2106..f7f03c5f2 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -506,7 +506,8 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {
506 } 506 }
507 return devices; 507 return devices;
508} 508}
509bool SDLDriver::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { 509Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier,
510 const Input::VibrationStatus vibration) {
510 const auto joystick = 511 const auto joystick =
511 GetSDLJoystickByGUID(identifier.guid.Format(), static_cast<int>(identifier.port)); 512 GetSDLJoystickByGUID(identifier.guid.Format(), static_cast<int>(identifier.port));
512 const auto process_amplitude = [](f32 amplitude) { 513 const auto process_amplitude = [](f32 amplitude) {
@@ -519,7 +520,10 @@ bool SDLDriver::SetRumble(const PadIdentifier& identifier, const Input::Vibratio
519 .high_frequency = vibration.high_frequency, 520 .high_frequency = vibration.high_frequency,
520 }; 521 };
521 522
522 return joystick->RumblePlay(new_vibration); 523 if (!joystick->RumblePlay(new_vibration)) {
524 return Input::VibrationError::Unknown;
525 }
526 return Input::VibrationError::None;
523} 527}
524Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, 528Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid,
525 s32 axis, float value) const { 529 s32 axis, float value) const {
diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h
index d8d350184..f66b33c77 100644
--- a/src/input_common/drivers/sdl_driver.h
+++ b/src/input_common/drivers/sdl_driver.h
@@ -58,7 +58,7 @@ public:
58 std::string GetHatButtonName(u8 direction_value) const override; 58 std::string GetHatButtonName(u8 direction_value) const override;
59 u8 GetHatButtonId(const std::string direction_name) const override; 59 u8 GetHatButtonId(const std::string direction_name) const override;
60 60
61 bool SetRumble(const PadIdentifier& identifier, 61 Input::VibrationError SetRumble(const PadIdentifier& identifier,
62 const Input::VibrationStatus vibration) override; 62 const Input::VibrationStatus vibration) override;
63 63
64private: 64private:
diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp
index 38f150746..89ba4aeb1 100644
--- a/src/input_common/helpers/stick_from_buttons.cpp
+++ b/src/input_common/helpers/stick_from_buttons.cpp
@@ -251,7 +251,8 @@ private:
251 std::chrono::time_point<std::chrono::steady_clock> last_update; 251 std::chrono::time_point<std::chrono::steady_clock> last_update;
252}; 252};
253 253
254std::unique_ptr<Input::InputDevice> StickFromButton::Create(const Common::ParamPackage& params) { 254std::unique_ptr<Input::InputDevice> StickFromButton::Create(
255 const Common::ParamPackage& params) {
255 const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); 256 const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize();
256 auto up = Input::CreateDeviceFromString<Input::InputDevice>(params.Get("up", null_engine)); 257 auto up = Input::CreateDeviceFromString<Input::InputDevice>(params.Get("up", null_engine));
257 auto down = Input::CreateDeviceFromString<Input::InputDevice>(params.Get("down", null_engine)); 258 auto down = Input::CreateDeviceFromString<Input::InputDevice>(params.Get("down", null_engine));
diff --git a/src/input_common/helpers/stick_from_buttons.h b/src/input_common/helpers/stick_from_buttons.h
index 1d6e24c98..87165e022 100644
--- a/src/input_common/helpers/stick_from_buttons.h
+++ b/src/input_common/helpers/stick_from_buttons.h
@@ -25,7 +25,8 @@ public:
25 * - "modifier": a serialized ParamPackage for creating a button device as the modifier 25 * - "modifier": a serialized ParamPackage for creating a button device as the modifier
26 * - "modifier_scale": a float for the multiplier the modifier gives to the position 26 * - "modifier_scale": a float for the multiplier the modifier gives to the position
27 */ 27 */
28 std::unique_ptr<Input::InputDevice> Create(const Common::ParamPackage& params) override; 28 std::unique_ptr<Input::InputDevice> Create(
29 const Common::ParamPackage& params) override;
29}; 30};
30 31
31} // namespace InputCommon 32} // namespace InputCommon
diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp
index 2abfaf841..6c9046ffb 100644
--- a/src/input_common/helpers/touch_from_buttons.cpp
+++ b/src/input_common/helpers/touch_from_buttons.cpp
@@ -57,7 +57,9 @@ private:
57 const Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; 57 const Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false};
58}; 58};
59 59
60std::unique_ptr<Input::InputDevice> TouchFromButton::Create(const Common::ParamPackage& params) { 60
61std::unique_ptr<Input::InputDevice> TouchFromButton::Create(
62 const Common::ParamPackage& params) {
61 const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); 63 const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize();
62 auto button = 64 auto button =
63 Input::CreateDeviceFromString<Input::InputDevice>(params.Get("button", null_engine)); 65 Input::CreateDeviceFromString<Input::InputDevice>(params.Get("button", null_engine));
diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h
index 86a8e00d8..8a953c382 100644
--- a/src/input_common/input_engine.h
+++ b/src/input_common/input_engine.h
@@ -114,18 +114,24 @@ public:
114 // Disable configuring mode for mapping 114 // Disable configuring mode for mapping
115 void EndConfiguration(); 115 void EndConfiguration();
116 116
117 // Sets rumble to a controller
118 virtual bool SetRumble([[maybe_unused]] const PadIdentifier& identifier,
119 [[maybe_unused]] const Input::VibrationStatus vibration) {
120 return false;
121 }
122
123 // Sets a led pattern for a controller 117 // Sets a led pattern for a controller
124 virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier, 118 virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier,
125 [[maybe_unused]] const Input::LedStatus led_status) { 119 [[maybe_unused]] const Input::LedStatus led_status) {
126 return; 120 return;
127 } 121 }
128 122
123 // Sets rumble to a controller
124 virtual Input::VibrationError SetRumble([[maybe_unused]] const PadIdentifier& identifier,
125 [[maybe_unused]] const Input::VibrationStatus vibration) {
126 return Input::VibrationError::NotSupported;
127 }
128
129 // Sets polling mode to a controller
130 virtual Input::PollingError SetPollingMode([[maybe_unused]] const PadIdentifier& identifier,
131 [[maybe_unused]] const Input::PollingMode vibration) {
132 return Input::PollingError::NotSupported;
133 }
134
129 // Returns the engine name 135 // Returns the engine name
130 [[nodiscard]] const std::string& GetEngineName() const; 136 [[nodiscard]] const std::string& GetEngineName() const;
131 137
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp
index 46a7dd276..781012886 100644
--- a/src/input_common/input_poller.cpp
+++ b/src/input_common/input_poller.cpp
@@ -592,6 +592,28 @@ private:
592 InputEngine* input_engine; 592 InputEngine* input_engine;
593}; 593};
594 594
595class OutputFromIdentifier final : public Input::OutputDevice {
596public:
597 explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_)
598 : identifier(identifier_), input_engine(input_engine_) {}
599
600 virtual void SetLED( Input::LedStatus led_status) {
601 input_engine->SetLeds(identifier, led_status);
602 }
603
604 virtual Input::VibrationError SetVibration(Input::VibrationStatus vibration_status) {
605 return input_engine->SetRumble(identifier, vibration_status);
606 }
607
608 virtual Input::PollingError SetPollingMode(Input::PollingMode polling_mode) {
609 return input_engine->SetPollingMode(identifier, polling_mode);
610 }
611
612private:
613 const PadIdentifier identifier;
614 InputEngine* input_engine;
615};
616
595std::unique_ptr<Input::InputDevice> InputFactory::CreateButtonDevice( 617std::unique_ptr<Input::InputDevice> InputFactory::CreateButtonDevice(
596 const Common::ParamPackage& params) { 618 const Common::ParamPackage& params) {
597 const PadIdentifier identifier = { 619 const PadIdentifier identifier = {
@@ -825,7 +847,8 @@ std::unique_ptr<Input::InputDevice> InputFactory::CreateMotionDevice(Common::Par
825InputFactory::InputFactory(std::shared_ptr<InputEngine> input_engine_) 847InputFactory::InputFactory(std::shared_ptr<InputEngine> input_engine_)
826 : input_engine(std::move(input_engine_)) {} 848 : input_engine(std::move(input_engine_)) {}
827 849
828std::unique_ptr<Input::InputDevice> InputFactory::Create(const Common::ParamPackage& params) { 850std::unique_ptr<Input::InputDevice> InputFactory::Create(
851 const Common::ParamPackage& params) {
829 if (params.Has("button") && params.Has("axis")) { 852 if (params.Has("button") && params.Has("axis")) {
830 return CreateTriggerDevice(params); 853 return CreateTriggerDevice(params);
831 } 854 }
@@ -857,4 +880,19 @@ std::unique_ptr<Input::InputDevice> InputFactory::Create(const Common::ParamPack
857 return std::make_unique<DummyInput>(); 880 return std::make_unique<DummyInput>();
858} 881}
859 882
883OutputFactory::OutputFactory(std::shared_ptr<InputEngine> input_engine_)
884 : input_engine(std::move(input_engine_)) {}
885
886std::unique_ptr<Input::OutputDevice> OutputFactory::Create(
887 const Common::ParamPackage& params) {
888 const PadIdentifier identifier = {
889 .guid = Common::UUID{params.Get("guid", "")},
890 .port = static_cast<std::size_t>(params.Get("port", 0)),
891 .pad = static_cast<std::size_t>(params.Get("pad", 0)),
892 };
893
894 input_engine->PreSetController(identifier);
895 return std::make_unique<OutputFromIdentifier>(identifier, input_engine.get());
896}
897
860} // namespace InputCommon 898} // namespace InputCommon
diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h
index 3c1e5b541..16cade5fa 100644
--- a/src/input_common/input_poller.h
+++ b/src/input_common/input_poller.h
@@ -16,12 +16,32 @@ class InputEngine;
16/** 16/**
17 * An Input factory. It receives input events and forward them to all input devices it created. 17 * An Input factory. It receives input events and forward them to all input devices it created.
18 */ 18 */
19
20class OutputFactory final : public Input::Factory<Input::OutputDevice> {
21public:
22 explicit OutputFactory(std::shared_ptr<InputEngine> input_engine_);
23
24 /**
25 * Creates an output device from the parameters given.
26 * @param params contains parameters for creating the device:
27 * @param - "guid": text string for identifing controllers
28 * @param - "port": port of the connected device
29 * @param - "pad": slot of the connected controller
30 * @return an unique ouput device with the parameters specified
31 */
32 std::unique_ptr<Input::OutputDevice> Create(
33 const Common::ParamPackage& params) override;
34
35private:
36 std::shared_ptr<InputEngine> input_engine;
37};
38
19class InputFactory final : public Input::Factory<Input::InputDevice> { 39class InputFactory final : public Input::Factory<Input::InputDevice> {
20public: 40public:
21 explicit InputFactory(std::shared_ptr<InputEngine> input_engine_); 41 explicit InputFactory(std::shared_ptr<InputEngine> input_engine_);
22 42
23 /** 43 /**
24 * Creates a input device from the parameters given. Identifies the type of input to be returned 44 * Creates an input device from the parameters given. Identifies the type of input to be returned
25 * if it contains the following parameters: 45 * if it contains the following parameters:
26 * - button: Contains "button" or "code" 46 * - button: Contains "button" or "code"
27 * - hat_button: Contains "hat" 47 * - hat_button: Contains "hat"
@@ -32,6 +52,7 @@ public:
32 * - motion: Contains "motion" 52 * - motion: Contains "motion"
33 * - touch: Contains "button", "axis_x" and "axis_y" 53 * - touch: Contains "button", "axis_x" and "axis_y"
34 * - battery: Contains "battery" 54 * - battery: Contains "battery"
55 * - output: Contains "output"
35 * @param params contains parameters for creating the device: 56 * @param params contains parameters for creating the device:
36 * @param - "code": the code of the keyboard key to bind with the input 57 * @param - "code": the code of the keyboard key to bind with the input
37 * @param - "button": same as "code" but for controller buttons 58 * @param - "button": same as "code" but for controller buttons
@@ -41,10 +62,11 @@ public:
41 * @param - "axis_x": same as axis but specifing horizontal direction 62 * @param - "axis_x": same as axis but specifing horizontal direction
42 * @param - "axis_y": same as axis but specifing vertical direction 63 * @param - "axis_y": same as axis but specifing vertical direction
43 * @param - "axis_z": same as axis but specifing forward direction 64 * @param - "axis_z": same as axis but specifing forward direction
44 * @param - "battery": Only used as a placeholder to set the input type 65 * @param - "battery": Only used as a placeholder to set the input type
45 * @return an unique input device with the parameters specified 66 * @return an unique input device with the parameters specified
46 */ 67 */
47 std::unique_ptr<Input::InputDevice> Create(const Common::ParamPackage& params) override; 68 std::unique_ptr<Input::InputDevice> Create(
69 const Common::ParamPackage& params) override;
48 70
49private: 71private:
50 /** 72 /**
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 46ca6b76c..b7fe9cb37 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -46,8 +46,10 @@ struct InputSubsystem::Impl {
46 46
47 gcadapter = std::make_shared<GCAdapter>("gcpad"); 47 gcadapter = std::make_shared<GCAdapter>("gcpad");
48 gcadapter->SetMappingCallback(mapping_callback); 48 gcadapter->SetMappingCallback(mapping_callback);
49 gcadapter_factory = std::make_shared<InputFactory>(gcadapter); 49 gcadapter_input_factory = std::make_shared<InputFactory>(gcadapter);
50 Input::RegisterFactory<Input::InputDevice>(gcadapter->GetEngineName(), gcadapter_factory); 50 gcadapter_output_factory = std::make_shared<OutputFactory>(gcadapter);
51 Input::RegisterFactory<Input::InputDevice>(gcadapter->GetEngineName(), gcadapter_input_factory);
52 Input::RegisterFactory<Input::OutputDevice>(gcadapter->GetEngineName(), gcadapter_output_factory);
51 53
52 udp_client = std::make_shared<CemuhookUDP::UDPClient>("cemuhookudp"); 54 udp_client = std::make_shared<CemuhookUDP::UDPClient>("cemuhookudp");
53 udp_client->SetMappingCallback(mapping_callback); 55 udp_client->SetMappingCallback(mapping_callback);
@@ -62,8 +64,10 @@ struct InputSubsystem::Impl {
62#ifdef HAVE_SDL2 64#ifdef HAVE_SDL2
63 sdl = std::make_shared<SDLDriver>("sdl"); 65 sdl = std::make_shared<SDLDriver>("sdl");
64 sdl->SetMappingCallback(mapping_callback); 66 sdl->SetMappingCallback(mapping_callback);
65 sdl_factory = std::make_shared<InputFactory>(sdl); 67 sdl_input_factory = std::make_shared<InputFactory>(sdl);
66 Input::RegisterFactory<Input::InputDevice>(sdl->GetEngineName(), sdl_factory); 68 sdl_output_factory = std::make_shared<OutputFactory>(sdl);
69 Input::RegisterFactory<Input::InputDevice>(sdl->GetEngineName(), sdl_input_factory);
70 Input::RegisterFactory<Input::OutputDevice>(sdl->GetEngineName(), sdl_output_factory);
67#endif 71#endif
68 72
69 Input::RegisterFactory<Input::InputDevice>("touch_from_button", 73 Input::RegisterFactory<Input::InputDevice>("touch_from_button",
@@ -247,21 +251,27 @@ struct InputSubsystem::Impl {
247 } 251 }
248 252
249 std::shared_ptr<MappingFactory> mapping_factory; 253 std::shared_ptr<MappingFactory> mapping_factory;
254
250 std::shared_ptr<Keyboard> keyboard; 255 std::shared_ptr<Keyboard> keyboard;
251 std::shared_ptr<InputFactory> keyboard_factory;
252 std::shared_ptr<Mouse> mouse; 256 std::shared_ptr<Mouse> mouse;
253 std::shared_ptr<InputFactory> mouse_factory;
254 std::shared_ptr<GCAdapter> gcadapter; 257 std::shared_ptr<GCAdapter> gcadapter;
255 std::shared_ptr<InputFactory> gcadapter_factory;
256 std::shared_ptr<TouchScreen> touch_screen; 258 std::shared_ptr<TouchScreen> touch_screen;
257 std::shared_ptr<InputFactory> touch_screen_factory; 259 std::shared_ptr<TasInput::Tas> tas_input;
258 std::shared_ptr<CemuhookUDP::UDPClient> udp_client; 260 std::shared_ptr<CemuhookUDP::UDPClient> udp_client;
261
262 std::shared_ptr<InputFactory> keyboard_factory;
263 std::shared_ptr<InputFactory> mouse_factory;
264 std::shared_ptr<InputFactory> gcadapter_input_factory;
265 std::shared_ptr<InputFactory> touch_screen_factory;
259 std::shared_ptr<InputFactory> udp_client_factory; 266 std::shared_ptr<InputFactory> udp_client_factory;
260 std::shared_ptr<TasInput::Tas> tas_input;
261 std::shared_ptr<InputFactory> tas_input_factory; 267 std::shared_ptr<InputFactory> tas_input_factory;
268
269 std::shared_ptr<OutputFactory> gcadapter_output_factory;
270
262#ifdef HAVE_SDL2 271#ifdef HAVE_SDL2
263 std::shared_ptr<SDLDriver> sdl; 272 std::shared_ptr<SDLDriver> sdl;
264 std::shared_ptr<InputFactory> sdl_factory; 273 std::shared_ptr<InputFactory> sdl_input_factory;
274 std::shared_ptr<OutputFactory> sdl_output_factory;
265#endif 275#endif
266}; 276};
267 277
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index adc9706f1..ed9c3facf 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -465,6 +465,8 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
465 UpdateControllerEnabledButtons(); 465 UpdateControllerEnabledButtons();
466 UpdateControllerButtonNames(); 466 UpdateControllerButtonNames();
467 UpdateMotionButtons(); 467 UpdateMotionButtons();
468 emulated_controller->SetNpadType(
469 GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()));
468 }); 470 });
469 471
470 connect(ui->comboDevices, qOverload<int>(&QComboBox::activated), this, 472 connect(ui->comboDevices, qOverload<int>(&QComboBox::activated), this,
@@ -540,6 +542,11 @@ void ConfigureInputPlayer::LoadConfiguration() {
540 542
541void ConfigureInputPlayer::ConnectPlayer(bool connected) { 543void ConfigureInputPlayer::ConnectPlayer(bool connected) {
542 ui->groupConnectedController->setChecked(connected); 544 ui->groupConnectedController->setChecked(connected);
545 if (connected) {
546 emulated_controller->Connect();
547 } else {
548 emulated_controller->Disconnect();
549 }
543} 550}
544 551
545void ConfigureInputPlayer::UpdateInputDeviceCombobox() { 552void ConfigureInputPlayer::UpdateInputDeviceCombobox() {
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index 03d29f194..2ba9d7290 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -24,34 +24,6 @@ PlayerControlPreview::~PlayerControlPreview() {
24 } 24 }
25}; 25};
26 26
27PlayerControlPreview::LedPattern PlayerControlPreview::GetColorPattern(std::size_t index,
28 bool player_on) {
29 if (!player_on) {
30 return {0, 0, 0, 0};
31 }
32
33 switch (index) {
34 case 0:
35 return {1, 0, 0, 0};
36 case 1:
37 return {1, 1, 0, 0};
38 case 2:
39 return {1, 1, 1, 0};
40 case 3:
41 return {1, 1, 1, 1};
42 case 4:
43 return {1, 0, 0, 1};
44 case 5:
45 return {1, 0, 1, 0};
46 case 6:
47 return {1, 0, 1, 1};
48 case 7:
49 return {0, 1, 1, 0};
50 default:
51 return {0, 0, 0, 0};
52 }
53}
54
55void PlayerControlPreview::SetController(Core::HID::EmulatedController* controller_) { 27void PlayerControlPreview::SetController(Core::HID::EmulatedController* controller_) {
56 if (is_controller_set) { 28 if (is_controller_set) {
57 controller->DeleteCallback(callback_key); 29 controller->DeleteCallback(callback_key);
@@ -160,8 +132,13 @@ void PlayerControlPreview::ControllerUpdate(Core::HID::ControllerTriggerType typ
160 132
161 switch (type) { 133 switch (type) {
162 case Core::HID::ControllerTriggerType::Connected: 134 case Core::HID::ControllerTriggerType::Connected:
135 is_connected = true;
136 led_pattern = controller->GetLedPattern();
137 needs_redraw = true;
138 break;
163 case Core::HID::ControllerTriggerType::Disconnected: 139 case Core::HID::ControllerTriggerType::Disconnected:
164 is_connected = controller->IsConnected(); 140 is_connected = false;
141 led_pattern.raw = 0;
165 needs_redraw = true; 142 needs_redraw = true;
166 break; 143 break;
167 case Core::HID::ControllerTriggerType::Type: 144 case Core::HID::ControllerTriggerType::Type:
@@ -1853,10 +1830,14 @@ void PlayerControlPreview::DrawLeftBody(QPainter& p, const QPointF center) {
1853 const float led_size = 5.0f; 1830 const float led_size = 5.0f;
1854 const QPointF led_position = sideview_center + QPointF(0, -36); 1831 const QPointF led_position = sideview_center + QPointF(0, -36);
1855 int led_count = 0; 1832 int led_count = 0;
1856 for (const auto& color : led_color) { 1833 p.setBrush(led_pattern.position1 ? colors.led_on : colors.led_off);
1857 p.setBrush(color); 1834 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size);
1858 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); 1835 p.setBrush(led_pattern.position2 ? colors.led_on : colors.led_off);
1859 } 1836 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size);
1837 p.setBrush(led_pattern.position3 ? colors.led_on : colors.led_off);
1838 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size);
1839 p.setBrush(led_pattern.position4 ? colors.led_on : colors.led_off);
1840 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size);
1860} 1841}
1861 1842
1862void PlayerControlPreview::DrawRightBody(QPainter& p, const QPointF center) { 1843void PlayerControlPreview::DrawRightBody(QPainter& p, const QPointF center) {
@@ -1949,10 +1930,14 @@ void PlayerControlPreview::DrawRightBody(QPainter& p, const QPointF center) {
1949 const float led_size = 5.0f; 1930 const float led_size = 5.0f;
1950 const QPointF led_position = sideview_center + QPointF(0, -36); 1931 const QPointF led_position = sideview_center + QPointF(0, -36);
1951 int led_count = 0; 1932 int led_count = 0;
1952 for (const auto& color : led_color) { 1933 p.setBrush(led_pattern.position1 ? colors.led_on : colors.led_off);
1953 p.setBrush(color); 1934 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size);
1954 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); 1935 p.setBrush(led_pattern.position2 ? colors.led_on : colors.led_off);
1955 } 1936 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size);
1937 p.setBrush(led_pattern.position3 ? colors.led_on : colors.led_off);
1938 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size);
1939 p.setBrush(led_pattern.position4 ? colors.led_on : colors.led_off);
1940 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size);
1956} 1941}
1957 1942
1958void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, 1943void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center,
diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h
index b44a2e347..16f9748f5 100644
--- a/src/yuzu/configuration/configure_input_player_widget.h
+++ b/src/yuzu/configuration/configure_input_player_widget.h
@@ -59,13 +59,6 @@ private:
59 SR, 59 SR,
60 }; 60 };
61 61
62 struct LedPattern {
63 bool position1;
64 bool position2;
65 bool position3;
66 bool position4;
67 };
68
69 struct ColorMapping { 62 struct ColorMapping {
70 QColor outline{}; 63 QColor outline{};
71 QColor primary{}; 64 QColor primary{};
@@ -88,7 +81,6 @@ private:
88 QColor deadzone{}; 81 QColor deadzone{};
89 }; 82 };
90 83
91 static LedPattern GetColorPattern(std::size_t index, bool player_on);
92 void UpdateColors(); 84 void UpdateColors();
93 void ResetInputs(); 85 void ResetInputs();
94 86
@@ -194,7 +186,7 @@ private:
194 int callback_key; 186 int callback_key;
195 QColor button_color{}; 187 QColor button_color{};
196 ColorMapping colors{}; 188 ColorMapping colors{};
197 std::array<QColor, 4> led_color{}; 189 Core::HID::LedPattern led_pattern{0, 0, 0, 0};
198 std::size_t player_index{}; 190 std::size_t player_index{};
199 Core::HID::EmulatedController* controller; 191 Core::HID::EmulatedController* controller;
200 std::size_t button_mapping_index{Settings::NativeButton::NumButtons}; 192 std::size_t button_mapping_index{Settings::NativeButton::NumButtons};