@@ -67,6 +67,19 @@ static constexpr std::array<u16, XInputSource::NUM_BUTTONS> s_button_masks = {{
6767 XINPUT_GAMEPAD_Y,
6868 0x400 , // XINPUT_GAMEPAD_GUIDE
6969}};
70+
71+ static constexpr const std::array s_scp_axis_fields = {
72+ &SCP_EXTN::SCP_LX, &SCP_EXTN::SCP_LY, &SCP_EXTN::SCP_RX, &SCP_EXTN::SCP_RY, &SCP_EXTN::SCP_L2, &SCP_EXTN::SCP_R2,
73+ };
74+ static_assert (std::size(s_scp_axis_fields) == XInputSource::NUM_AXES);
75+
76+ static constexpr const std::array s_scp_button_fields = {
77+ &SCP_EXTN::SCP_UP, &SCP_EXTN::SCP_DOWN, &SCP_EXTN::SCP_LEFT, &SCP_EXTN::SCP_RIGHT, &SCP_EXTN::SCP_START,
78+ &SCP_EXTN::SCP_SELECT, &SCP_EXTN::SCP_L3, &SCP_EXTN::SCP_R3, &SCP_EXTN::SCP_L1, &SCP_EXTN::SCP_R1,
79+ &SCP_EXTN::SCP_X, &SCP_EXTN::SCP_C, &SCP_EXTN::SCP_S, &SCP_EXTN::SCP_T, &SCP_EXTN::SCP_PS,
80+ };
81+ static_assert (std::size(s_scp_button_fields) == XInputSource::NUM_BUTTONS);
82+
7083static constexpr std::array<const char *, XInputSource::NUM_BUTTONS> s_button_icons = {{
7184 ICON_PF_XBOX_DPAD_UP, // XINPUT_GAMEPAD_DPAD_UP
7285 ICON_PF_XBOX_DPAD_DOWN, // XINPUT_GAMEPAD_DPAD_DOWN
@@ -144,6 +157,14 @@ bool XInputSource::Initialize(const SettingsInterface& si, std::unique_lock<std:
144157 return false ;
145158 }
146159
160+ // Only present with SCP extension (DSHidMini)
161+ m_xinput_get_extended =
162+ reinterpret_cast <decltype (m_xinput_get_extended)>(GetProcAddress (m_xinput_module, " XInputGetExtended" ));
163+ if (m_xinput_get_extended)
164+ INFO_COLOR_LOG (StrongGreen, " XInputGetExtended() is available, SCP extension features enabled." );
165+ else
166+ INFO_COLOR_LOG (StrongOrange, " XInputGetExtended() is not available, SCP extension features disabled." );
167+
147168 ReloadDevices ();
148169 return true ;
149170}
@@ -152,14 +173,26 @@ void XInputSource::UpdateSettings(const SettingsInterface& si, std::unique_lock<
152173{
153174}
154175
176+ bool XInputSource::UseSCPExtn () const
177+ {
178+ return (m_xinput_get_extended != nullptr );
179+ }
180+
181+ DWORD XInputSource::GetControllerState (u32 index, ControllerState* state)
182+ {
183+ if (UseSCPExtn ())
184+ return m_xinput_get_extended (index, &state->scp_extn );
185+ else
186+ return m_xinput_get_state (index, &state->xinput );
187+ }
188+
155189bool XInputSource::ReloadDevices ()
156190{
157191 bool changed = false ;
158192 for (u32 i = 0 ; i < NUM_CONTROLLERS; i++)
159193 {
160- XINPUT_STATE new_state;
161- DWORD result = m_xinput_get_state (i, &new_state);
162-
194+ ControllerState new_state;
195+ const DWORD result = GetControllerState (i, &new_state);
163196 if (result == ERROR_SUCCESS)
164197 {
165198 if (m_controllers[i].connected )
@@ -198,6 +231,7 @@ void XInputSource::Shutdown()
198231 m_xinput_get_state = nullptr ;
199232 m_xinput_set_state = nullptr ;
200233 m_xinput_get_capabilities = nullptr ;
234+ m_xinput_get_extended = nullptr ;
201235}
202236
203237void XInputSource::PollEvents ()
@@ -208,9 +242,8 @@ void XInputSource::PollEvents()
208242 if (!was_connected)
209243 continue ;
210244
211- XINPUT_STATE new_state;
212- DWORD result = m_xinput_get_state (i, &new_state);
213-
245+ ControllerState new_state;
246+ const DWORD result = GetControllerState (i, &new_state);
214247 if (result == ERROR_SUCCESS)
215248 {
216249 if (!was_connected)
@@ -457,7 +490,7 @@ bool XInputSource::GetGenericBindingMapping(std::string_view device, GenericInpu
457490 return true ;
458491}
459492
460- void XInputSource::HandleControllerConnection (u32 index, const XINPUT_STATE & state)
493+ void XInputSource::HandleControllerConnection (u32 index, const ControllerState & state)
461494{
462495 INFO_LOG (" XInput controller {} connected." , index);
463496
@@ -485,14 +518,16 @@ void XInputSource::HandleControllerDisconnection(u32 index)
485518 GetDeviceIdentifier (index));
486519}
487520
488- void XInputSource::CheckForStateChanges (u32 index, const XINPUT_STATE & new_state)
521+ void XInputSource::CheckForStateChanges (u32 index, const ControllerState & new_state)
489522{
490523 ControllerData& cd = m_controllers[index];
491- if (new_state.dwPacketNumber == cd.last_state .dwPacketNumber )
492- return ;
524+ if (!UseSCPExtn ())
525+ {
526+ if (new_state.xinput .dwPacketNumber == cd.last_state .xinput .dwPacketNumber )
527+ return ;
493528
494- XINPUT_GAMEPAD& ogp = cd.last_state .Gamepad ;
495- const XINPUT_GAMEPAD& ngp = new_state.Gamepad ;
529+ XINPUT_GAMEPAD& ogp = cd.last_state . xinput .Gamepad ;
530+ const XINPUT_GAMEPAD& ngp = new_state. xinput .Gamepad ;
496531
497532#define CHECK_AXIS (field, axis, min_value, max_value ) \
498533 if (ogp.field != ngp.field ) \
@@ -502,28 +537,57 @@ void XInputSource::CheckForStateChanges(u32 index, const XINPUT_STATE& new_state
502537 s_xinput_generic_binding_axis_mapping[axis][BoolToUInt8 (ngp.field >= 0 )]); \
503538 }
504539
505- // Y axes is inverted in XInput when compared to SDL.
506- CHECK_AXIS (sThumbLX , AXIS_LEFTX, 32768 , 32767 );
507- CHECK_AXIS (sThumbLY , AXIS_LEFTY, -32768 , -32767 );
508- CHECK_AXIS (sThumbRX , AXIS_RIGHTX, 32768 , 32767 );
509- CHECK_AXIS (sThumbRY , AXIS_RIGHTY, -32768 , -32767 );
510- CHECK_AXIS (bLeftTrigger, AXIS_LEFTTRIGGER, 0 , 255 );
511- CHECK_AXIS (bRightTrigger, AXIS_RIGHTTRIGGER, 0 , 255 );
540+ // Y axes is inverted in XInput when compared to SDL.
541+ CHECK_AXIS (sThumbLX , AXIS_LEFTX, 32768 , 32767 );
542+ CHECK_AXIS (sThumbLY , AXIS_LEFTY, -32768 , -32767 );
543+ CHECK_AXIS (sThumbRX , AXIS_RIGHTX, 32768 , 32767 );
544+ CHECK_AXIS (sThumbRY , AXIS_RIGHTY, -32768 , -32767 );
545+ CHECK_AXIS (bLeftTrigger, AXIS_LEFTTRIGGER, 0 , 255 );
546+ CHECK_AXIS (bRightTrigger, AXIS_RIGHTTRIGGER, 0 , 255 );
512547
513548#undef CHECK_AXIS
514549
515- const u16 old_button_bits = ogp.wButtons ;
516- const u16 new_button_bits = ngp.wButtons ;
517- if (old_button_bits != new_button_bits)
550+ const u16 old_button_bits = ogp.wButtons ;
551+ const u16 new_button_bits = ngp.wButtons ;
552+ if (old_button_bits != new_button_bits)
553+ {
554+ for (u32 button = 0 ; button < NUM_BUTTONS; button++)
555+ {
556+ const u16 button_mask = s_button_masks[button];
557+ if ((old_button_bits & button_mask) != (new_button_bits & button_mask))
558+ {
559+ const GenericInputBinding generic_key = s_xinput_generic_binding_button_mapping[button];
560+ const float value = ((new_button_bits & button_mask) != 0 ) ? 1 .0f : 0 .0f ;
561+ InputManager::InvokeEvents (MakeGenericControllerButtonKey (InputSourceType::XInput, index, button), value,
562+ generic_key);
563+ }
564+ }
565+ }
566+ }
567+ else
518568 {
519- for (u32 button = 0 ; button < NUM_BUTTONS; button++)
569+ for (u32 i = 0 ; i < NUM_AXES; i++)
570+ {
571+ const float old_value = (cd.last_state .scp_extn .*s_scp_axis_fields[i]);
572+ const float new_value = (new_state.scp_extn .*s_scp_axis_fields[i]);
573+ if (old_value != new_value)
574+ {
575+ // Y axes is inverted in XInput when compared to SDL.
576+ const bool invert = (i == AXIS_LEFTY || i == AXIS_RIGHTY);
577+ InputManager::InvokeEvents (MakeGenericControllerAxisKey (InputSourceType::XInput, index, i),
578+ invert ? (new_value * -1 .0f ) : new_value,
579+ s_xinput_generic_binding_axis_mapping[i][BoolToUInt8 (new_value >= 0 )]);
580+ }
581+ }
582+
583+ for (u32 i = 0 ; i < NUM_BUTTONS; i++)
520584 {
521- const u16 button_mask = s_button_masks[button];
522- if ((old_button_bits & button_mask) != (new_button_bits & button_mask))
585+ const float old_value = (cd.last_state .scp_extn .*s_scp_button_fields[i]);
586+ const float new_value = (new_state.scp_extn .*s_scp_button_fields[i]);
587+ if (old_value != new_value)
523588 {
524- const GenericInputBinding generic_key = s_xinput_generic_binding_button_mapping[button];
525- const float value = ((new_button_bits & button_mask) != 0 ) ? 1 .0f : 0 .0f ;
526- InputManager::InvokeEvents (MakeGenericControllerButtonKey (InputSourceType::XInput, index, button), value,
589+ const GenericInputBinding generic_key = s_xinput_generic_binding_button_mapping[i];
590+ InputManager::InvokeEvents (MakeGenericControllerButtonKey (InputSourceType::XInput, index, i), new_value,
527591 generic_key);
528592 }
529593 }
@@ -544,28 +608,45 @@ std::optional<float> XInputSource::GetCurrentValue(InputBindingKey key)
544608
545609 if (key.source_subtype == InputSubclass::ControllerAxis && key.data < NUM_AXES)
546610 {
547- const XINPUT_GAMEPAD& state = cd.last_state .Gamepad ;
611+ if (!UseSCPExtn ())
612+ {
613+ const XINPUT_GAMEPAD& state = cd.last_state .xinput .Gamepad ;
548614#define CHECK_AXIS (field, axis, min_value, max_value ) \
549615 case axis: \
550616 ret = static_cast <float >(state.field ) / ((state.field < 0 ) ? min_value : max_value); \
551617 break ;
552618
553- // Y axes is inverted in XInput when compared to SDL.
554- switch (key.data )
619+ // Y axes is inverted in XInput when compared to SDL.
620+ switch (key.data )
621+ {
622+ CHECK_AXIS (sThumbLX , AXIS_LEFTX, 32768 , 32767 );
623+ CHECK_AXIS (sThumbLY , AXIS_LEFTY, -32768 , -32767 );
624+ CHECK_AXIS (sThumbRX , AXIS_RIGHTX, 32768 , 32767 );
625+ CHECK_AXIS (sThumbRY , AXIS_RIGHTY, -32768 , -32767 );
626+ CHECK_AXIS (bLeftTrigger, AXIS_LEFTTRIGGER, 0 , 255 );
627+ CHECK_AXIS (bRightTrigger, AXIS_RIGHTTRIGGER, 0 , 255 );
628+ }
629+ }
630+ else
555631 {
556- CHECK_AXIS (sThumbLX , AXIS_LEFTX, 32768 , 32767 );
557- CHECK_AXIS (sThumbLY , AXIS_LEFTY, -32768 , -32767 );
558- CHECK_AXIS (sThumbRX , AXIS_RIGHTX, 32768 , 32767 );
559- CHECK_AXIS (sThumbRY , AXIS_RIGHTY, -32768 , -32767 );
560- CHECK_AXIS (bLeftTrigger, AXIS_LEFTTRIGGER, 0 , 255 );
561- CHECK_AXIS (bRightTrigger, AXIS_RIGHTTRIGGER, 0 , 255 );
632+ const float value = (cd.last_state .scp_extn .*s_scp_axis_fields[key.data ]);
633+
634+ // Y axes is inverted in XInput when compared to SDL.
635+ ret = ((key.data == AXIS_LEFTY || key.data == AXIS_RIGHTY) ? (value * -1 .0f ) : value);
562636 }
563637 }
564638 else if (key.source_subtype == InputSubclass::ControllerButton && key.data < NUM_BUTTONS)
565639 {
566- const XINPUT_GAMEPAD& state = cd.last_state .Gamepad ;
567- const u16 button_mask = s_button_masks[key.data ];
568- ret = BoolToFloat ((state.wButtons & button_mask) != 0 );
640+ if (!UseSCPExtn ())
641+ {
642+ const XINPUT_GAMEPAD& state = cd.last_state .xinput .Gamepad ;
643+ const u16 button_mask = s_button_masks[key.data ];
644+ ret = BoolToFloat ((state.wButtons & button_mask) != 0 );
645+ }
646+ else
647+ {
648+ ret = (cd.last_state .scp_extn .*s_scp_button_fields[key.data ]);
649+ }
569650 }
570651
571652 return ret;
0 commit comments