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
+22 -2
View File
@@ -58,8 +58,28 @@ std::string Button::getVKeyString() {
return "Pause";
case 0x14:
return "Caps Lock";
case 0x15:
return "IME Kana/Hangul";
case 0x16:
return "IME On";
case 0x17:
return "IME Junja";
case 0x18:
return "IME Final";
case 0x19:
return "IME Hanja/Kanji";
case 0x1A:
return "IME Off";
case 0x1B:
return "Escape";
case 0x1C:
return "IME Convert";
case 0x1D:
return "IME Nonconvert";
case 0x1E:
return "IME Accept";
case 0x1F:
return "IME Mode Change";
case 0x20:
return "Space";
case 0x21:
@@ -255,9 +275,9 @@ std::string Button::getVKeyString() {
case 0xA3:
return "Right Control";
case 0xA4:
return "Left Menu";
return "Left Alt";
case 0xA5:
return "Right Menu";
return "Right Alt";
default:
// check win API
+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