overlay: fixes for naive binding (#542)

## Description of change
Three bugs:

* Some keys are IME-dependent. Right Alt can be IME mode switch for
Japanese / Korean, and Right Ctrl is often the Kanji button.
* If you press modifiers like Ctrl during bind-many-naive, it will skip
over a button, because of broken for loop logic that ends up calling
`inc_buttons_many_index` too many times
* trying to cancel out of bind-many-naive with left and right mouse
buttons swap doesn't work

## Testing
Validating various IME. I don't have a keyboard in another language
though..
This commit is contained in:
bicarus
2026-01-30 13:16:14 -08:00
committed by GitHub
parent 7a6cadb176
commit 3ad88ef15c
2 changed files with 64 additions and 28 deletions
+42 -26
View File
@@ -1216,6 +1216,8 @@ namespace overlay::windows {
} else {
// get new keyboard state
// these are async, and some keys generate multiple vKeys (e.g., VK_SHIFT, VK_LSHIFT)
// use care when iterating over the result (could result in torn reads)
bool keyboard_state_new[sizeof(buttons_keyboard_state)];
for (size_t i = 0; i < sizeof(keyboard_state_new); i++) {
keyboard_state_new[i] = GetAsyncKeyState(i) != 0;
@@ -1225,33 +1227,47 @@ namespace overlay::windows {
for (unsigned short int vKey = 0x01; vKey < sizeof(buttons_keyboard_state); vKey++) {
// ignore num lock escape sequence
if (vKey != VK_NUMLOCK) {
// check for key press
if (keyboard_state_new[vKey] && !buttons_keyboard_state[vKey]) {
// ignore escape
if ((!escape_cancels_bind || vKey != VK_ESCAPE) &&
(vKey != VK_LBUTTON || !ImGui::IsItemHovered())) {
// bind key
button->setDeviceIdentifier("");
button->setVKey(vKey);
button->setDebounceUp(0.0);
button->setDebounceDown(0.0);
button->setVelocityThreshold(0);
::Config::getInstance().updateBinding(
games_list[games_selected], *button,
buttons_page - 1);
inc_buttons_many_index(button_it_max);
} else {
buttons_many_index = -1;
}
buttons_bind_active = false;
ImGui::CloseCurrentPopup();
}
if (vKey == VK_NUMLOCK) {
continue;
}
// prefer VK_LSHIFT/VK_RSHIFT, VK_LCONTROL/VK_RCONTROL, VK_LMENU/VK_RMENU
if (vKey == VK_SHIFT || vKey == VK_CONTROL || vKey == VK_MENU) {
continue;
}
// check if key is newly pressed
if (!(keyboard_state_new[vKey] && !buttons_keyboard_state[vKey])) {
continue;
}
// don't bother checking GetSystemMetrics(SM_SWAPBUTTON), just check both
const bool is_mouse_pressed = (vKey == VK_LBUTTON || vKey == VK_RBUTTON);
// some key is newly pressed; process it here, which will result in a new bind
// or a cancellation
if (escape_cancels_bind && vKey == VK_ESCAPE) {
// escape cancels out
buttons_many_index = -1;
} else if (is_mouse_pressed && ImGui::IsItemHovered()) {
// left or right mouse click on top of cancel button
buttons_many_index = -1;
} else {
// bind key
button->setDeviceIdentifier("");
button->setVKey(vKey);
button->setDebounceUp(0.0);
button->setDebounceDown(0.0);
button->setVelocityThreshold(0);
::Config::getInstance().updateBinding(
games_list[games_selected], *button,
buttons_page - 1);
inc_buttons_many_index(button_it_max);
}
buttons_bind_active = false;
ImGui::CloseCurrentPopup();
break;
}
// clean up