Fix Right Alt key not working in keybindings on Windows (#40536)

### Problem
On Windows, the right Alt key was not working in keybindings (e.g.,
`Ctrl+Right Alt+B`), while the left Alt key worked correctly. This was
due to overly aggressive AltGr detection that treated any `right Alt +
left Ctrl` combination as AltGr, even on US keyboards where AltGr
doesn't exist.

### Root Cause
Windows internally represents AltGr (Alt Graph) as `right Alt + left
Ctrl` pressed simultaneously. The previous implementation always
excluded this combination from being treated as regular modifier keys to
support international keyboards. However, this broke keybindings using
right Alt on US/UK keyboards where users expect right Alt to behave
identically to left Alt.

### Solution
Implemented keyboard layout-aware AltGr detection:

1. Added `uses_altgr()` method to `WindowsKeyboardLayout` that checks if
the current keyboard layout is known to use AltGr (German, French,
Spanish, Polish, etc.)
2. Modified `current_modifiers()` to only apply AltGr special handling
when the keyboard layout actually uses it
3. Added explicit checking for both `VK_LMENU` and `VK_RMENU` instead of
relying solely on the generic `VK_MENU`

### Behavior
- **US/UK keyboards**: Right Alt now works identically to left Alt in
keybindings. `Ctrl+Right Alt+B` triggers the same action as `Ctrl+Left
Alt+B`
- **International keyboards** (German, French, Spanish, etc.): AltGr
continues to work correctly for typing special characters and doesn't
trigger keybindings
- **All keyboards**: Both Alt keys are detected symmetrically, matching
the behavior of left/right Windows keys

### Testing
Manually tested on Windows with US keyboard layout:
-  `Ctrl+Left Alt+B` triggers keybinding
-  `Ctrl+Right Alt+B` triggers keybinding  
-  Both Alt keys work independently in keybindings


Release Notes:
- Fixed Right Alt key not working in keybindings on Windows
This commit is contained in:
joel
2025-10-18 02:27:45 +02:00
committed by GitHub
parent 47c6ae7b1f
commit 3d6722be9a
2 changed files with 48 additions and 4 deletions
+16 -4
View File
@@ -1307,10 +1307,10 @@ where
F: FnOnce(Keystroke) -> PlatformInput,
{
let virtual_key = VIRTUAL_KEY(wparam.loword());
let mut modifiers = current_modifiers();
let modifiers = current_modifiers();
match virtual_key {
VK_SHIFT | VK_CONTROL | VK_MENU | VK_LWIN | VK_RWIN => {
VK_SHIFT | VK_CONTROL | VK_MENU | VK_LMENU | VK_RMENU | VK_LWIN | VK_RWIN => {
if state
.last_reported_modifiers
.is_some_and(|prev_modifiers| prev_modifiers == modifiers)
@@ -1460,13 +1460,25 @@ fn is_virtual_key_pressed(vkey: VIRTUAL_KEY) -> bool {
unsafe { GetKeyState(vkey.0 as i32) < 0 }
}
fn keyboard_uses_altgr() -> bool {
use crate::platform::windows::keyboard::WindowsKeyboardLayout;
WindowsKeyboardLayout::new()
.map(|layout| layout.uses_altgr())
.unwrap_or(false)
}
#[inline]
pub(crate) fn current_modifiers() -> Modifiers {
let altgr = is_virtual_key_pressed(VK_RMENU) && is_virtual_key_pressed(VK_LCONTROL);
let lmenu_pressed = is_virtual_key_pressed(VK_LMENU);
let rmenu_pressed = is_virtual_key_pressed(VK_RMENU);
let lcontrol_pressed = is_virtual_key_pressed(VK_LCONTROL);
// Only treat right Alt + left Ctrl as AltGr on keyboards that actually use it
let altgr = keyboard_uses_altgr() && rmenu_pressed && lcontrol_pressed;
Modifiers {
control: is_virtual_key_pressed(VK_CONTROL) && !altgr,
alt: is_virtual_key_pressed(VK_MENU) && !altgr,
alt: (lmenu_pressed || rmenu_pressed) && !altgr,
shift: is_virtual_key_pressed(VK_SHIFT),
platform: is_virtual_key_pressed(VK_LWIN) || is_virtual_key_pressed(VK_RWIN),
function: false,
@@ -110,6 +110,38 @@ impl WindowsKeyboardLayout {
name: "unknown".to_string(),
}
}
pub(crate) fn uses_altgr(&self) -> bool {
// Check if this is a known AltGr layout by examining the layout ID
// The layout ID is a hex string like "00000409" (US) or "00000407" (German)
// Extract the language ID (last 4 bytes)
let id_bytes = self.id.as_bytes();
if id_bytes.len() >= 4 {
let lang_id = &id_bytes[id_bytes.len() - 4..];
// List of keyboard layouts that use AltGr (non-exhaustive)
matches!(
lang_id,
b"0407" | // German
b"040C" | // French
b"040A" | // Spanish
b"0415" | // Polish
b"0413" | // Dutch
b"0816" | // Portuguese
b"041D" | // Swedish
b"0414" | // Norwegian
b"040B" | // Finnish
b"041F" | // Turkish
b"0419" | // Russian
b"0405" | // Czech
b"040E" | // Hungarian
b"0424" | // Slovenian
b"041B" | // Slovak
b"0418" // Romanian
)
} else {
false
}
}
}
impl WindowsKeyboardMapper {