Skip to content

Commit cc206d3

Browse files
Osspialmurarth
andauthored
Implement windows focus key press/release on Windows (#1307)
* X11: Sync key press/release with window focus * When a window loses focus, key release events are issued for all pressed keys * When a window gains focus, key press events are issued for all pressed keys * Adds `is_synthetic` field to `WindowEvent` variant `KeyboardInput` to indicate that these events are synthetic. * Adds `is_synthetic: false` to `WindowEvent::KeyboardInput` events issued on all other platforms * Implement windows focus key press/release on Windows * Docs Co-authored-by: Murarth <murarth@gmail.com>
1 parent 5d99316 commit cc206d3

File tree

4 files changed

+57
-3
lines changed

4 files changed

+57
-3
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
- On X11, generate synthetic key events for keys held when a window gains or loses focus.
3333
- On X11, issue a `CursorMoved` event when a `Touch` event occurs,
3434
as X11 implicitly moves the cursor for such events.
35+
- Add `is_synthetic` field to `WindowEvent` variant `KeyboardInput`,
36+
indicating that the event is generated by winit.
37+
- On X11 and Windows, generate synthetic key events for keys held when a window gains or loses focus.
3538

3639
# 0.20.0 Alpha 4 (2019-10-18)
3740

src/event.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,10 @@ pub enum WindowEvent {
150150
/// If `true`, the event was generated synthetically by winit
151151
/// in one of the following circumstances:
152152
///
153-
/// * **X11**: Synthetic key press events are generated for all keys pressed
153+
/// * Synthetic key press events are generated for all keys pressed
154154
/// when a window gains focus. Likewise, synthetic key release events
155155
/// are generated for all keys pressed when a window goes out of focus.
156+
/// ***Currently, this is only functional on X11 and Windows***
156157
///
157158
/// Otherwise, this value is always `false`.
158159
is_synthetic: bool,

src/platform_impl/windows/event.rs

+10
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ pub fn get_key_mods() -> ModifiersState {
2727
mods
2828
}
2929

30+
pub fn get_pressed_keys() -> impl Iterator<Item = c_int> {
31+
let mut keyboard_state = vec![0u8; 256];
32+
unsafe { winuser::GetKeyboardState(keyboard_state.as_mut_ptr()) };
33+
keyboard_state
34+
.into_iter()
35+
.enumerate()
36+
.filter(|(_, p)| (*p & (1 << 7)) != 0) // whether or not a key is pressed is communicated via the high-order bit
37+
.map(|(i, _)| i as c_int)
38+
}
39+
3040
unsafe fn get_char(keyboard_state: &[u8; 256], v_key: u32, hkl: HKL) -> Option<char> {
3141
let mut unicode_bytes = [0u16; 5];
3242
let len = winuser::ToUnicodeEx(

src/platform_impl/windows/event_loop.rs

+42-2
Original file line numberDiff line numberDiff line change
@@ -1421,7 +1421,27 @@ unsafe extern "system" fn public_window_callback<T>(
14211421
}
14221422

14231423
winuser::WM_SETFOCUS => {
1424-
use crate::event::WindowEvent::Focused;
1424+
use crate::event::{ElementState::Released, WindowEvent::Focused};
1425+
for windows_keycode in event::get_pressed_keys() {
1426+
let scancode =
1427+
winuser::MapVirtualKeyA(windows_keycode as _, winuser::MAPVK_VK_TO_VSC);
1428+
let virtual_keycode = event::vkey_to_winit_vkey(windows_keycode);
1429+
1430+
subclass_input.send_event(Event::WindowEvent {
1431+
window_id: RootWindowId(WindowId(window)),
1432+
event: WindowEvent::KeyboardInput {
1433+
device_id: DEVICE_ID,
1434+
input: KeyboardInput {
1435+
scancode,
1436+
virtual_keycode,
1437+
state: Released,
1438+
modifiers: event::get_key_mods(),
1439+
},
1440+
is_synthetic: true,
1441+
},
1442+
})
1443+
}
1444+
14251445
subclass_input.send_event(Event::WindowEvent {
14261446
window_id: RootWindowId(WindowId(window)),
14271447
event: Focused(true),
@@ -1431,7 +1451,27 @@ unsafe extern "system" fn public_window_callback<T>(
14311451
}
14321452

14331453
winuser::WM_KILLFOCUS => {
1434-
use crate::event::WindowEvent::Focused;
1454+
use crate::event::{ElementState::Released, WindowEvent::Focused};
1455+
for windows_keycode in event::get_pressed_keys() {
1456+
let scancode =
1457+
winuser::MapVirtualKeyA(windows_keycode as _, winuser::MAPVK_VK_TO_VSC);
1458+
let virtual_keycode = event::vkey_to_winit_vkey(windows_keycode);
1459+
1460+
subclass_input.send_event(Event::WindowEvent {
1461+
window_id: RootWindowId(WindowId(window)),
1462+
event: WindowEvent::KeyboardInput {
1463+
device_id: DEVICE_ID,
1464+
input: KeyboardInput {
1465+
scancode,
1466+
virtual_keycode,
1467+
state: Released,
1468+
modifiers: event::get_key_mods(),
1469+
},
1470+
is_synthetic: true,
1471+
},
1472+
})
1473+
}
1474+
14351475
subclass_input.send_event(Event::WindowEvent {
14361476
window_id: RootWindowId(WindowId(window)),
14371477
event: Focused(false),

0 commit comments

Comments
 (0)