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,31 +205,49 @@ 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/
winuser::VK_SHIFT => unsafe { winuser::MapVirtualKeyA( let vkey = match vkey {
scancode, winuser::VK_SHIFT => unsafe { winuser::MapVirtualKeyA(
winuser::MAPVK_VSC_TO_VK_EX, scancode,
) as _ }, winuser::MAPVK_VSC_TO_VK_EX,
winuser::VK_CONTROL => if extended { ) as _ },
winuser::VK_RCONTROL winuser::VK_CONTROL => if extended {
} else { winuser::VK_RCONTROL
winuser::VK_LCONTROL } else {
}, winuser::VK_LCONTROL
winuser::VK_MENU => if extended { },
winuser::VK_RMENU winuser::VK_MENU => if extended {
} else { winuser::VK_RMENU
winuser::VK_LMENU } else {
}, 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,26 +586,27 @@ 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 {
window_id: SuperWindowId(WindowId(window)),
event: WindowEvent::KeyboardInput {
device_id: DEVICE_ID,
input: KeyboardInput {
state: Pressed,
scancode: scancode,
virtual_keycode: vkey,
modifiers: event::get_key_mods(),
}
}
});
// Windows doesn't emit a delete character by default, but in order to make it
// consistent with the other platforms we'll emit a delete character here.
if vkey == Some(VirtualKeyCode::Delete) {
send_event(Event::WindowEvent { send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)), window_id: SuperWindowId(WindowId(window)),
event: WindowEvent::ReceivedCharacter('\u{7F}'), event: WindowEvent::KeyboardInput {
device_id: DEVICE_ID,
input: KeyboardInput {
state: Pressed,
scancode: scancode,
virtual_keycode: vkey,
modifiers: event::get_key_mods(),
}
}
}); });
// Windows doesn't emit a delete character by default, but in order to make it
// consistent with the other platforms we'll emit a delete character here.
if vkey == Some(VirtualKeyCode::Delete) {
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: WindowEvent::ReceivedCharacter('\u{7F}'),
});
}
} }
0 0
} }
@ -613,19 +614,20 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
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 {
device_id: DEVICE_ID, device_id: DEVICE_ID,
input: KeyboardInput { input: KeyboardInput {
state: Released, state: Released,
scancode: scancode, scancode: scancode,
virtual_keycode: vkey, virtual_keycode: vkey,
modifiers: event::get_key_mods(), modifiers: event::get_key_mods(),
}, },
} }
}); });
}
0 0
}, },
@ -836,23 +838,25 @@ 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 {
device_id, device_id,
event: Key(KeyboardInput { event: Key(KeyboardInput {
scancode, scancode,
state, state,
virtual_keycode, virtual_keycode,
modifiers: event::get_key_mods(), modifiers: event::get_key_mods(),
}), }),
}); });
}
} }
} }
} }