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:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user