Windows: Fix detection of Pause and Scroll keys (#525)

Fixes #524
This commit is contained in:
Francesca Frangipane 2018-05-18 18:48:19 -04:00 committed by GitHub
parent dec728cfa2
commit fddfb2e2d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 88 additions and 65 deletions

View file

@ -16,6 +16,7 @@
- macOS keyboard handling has been overhauled, allowing for the use of dead keys, IME, etc. Right modifier keys are also no longer reported as being left. - macOS keyboard handling has been overhauled, allowing for the use of dead keys, IME, etc. Right modifier keys are also no longer reported as being left.
- Added the `Window::set_ime_spot(x: i32, y: i32)` method, which is implemented on X11 and macOS. - Added the `Window::set_ime_spot(x: i32, y: i32)` method, which is implemented on X11 and macOS.
- **Breaking**: `os::unix::WindowExt::send_xim_spot(x: i16, y: i16)` no longer exists. Switch to the new `Window::set_ime_spot(x: i32, y: i32)`, which has equivalent functionality. - **Breaking**: `os::unix::WindowExt::send_xim_spot(x: i16, y: i16)` no longer exists. Switch to the new `Window::set_ime_spot(x: i32, y: i32)`, which has equivalent functionality.
- Fixed detection of `Pause` and `Scroll` keys on Windows.
# Version 0.14.0 (2018-05-09) # Version 0.14.0 (2018-05-09)

View file

@ -205,8 +205,9 @@ pub fn vkey_to_winit_vkey(vkey: c_int) -> Option<VirtualKeyCode> {
} }
} }
pub fn vkey_left_right(vkey: c_int, scancode: UINT, extended: bool) -> c_int { pub fn handle_extended_keys(vkey: c_int, mut scancode: UINT, extended: bool) -> Option<(c_int, UINT)> {
match vkey { // Welcome to hell https://blog.molecular-matters.com/2011/09/05/properly-handling-keyboard-input/
let vkey = match vkey {
winuser::VK_SHIFT => unsafe { winuser::MapVirtualKeyA( winuser::VK_SHIFT => unsafe { winuser::MapVirtualKeyA(
scancode, scancode,
winuser::MAPVK_VSC_TO_VK_EX, winuser::MAPVK_VSC_TO_VK_EX,
@ -221,15 +222,32 @@ pub fn vkey_left_right(vkey: c_int, scancode: UINT, extended: bool) -> c_int {
} else { } else {
winuser::VK_LMENU winuser::VK_LMENU
}, },
_ => vkey, _ => match scancode {
// This is only triggered when using raw input. Without this check, we get two events whenever VK_PAUSE is
// pressed, the first one having scancode 0x1D but vkey VK_PAUSE...
0x1D if vkey == winuser::VK_PAUSE => return None,
// ...and the second having scancode 0x45 but an unmatched vkey!
0x45 => winuser::VK_PAUSE,
// VK_PAUSE and VK_SCROLL have the same scancode when using modifiers, alongside incorrect vkey values.
0x46 => {
if extended {
scancode = 0x45;
winuser::VK_PAUSE
} else {
winuser::VK_SCROLL
} }
},
_ => vkey,
},
};
Some((vkey, scancode))
} }
pub fn vkeycode_to_element(wparam: WPARAM, lparam: LPARAM) -> (ScanCode, Option<VirtualKeyCode>) { pub fn process_key_params(wparam: WPARAM, lparam: LPARAM) -> Option<(ScanCode, Option<VirtualKeyCode>)> {
let scancode = ((lparam >> 16) & 0xff) as UINT; let scancode = ((lparam >> 16) & 0xff) as UINT;
let extended = (lparam & 0x01000000) != 0; let extended = (lparam & 0x01000000) != 0;
let vkey = vkey_left_right(wparam as _, scancode, extended); handle_extended_keys(wparam as _, scancode, extended)
(scancode, vkey_to_winit_vkey(vkey)) .map(|(vkey, scancode)| (scancode, vkey_to_winit_vkey(vkey)))
} }
// This is needed as windows doesn't properly distinguish // This is needed as windows doesn't properly distinguish

View file

@ -34,7 +34,7 @@ use winapi::um::winnt::{LONG, SHORT};
use events::DeviceEvent; use events::DeviceEvent;
use platform::platform::{event, Cursor, WindowId, DEVICE_ID, wrap_device_id, util}; use platform::platform::{event, Cursor, WindowId, DEVICE_ID, wrap_device_id, util};
use platform::platform::event::{vkey_to_winit_vkey, vkey_left_right}; use platform::platform::event::{handle_extended_keys, process_key_params, vkey_to_winit_vkey};
use platform::platform::raw_input::*; use platform::platform::raw_input::*;
use platform::platform::window::adjust_size; use platform::platform::window::adjust_size;
@ -586,7 +586,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
if msg == winuser::WM_SYSKEYDOWN && wparam as i32 == winuser::VK_F4 { if msg == winuser::WM_SYSKEYDOWN && wparam as i32 == winuser::VK_F4 {
winuser::DefWindowProcW(window, msg, wparam, lparam) winuser::DefWindowProcW(window, msg, wparam, lparam)
} else { } else {
let (scancode, vkey) = event::vkeycode_to_element(wparam, lparam); if let Some((scancode, vkey)) = process_key_params(wparam, lparam) {
send_event(Event::WindowEvent { send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)), window_id: SuperWindowId(WindowId(window)),
event: WindowEvent::KeyboardInput { event: WindowEvent::KeyboardInput {
@ -607,13 +607,14 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
event: WindowEvent::ReceivedCharacter('\u{7F}'), event: WindowEvent::ReceivedCharacter('\u{7F}'),
}); });
} }
}
0 0
} }
}, },
winuser::WM_KEYUP | winuser::WM_SYSKEYUP => { winuser::WM_KEYUP | winuser::WM_SYSKEYUP => {
use events::ElementState::Released; use events::ElementState::Released;
let (scancode, vkey) = event::vkeycode_to_element(wparam, lparam); if let Some((scancode, vkey)) = process_key_params(wparam, lparam) {
send_event(Event::WindowEvent { send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)), window_id: SuperWindowId(WindowId(window)),
event: WindowEvent::KeyboardInput { event: WindowEvent::KeyboardInput {
@ -626,6 +627,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
}, },
} }
}); });
}
0 0
}, },
@ -836,12 +838,13 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
}; };
let scancode = keyboard.MakeCode as _; let scancode = keyboard.MakeCode as _;
let extended = util::has_flag(keyboard.Flags, winuser::RI_KEY_E0 as _); let extended = util::has_flag(keyboard.Flags, winuser::RI_KEY_E0 as _)
let vkey = vkey_left_right( | util::has_flag(keyboard.Flags, winuser::RI_KEY_E1 as _);
if let Some((vkey, scancode)) = handle_extended_keys(
keyboard.VKey as _, keyboard.VKey as _,
scancode, scancode,
extended, extended,
); ) {
let virtual_keycode = vkey_to_winit_vkey(vkey); let virtual_keycode = vkey_to_winit_vkey(vkey);
send_event(Event::DeviceEvent { send_event(Event::DeviceEvent {
@ -856,6 +859,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
} }
} }
} }
}
winuser::DefWindowProcW(window, msg, wparam, lparam) winuser::DefWindowProcW(window, msg, wparam, lparam)
}, },