xinput: bind UI, vibration, hotplug (#620)

## Link to GitHub Issue or related Pull Request, if one exists
#616 

## Description of change
`Naive` button is now called `Naive/XInput` and detects XInput
controllers

Add vibration output as "Lights"

Add proper hotplug support and multiple controllers

Fix misc bugs on x86

## Testing
I tested with two xbox controllers.
This commit is contained in:
bicarus
2026-04-10 01:04:20 -07:00
committed by GitHub
parent ca70f7b19c
commit a159691097
11 changed files with 275 additions and 68 deletions
+43 -8
View File
@@ -673,7 +673,7 @@ namespace overlay::windows {
// longest column is probably "Toggle Virtual Keypad P1" in Overlay tab
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(220));
ImGui::TableSetupColumn("Binding", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(140));
ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(170));
// check if empty
if (!buttons || buttons->empty()) {
@@ -913,8 +913,8 @@ namespace overlay::windows {
// naive binding
ImGui::SameLine();
std::string naive_string = "Naive " + button_name;
if (ImGui::Button("Naive")
std::string naive_string = "Naive/XInput " + button_name;
if (ImGui::Button("Naive/XInput")
|| (buttons_many_active && buttons_many_active_section == name && !buttons_bind_active
&& alt_index == 0
&& buttons_many_naive && buttons_many_index == button_it
@@ -934,11 +934,12 @@ namespace overlay::windows {
}
if (ImGui::IsItemHovered(ImGui::TOOLTIP_FLAGS)) {
ImGui::HelpTooltip(
"Uses GetAsyncKeyState to check for any keyboard / mouse input. "
"For best performance, Bind should be preferred, but this can be used when:\n"
" * you don't care about which device is used\n"
"Alternative to Bind, using GetAsyncKeyState for KB/Mouse and XInput for controllers.\n\n"
"This can be used when:\n"
" * you want to use XInput for gamepads (for analog triggers)\n"
" * you don't care about which keyboard/mouse is used\n"
" * you want to use input remapping or automation software\n"
" * if you have NKRO issues with Bind");
" * you have NKRO issues with Bind");
}
naive_button_popup(naive_string, button, button_it_max, alt_index);
@@ -998,7 +999,7 @@ namespace overlay::windows {
}
// Naive Many
if (ImGui::MenuItem("Naive (many)")) {
if (ImGui::MenuItem("Naive/XInput (many)")) {
buttons_many_active = true;
buttons_many_index = button_it;
buttons_many_naive = true;
@@ -1555,6 +1556,22 @@ namespace overlay::windows {
}
}
// check xinput
if (check_devices) {
xinput::XINPUT_NEW_BUTTON xinput;
if (RI_MGR->XINPUT_MGR->get_any_button_pressed(xinput)) {
button->setDeviceIdentifier(xinput::get_device_desc(xinput.player));
button->setVKey(static_cast<uint16_t>(xinput.button));
::Config::getInstance().updateBinding(
games_list[games_selected], *button, alt_index - 1);
inc_buttons_many_index(button_it_max);
buttons_bind_active = false;
ImGui::CloseCurrentPopup();
check_devices = false;
}
}
// check GetAsyncKeyState
if (check_devices) {
// get new keyboard state
// these are async, and some keys generate multiple vKeys (e.g., VK_SHIFT, VK_LSHIFT)
@@ -2747,6 +2764,7 @@ namespace overlay::windows {
case rawinput::PIUIO_DEVICE:
case rawinput::SMX_STAGE:
case rawinput::SMX_DEDICAB:
case rawinput::XINPUT_GAMEPAD:
this->auto_match_devices.emplace_back(&device);
break;
default:
@@ -2913,6 +2931,7 @@ namespace overlay::windows {
case rawinput::PIUIO_DEVICE:
case rawinput::SMX_STAGE:
case rawinput::SMX_DEDICAB:
case rawinput::XINPUT_GAMEPAD:
this->lights_devices.emplace_back(&device);
break;
default:
@@ -3066,6 +3085,15 @@ namespace overlay::windows {
}
break;
}
case rawinput::XINPUT_GAMEPAD: {
// add all names of XInput gamepad device
for (int i = 0; i < static_cast<int>(xinput::XInputOutputEnum::COUNT); i++) {
control_names.emplace_back(
xinput::get_output_string(static_cast<xinput::XInputOutputEnum>(i)));
}
break;
}
default:
break;
}
@@ -3611,6 +3639,13 @@ namespace overlay::windows {
}
break;
}
case rawinput::XINPUT_GAMEPAD: {
for (int i = 0; i < static_cast<int>(xinput::XInputOutputEnum::COUNT); i++) {
raw_names.emplace_back(
xinput::get_output_string(static_cast<xinput::XInputOutputEnum>(i)));
}
break;
}
default:
break;
}