From b1e07f9aa234fc7fdb426901243efeb09cae54eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Art=C3=BAr=20Kov=C3=A1cs?= Date: Sun, 25 Apr 2021 18:29:55 +0200 Subject: [PATCH 01/53] New keyboard API for Windows (#1788) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Introducing the new `KeyEvent` and renaming old stuff * Implemented physical_key on Windows * Ran cargo fmt * Progress with the keyboard's windows implementation * Add proper handling of dead keys * Add translation for non-printable virtual keys * Run `cargo fmt` * Fix for AltGraph not being reported * Synthesize key events when focus enters or leaves * Minor improvements * Remove obsolete API * Fix numlock and pause not being reported correctly * Ran `cargo fmt` * Fix numpad keys being reported incorrectly * Update examples * Ran `cargo fmt` * Add documentation for `ScanCode` * Add key binding example * Use consistent modifier key names #1343 * WONT COMPILE transitioning to new keyboard API * WONT COMPILE Implement new keyboard layout preparation * WONT COMPILE new keyboard API progress * Main compile errors fixed for keyboard * Fix bugs in new keyboard handling * Remove obsolete code * Fix examples * Ran `cargo fmt` * Fix build error with serde * Ran `cargo fmt` * Tweaks in the Windows keyboard implementation * Add `KeyCodeExtScancode` * Add `reset_dead_keys` * Improve the documentation for `Key` and `KeyCode` * Rename the meta key to super * Address feedback for the keyboard API * Fix for rustdoc Co-authored-by: Markus Røyset * Improve documentation Co-authored-by: Markus Røyset * Fix for arrow keys being reported as unidentified. And minor improvements * Fix media keys reporting Unidentified * Don't report text on key release events * Fix for NumLock being reported as Pause in raw input * Fix for strange behaviour around NumLock and Pause * Fix for NumLock being ineffective * Fix for location not being reported correctly * `RawKeyEvent`s now report repeat * Don't report text for synthetic key releases * Address feedback - Add the `Space` variant to the `to_text` function. - Mark `get_kbd_state` safe. - Change `[MaybeUninit; 256]` to `MaybeUninit<[u8; 256]>` * Filter `Unidentified` from PrtSc key device events * Don't report incorrect `RawKeyEvent` for shift + numpad * AltGraph is not reported again * Document Windows specific behaviour for shift+numpad * Fix typo * Dead keys now affect characters from logical_key * Prevent Pause and NumLock mappings in window events * Apply suggestions from code review Co-authored-by: Markus Røyset * Ran `cargo fmt` * Add W3C license for `Key` and `KeyCode` * Extend documentation according to feedback * Ignore NumLock in `key_without_modifiers` * Remove unused `key_code_to_non_char_key` * Remove empty event.rs file * Use space for resetting dead keys * Fix reporting multiple graphemes in logical_key * Avoid incorrect synthetic keypress during setfocus * Fixed the AltGr keypress not being reported when the AltGr key is pressed and released in a very quick succession * Filter fake Ctrl events when pressing AltGr * Improve code quality * Remove `repeat` from `RawKeyEvent` * Allow fractional scroll in raw mouse events * Fix typo Co-authored-by: Markus Siglreithmaier * Remove unused imports * Remove unused variable * Remove unnecessary `unwrap()` Co-authored-by: Markus Siglreithmaier * Avoid using the deprecated `into_rgba()` * Fix IME crash Co-authored-by: Markus Røyset Co-authored-by: Markus Siglreithmaier --- Cargo.toml | 3 + examples/control_flow.rs | 25 +- examples/cursor.rs | 6 +- examples/cursor_grab.rs | 21 +- examples/fullscreen.rs | 26 +- examples/handling_close.rs | 23 +- examples/key_binding.rs | 58 + examples/minimize.rs | 12 +- examples/multithreaded.rs | 163 +- examples/multiwindow.rs | 8 +- examples/resizable.rs | 9 +- examples/window_debug.rs | 121 +- src/event.rs | 416 ++--- src/keyboard.rs | 1417 ++++++++++++++++++ src/lib.rs | 1 + src/platform/mod.rs | 2 + src/platform/modifier_supplement.rs | 32 + src/platform/scancode.rs | 31 + src/platform/windows.rs | 362 ++++- src/platform_impl/windows/event.rs | 417 ------ src/platform_impl/windows/event_loop.rs | 660 ++++---- src/platform_impl/windows/keyboard.rs | 802 ++++++++++ src/platform_impl/windows/keyboard_layout.rs | 993 ++++++++++++ src/platform_impl/windows/minimal_ime.rs | 93 ++ src/platform_impl/windows/mod.rs | 11 +- src/platform_impl/windows/window.rs | 21 + src/platform_impl/windows/window_state.rs | 12 +- src/window.rs | 16 + tests/serde_objects.rs | 11 +- 29 files changed, 4514 insertions(+), 1258 deletions(-) create mode 100644 examples/key_binding.rs create mode 100644 src/keyboard.rs create mode 100644 src/platform/modifier_supplement.rs create mode 100644 src/platform/scancode.rs delete mode 100644 src/platform_impl/windows/event.rs create mode 100644 src/platform_impl/windows/keyboard.rs create mode 100644 src/platform_impl/windows/keyboard_layout.rs create mode 100644 src/platform_impl/windows/minimal_ime.rs diff --git a/Cargo.toml b/Cargo.toml index b1e4159ba4..d65620d493 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ serde = { version = "1", optional = true, features = ["serde_derive"] } raw-window-handle = "0.4.2" bitflags = "1" mint = { version = "0.5.6", optional = true } +nameof = "1" [dev-dependencies] image = "0.23.12" @@ -56,6 +57,7 @@ features = ["display_link"] [target.'cfg(target_os = "windows")'.dependencies] parking_lot = "0.11" +unicode-segmentation = "1.7.1" [target.'cfg(target_os = "windows")'.dependencies.winapi] version = "0.3.9" @@ -79,6 +81,7 @@ features = [ "winerror", "wingdi", "winnt", + "winnls", "winuser", "mmsystem", "timeapi" diff --git a/examples/control_flow.rs b/examples/control_flow.rs index cbb445eebb..9835c436f2 100644 --- a/examples/control_flow.rs +++ b/examples/control_flow.rs @@ -2,8 +2,9 @@ use std::{thread, time}; use simple_logger::SimpleLogger; use winit::{ - event::{Event, KeyboardInput, WindowEvent}, + event::{ElementState, Event, KeyEvent, WindowEvent}, event_loop::{ControlFlow, EventLoop}, + keyboard::Key, window::WindowBuilder, }; @@ -38,7 +39,7 @@ fn main() { let mut close_requested = false; event_loop.run(move |event, _, control_flow| { - use winit::event::{ElementState, StartCause, VirtualKeyCode}; + use winit::event::StartCause; println!("{:?}", event); match event { Event::NewEvents(start_cause) => { @@ -52,31 +53,33 @@ fn main() { close_requested = true; } WindowEvent::KeyboardInput { - input: - KeyboardInput { - virtual_keycode: Some(virtual_code), + event: + KeyEvent { + logical_key: key, state: ElementState::Pressed, .. }, .. - } => match virtual_code { - VirtualKeyCode::Key1 => { + } => match key { + // WARNING: Consider using `key_without_modifers()` if available on your platform. + // See the `key_binding` example + Key::Character("1") => { mode = Mode::Wait; println!("\nmode: {:?}\n", mode); } - VirtualKeyCode::Key2 => { + Key::Character("2") => { mode = Mode::WaitUntil; println!("\nmode: {:?}\n", mode); } - VirtualKeyCode::Key3 => { + Key::Character("3") => { mode = Mode::Poll; println!("\nmode: {:?}\n", mode); } - VirtualKeyCode::R => { + Key::Character("r") => { request_redraw = !request_redraw; println!("\nrequest_redraw: {}\n", request_redraw); } - VirtualKeyCode::Escape => { + Key::Escape => { close_requested = true; } _ => (), diff --git a/examples/cursor.rs b/examples/cursor.rs index 6ec8a05933..d9230e32e6 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -1,6 +1,6 @@ use simple_logger::SimpleLogger; use winit::{ - event::{ElementState, Event, KeyboardInput, WindowEvent}, + event::{ElementState, Event, KeyEvent, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{CursorIcon, WindowBuilder}, }; @@ -21,8 +21,8 @@ fn main() { Event::WindowEvent { event: WindowEvent::KeyboardInput { - input: - KeyboardInput { + event: + KeyEvent { state: ElementState::Pressed, .. }, diff --git a/examples/cursor_grab.rs b/examples/cursor_grab.rs index 90a94764de..746bf426ba 100644 --- a/examples/cursor_grab.rs +++ b/examples/cursor_grab.rs @@ -1,7 +1,8 @@ use simple_logger::SimpleLogger; use winit::{ - event::{DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, WindowEvent}, + event::{DeviceEvent, ElementState, Event, KeyEvent, WindowEvent}, event_loop::{ControlFlow, EventLoop}, + keyboard::{Key, ModifiersState}, window::WindowBuilder, }; @@ -23,19 +24,23 @@ fn main() { Event::WindowEvent { event, .. } => match event { WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, WindowEvent::KeyboardInput { - input: - KeyboardInput { + event: + KeyEvent { + logical_key: key, state: ElementState::Released, - virtual_keycode: Some(key), .. }, .. } => { - use winit::event::VirtualKeyCode::*; + // WARNING: Consider using `key_without_modifers()` if available on your platform. + // See the `key_binding` example match key { - Escape => *control_flow = ControlFlow::Exit, - G => window.set_cursor_grab(!modifiers.shift()).unwrap(), - H => window.set_cursor_visible(modifiers.shift()), + Key::Escape => *control_flow = ControlFlow::Exit, + Key::Character(ch) => match ch.to_lowercase().as_str() { + "g" => window.set_cursor_grab(!modifiers.shift_key()).unwrap(), + "h" => window.set_cursor_visible(modifiers.shift_key()), + _ => (), + }, _ => (), } } diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index 90d41ece12..d9d9876383 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -1,8 +1,9 @@ use std::io::{stdin, stdout, Write}; use simple_logger::SimpleLogger; -use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}; +use winit::event::{ElementState, Event, KeyEvent, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; +use winit::keyboard::Key; use winit::monitor::{MonitorHandle, VideoMode}; use winit::window::{Fullscreen, WindowBuilder}; @@ -38,30 +39,33 @@ fn main() { Event::WindowEvent { event, .. } => match event { WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, WindowEvent::KeyboardInput { - input: - KeyboardInput { - virtual_keycode: Some(virtual_code), - state, + event: + KeyEvent { + logical_key: key, + state: ElementState::Pressed, .. }, .. - } => match (virtual_code, state) { - (VirtualKeyCode::Escape, _) => *control_flow = ControlFlow::Exit, - (VirtualKeyCode::F, ElementState::Pressed) => { + } => match key { + Key::Escape => *control_flow = ControlFlow::Exit, + + // WARNING: Consider using `key_without_modifers()` if available on your platform. + // See the `key_binding` example + Key::Character("f") => { if window.fullscreen().is_some() { window.set_fullscreen(None); } else { window.set_fullscreen(fullscreen.clone()); } } - (VirtualKeyCode::S, ElementState::Pressed) => { + Key::Character("s") => { println!("window.fullscreen {:?}", window.fullscreen()); } - (VirtualKeyCode::M, ElementState::Pressed) => { + Key::Character("m") => { let is_maximized = window.is_maximized(); window.set_maximized(!is_maximized); } - (VirtualKeyCode::D, ElementState::Pressed) => { + Key::Character("d") => { decorations = !decorations; window.set_decorations(decorations); } diff --git a/examples/handling_close.rs b/examples/handling_close.rs index 8334c1773f..283cf48195 100644 --- a/examples/handling_close.rs +++ b/examples/handling_close.rs @@ -1,7 +1,8 @@ use simple_logger::SimpleLogger; use winit::{ - event::{Event, KeyboardInput, WindowEvent}, + event::{ElementState, Event, KeyEvent, WindowEvent}, event_loop::{ControlFlow, EventLoop}, + keyboard::Key, window::WindowBuilder, }; @@ -17,10 +18,6 @@ fn main() { let mut close_requested = false; event_loop.run(move |event, _, control_flow| { - use winit::event::{ - ElementState::Released, - VirtualKeyCode::{N, Y}, - }; *control_flow = ControlFlow::Wait; match event { @@ -44,16 +41,18 @@ fn main() { // the Y key. } WindowEvent::KeyboardInput { - input: - KeyboardInput { - virtual_keycode: Some(virtual_code), - state: Released, + event: + KeyEvent { + logical_key: key, + state: ElementState::Released, .. }, .. } => { - match virtual_code { - Y => { + // WARNING: Consider using `key_without_modifers()` if available on your platform. + // See the `key_binding` example + match key { + Key::Character("y") => { if close_requested { // This is where you'll want to do any cleanup you need. println!("Buh-bye!"); @@ -66,7 +65,7 @@ fn main() { *control_flow = ControlFlow::Exit; } } - N => { + Key::Character("n") => { if close_requested { println!("Your window will continue to stay by your side."); close_requested = false; diff --git a/examples/key_binding.rs b/examples/key_binding.rs new file mode 100644 index 0000000000..6f9bb1fe83 --- /dev/null +++ b/examples/key_binding.rs @@ -0,0 +1,58 @@ +use simple_logger::SimpleLogger; +use winit::{ + dpi::LogicalSize, + event::{ElementState, Event, KeyEvent, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + keyboard::{Key, ModifiersState}, + window::WindowBuilder, +}; + +///////////////////////////////////////////////////////////////////////////// +// WARNING: This is not available on all platforms (for example on the web). +use winit::platform::modifier_supplement::KeyEventExtModifierSupplement; +///////////////////////////////////////////////////////////////////////////// + +fn main() { + SimpleLogger::new().init().unwrap(); + let event_loop = EventLoop::new(); + + let _window = WindowBuilder::new() + .with_inner_size(LogicalSize::new(400.0, 200.0)) + .build(&event_loop) + .unwrap(); + + let mut modifiers = ModifiersState::default(); + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Wait; + + match event { + Event::WindowEvent { event, .. } => match event { + WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, + WindowEvent::ModifiersChanged(new_state) => { + modifiers = new_state; + } + WindowEvent::KeyboardInput { event, .. } => { + handle_key_event(modifiers, event); + } + _ => (), + }, + _ => (), + }; + }); +} + +fn handle_key_event(modifiers: ModifiersState, event: KeyEvent) { + if event.state == ElementState::Pressed && !event.repeat { + match event.key_without_modifiers() { + Key::Character("1") => { + if modifiers.shift_key() { + println!("Shift + 1 | logical_key: {:?}", event.logical_key); + } else { + println!("1"); + } + } + _ => (), + } + } +} diff --git a/examples/minimize.rs b/examples/minimize.rs index eb02a752c9..3c8b7f84ed 100644 --- a/examples/minimize.rs +++ b/examples/minimize.rs @@ -1,8 +1,10 @@ extern crate winit; use simple_logger::SimpleLogger; -use winit::event::{Event, VirtualKeyCode, WindowEvent}; + +use winit::event::{Event, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; +use winit::keyboard::Key; use winit::window::WindowBuilder; fn main() { @@ -25,12 +27,14 @@ fn main() { // Keyboard input event to handle minimize via a hotkey Event::WindowEvent { - event: WindowEvent::KeyboardInput { input, .. }, + event: WindowEvent::KeyboardInput { event, .. }, window_id, } => { if window_id == window.id() { - // Pressing the 'M' key will minimize the window - if input.virtual_keycode == Some(VirtualKeyCode::M) { + // Pressing the 'm' key will minimize the window + // WARNING: Consider using `key_without_modifers()` if available on your platform. + // See the `key_binding` example + if let Key::Character("m") = event.logical_key { window.set_minimized(true); } } diff --git a/examples/multithreaded.rs b/examples/multithreaded.rs index ba2b9ad240..6af0699772 100644 --- a/examples/multithreaded.rs +++ b/examples/multithreaded.rs @@ -5,8 +5,9 @@ fn main() { use simple_logger::SimpleLogger; use winit::{ dpi::{PhysicalPosition, PhysicalSize, Position, Size}, - event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, + event::{ElementState, Event, KeyEvent, WindowEvent}, event_loop::{ControlFlow, EventLoop}, + keyboard::{Key, ModifiersState}, window::{CursorIcon, Fullscreen, WindowBuilder}, }; @@ -27,6 +28,7 @@ fn main() { let (tx, rx) = mpsc::channel(); window_senders.insert(window.id(), tx); + let mut modifiers = ModifiersState::default(); thread::spawn(move || { while let Ok(event) = rx.recv() { match event { @@ -49,91 +51,96 @@ fn main() { ); } } - #[allow(deprecated)] + WindowEvent::ModifiersChanged(mod_state) => { + modifiers = mod_state; + } WindowEvent::KeyboardInput { - input: - KeyboardInput { + event: + KeyEvent { state: ElementState::Released, - virtual_keycode: Some(key), - modifiers, + logical_key: key, .. }, .. } => { + use Key::{ArrowLeft, ArrowRight, Character}; window.set_title(&format!("{:?}", key)); - let state = !modifiers.shift(); - use VirtualKeyCode::*; - match key { - A => window.set_always_on_top(state), - C => window.set_cursor_icon(match state { - true => CursorIcon::Progress, - false => CursorIcon::Default, - }), - D => window.set_decorations(!state), - // Cycle through video modes - Right | Left => { - video_mode_id = match key { - Left => video_mode_id.saturating_sub(1), - Right => (video_modes.len() - 1).min(video_mode_id + 1), + let state = !modifiers.shift_key(); + match &key { + // WARNING: Consider using `key_without_modifers()` if available on your platform. + // See the `key_binding` example + Character(string) => match string.to_lowercase().as_str() { + "a" => window.set_always_on_top(state), + "c" => window.set_cursor_icon(match state { + true => CursorIcon::Progress, + false => CursorIcon::Default, + }), + "d" => window.set_decorations(!state), + "f" => window.set_fullscreen(match (state, modifiers.alt_key()) { + (true, false) => Some(Fullscreen::Borderless(None)), + (true, true) => Some(Fullscreen::Exclusive( + video_modes[video_mode_id].clone(), + )), + (false, _) => None, + }), + "g" => window.set_cursor_grab(state).unwrap(), + "h" => window.set_cursor_visible(!state), + "i" => { + println!("Info:"); + println!("-> outer_position : {:?}", window.outer_position()); + println!("-> inner_position : {:?}", window.inner_position()); + println!("-> outer_size : {:?}", window.outer_size()); + println!("-> inner_size : {:?}", window.inner_size()); + println!("-> fullscreen : {:?}", window.fullscreen()); + } + "l" => window.set_min_inner_size(match state { + true => Some(WINDOW_SIZE), + false => None, + }), + "m" => window.set_maximized(state), + "p" => window.set_outer_position({ + let mut position = window.outer_position().unwrap(); + let sign = if state { 1 } else { -1 }; + position.x += 10 * sign; + position.y += 10 * sign; + position + }), + "q" => window.request_redraw(), + "r" => window.set_resizable(state), + "s" => window.set_inner_size(match state { + true => PhysicalSize::new( + WINDOW_SIZE.width + 100, + WINDOW_SIZE.height + 100, + ), + false => WINDOW_SIZE, + }), + "w" => { + if let Size::Physical(size) = WINDOW_SIZE.into() { + window + .set_cursor_position(Position::Physical( + PhysicalPosition::new( + size.width as i32 / 2, + size.height as i32 / 2, + ), + )) + .unwrap() + } + } + "z" => { + window.set_visible(false); + thread::sleep(Duration::from_secs(1)); + window.set_visible(true); + } + _ => (), + }, + ArrowRight | ArrowLeft => { + video_mode_id = match &key { + ArrowLeft => video_mode_id.saturating_sub(1), + ArrowRight => (video_modes.len() - 1).min(video_mode_id + 1), _ => unreachable!(), }; println!("Picking video mode: {}", video_modes[video_mode_id]); } - F => window.set_fullscreen(match (state, modifiers.alt()) { - (true, false) => Some(Fullscreen::Borderless(None)), - (true, true) => { - Some(Fullscreen::Exclusive(video_modes[video_mode_id].clone())) - } - (false, _) => None, - }), - G => window.set_cursor_grab(state).unwrap(), - H => window.set_cursor_visible(!state), - I => { - println!("Info:"); - println!("-> outer_position : {:?}", window.outer_position()); - println!("-> inner_position : {:?}", window.inner_position()); - println!("-> outer_size : {:?}", window.outer_size()); - println!("-> inner_size : {:?}", window.inner_size()); - println!("-> fullscreen : {:?}", window.fullscreen()); - } - L => window.set_min_inner_size(match state { - true => Some(WINDOW_SIZE), - false => None, - }), - M => window.set_maximized(state), - P => window.set_outer_position({ - let mut position = window.outer_position().unwrap(); - let sign = if state { 1 } else { -1 }; - position.x += 10 * sign; - position.y += 10 * sign; - position - }), - Q => window.request_redraw(), - R => window.set_resizable(state), - S => window.set_inner_size(match state { - true => PhysicalSize::new( - WINDOW_SIZE.width + 100, - WINDOW_SIZE.height + 100, - ), - false => WINDOW_SIZE, - }), - W => { - if let Size::Physical(size) = WINDOW_SIZE.into() { - window - .set_cursor_position(Position::Physical( - PhysicalPosition::new( - size.width as i32 / 2, - size.height as i32 / 2, - ), - )) - .unwrap() - } - } - Z => { - window.set_visible(false); - thread::sleep(Duration::from_secs(1)); - window.set_visible(true); - } _ => (), } } @@ -152,10 +159,10 @@ fn main() { WindowEvent::CloseRequested | WindowEvent::Destroyed | WindowEvent::KeyboardInput { - input: - KeyboardInput { + event: + KeyEvent { state: ElementState::Released, - virtual_keycode: Some(VirtualKeyCode::Escape), + logical_key: Key::Escape, .. }, .. diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index e946537296..2e6a84cfd8 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use simple_logger::SimpleLogger; use winit::{ - event::{ElementState, Event, KeyboardInput, WindowEvent}, + event::{ElementState, Event, KeyEvent, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::Window, }; @@ -34,9 +34,9 @@ fn main() { } } WindowEvent::KeyboardInput { - input: - KeyboardInput { - state: ElementState::Pressed, + event: + KeyEvent { + state: ElementState::Released, .. }, .. diff --git a/examples/resizable.rs b/examples/resizable.rs index 17892d8741..8d3387cabb 100644 --- a/examples/resizable.rs +++ b/examples/resizable.rs @@ -1,8 +1,9 @@ use simple_logger::SimpleLogger; use winit::{ dpi::LogicalSize, - event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, + event::{ElementState, Event, KeyEvent, WindowEvent}, event_loop::{ControlFlow, EventLoop}, + keyboard::KeyCode, window::WindowBuilder, }; @@ -26,9 +27,9 @@ fn main() { Event::WindowEvent { event, .. } => match event { WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, WindowEvent::KeyboardInput { - input: - KeyboardInput { - virtual_keycode: Some(VirtualKeyCode::Space), + event: + KeyEvent { + physical_key: KeyCode::Space, state: ElementState::Released, .. }, diff --git a/examples/window_debug.rs b/examples/window_debug.rs index 577ad5cd73..4a12cf47b9 100644 --- a/examples/window_debug.rs +++ b/examples/window_debug.rs @@ -3,8 +3,9 @@ use simple_logger::SimpleLogger; use winit::{ dpi::{LogicalSize, PhysicalSize}, - event::{DeviceEvent, ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, + event::{DeviceEvent, ElementState, Event, KeyEvent, RawKeyEvent, WindowEvent}, event_loop::{ControlFlow, EventLoop}, + keyboard::{Key, KeyCode}, window::{Fullscreen, WindowBuilder}, }; @@ -34,22 +35,24 @@ fn main() { *control_flow = ControlFlow::Wait; match event { + // This used to use the virtual key, but the new API + // only provides the `physical_key` (`Code`). Event::DeviceEvent { event: - DeviceEvent::Key(KeyboardInput { - virtual_keycode: Some(key), - state: ElementState::Pressed, + DeviceEvent::Key(RawKeyEvent { + physical_key, + state: ElementState::Released, .. }), .. - } => match key { - VirtualKeyCode::M => { + } => match physical_key { + KeyCode::KeyM => { if minimized { minimized = !minimized; window.set_minimized(minimized); } } - VirtualKeyCode::V => { + KeyCode::KeyV => { if !visible { visible = !visible; window.set_visible(visible); @@ -58,61 +61,65 @@ fn main() { _ => (), }, Event::WindowEvent { - event: WindowEvent::KeyboardInput { input, .. }, + event: + WindowEvent::KeyboardInput { + event: + KeyEvent { + logical_key: Key::Character(key_str), + state: ElementState::Released, + .. + }, + .. + }, .. - } => match input { - KeyboardInput { - virtual_keycode: Some(key), - state: ElementState::Pressed, - .. - } => match key { - VirtualKeyCode::E => { - fn area(size: PhysicalSize) -> u32 { - size.width * size.height - } - - let monitor = window.current_monitor().unwrap(); - if let Some(mode) = monitor - .video_modes() - .max_by(|a, b| area(a.size()).cmp(&area(b.size()))) - { - window.set_fullscreen(Some(Fullscreen::Exclusive(mode))); - } else { - eprintln!("no video modes available"); - } - } - VirtualKeyCode::F => { - if window.fullscreen().is_some() { - window.set_fullscreen(None); - } else { - let monitor = window.current_monitor(); - window.set_fullscreen(Some(Fullscreen::Borderless(monitor))); - } - } - VirtualKeyCode::P => { - if window.fullscreen().is_some() { - window.set_fullscreen(None); - } else { - window.set_fullscreen(Some(Fullscreen::Borderless(None))); - } + } => match key_str { + // WARNING: Consider using `key_without_modifers()` if available on your platform. + // See the `key_binding` example + "e" => { + fn area(size: PhysicalSize) -> u32 { + size.width * size.height } - VirtualKeyCode::M => { - minimized = !minimized; - window.set_minimized(minimized); - } - VirtualKeyCode::Q => { - *control_flow = ControlFlow::Exit; + + let monitor = window.current_monitor().unwrap(); + if let Some(mode) = monitor + .video_modes() + .max_by(|a, b| area(a.size()).cmp(&area(b.size()))) + { + window.set_fullscreen(Some(Fullscreen::Exclusive(mode))); + } else { + eprintln!("no video modes available"); } - VirtualKeyCode::V => { - visible = !visible; - window.set_visible(visible); + } + "f" => { + if window.fullscreen().is_some() { + window.set_fullscreen(None); + } else { + let monitor = window.current_monitor(); + window.set_fullscreen(Some(Fullscreen::Borderless(monitor))); } - VirtualKeyCode::X => { - let is_maximized = window.is_maximized(); - window.set_maximized(!is_maximized); + } + "p" => { + if window.fullscreen().is_some() { + window.set_fullscreen(None); + } else { + window.set_fullscreen(Some(Fullscreen::Borderless(None))); } - _ => (), - }, + } + "m" => { + minimized = !minimized; + window.set_minimized(minimized); + } + "q" => { + *control_flow = ControlFlow::Exit; + } + "v" => { + visible = !visible; + window.set_visible(visible); + } + "x" => { + let is_maximized = window.is_maximized(); + window.set_maximized(!is_maximized); + } _ => (), }, Event::WindowEvent { diff --git a/src/event.rs b/src/event.rs index 6660e00688..7e172cad47 100644 --- a/src/event.rs +++ b/src/event.rs @@ -38,6 +38,7 @@ use std::path::PathBuf; use crate::{ dpi::{PhysicalPosition, PhysicalSize}, + keyboard::{self, ModifiersState}, platform_impl, window::{Theme, WindowId}, }; @@ -239,8 +240,12 @@ pub enum WindowEvent<'a> { /// hovered. HoveredFileCancelled, - /// The window received a unicode character. - ReceivedCharacter(char), + /// The user commited an IME string for this window. + /// + /// This is a temporary API until [#1497] gets completed. + /// + /// [#1497]: https://github.com/rust-windowing/winit/issues/1497 + ReceivedImeText(String), /// The window gained or lost focus. /// @@ -248,9 +253,15 @@ pub enum WindowEvent<'a> { Focused(bool), /// An event from the keyboard has been received. + /// + /// ## Platform-specific + /// - **Windows:** The shift key overrides NumLock. In other words, while shift is held down, + /// numpad keys act as if NumLock wasn't active. When this is used, the OS sends fake key + /// events which are not marked as `is_synthetic`. KeyboardInput { device_id: DeviceId, - input: KeyboardInput, + event: KeyEvent, + /// If `true`, the event was generated synthetically by winit /// in one of the following circumstances: /// @@ -365,15 +376,15 @@ impl Clone for WindowEvent<'static> { DroppedFile(file) => DroppedFile(file.clone()), HoveredFile(file) => HoveredFile(file.clone()), HoveredFileCancelled => HoveredFileCancelled, - ReceivedCharacter(c) => ReceivedCharacter(*c), + ReceivedImeText(s) => ReceivedImeText(s.clone()), Focused(f) => Focused(*f), KeyboardInput { device_id, - input, + event, is_synthetic, } => KeyboardInput { device_id: *device_id, - input: *input, + event: event.clone(), is_synthetic: *is_synthetic, }, @@ -456,15 +467,15 @@ impl<'a> WindowEvent<'a> { DroppedFile(file) => Some(DroppedFile(file)), HoveredFile(file) => Some(HoveredFile(file)), HoveredFileCancelled => Some(HoveredFileCancelled), - ReceivedCharacter(c) => Some(ReceivedCharacter(c)), + ReceivedImeText(s) => Some(ReceivedImeText(s)), Focused(focused) => Some(Focused(focused)), KeyboardInput { device_id, - input, + event, is_synthetic, } => Some(KeyboardInput { device_id, - input, + event, is_synthetic, }), ModifiersChanged(modifiers) => Some(ModifiersChanged(modifiers)), @@ -593,38 +604,82 @@ pub enum DeviceEvent { state: ElementState, }, - Key(KeyboardInput), + Key(RawKeyEvent), Text { codepoint: char, }, } -/// Describes a keyboard input event. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +/// Describes a keyboard input as a raw device event. +/// +/// Note that holding down a key may produce repeated `RawKeyEvent`s. The +/// operating system doesn't provide information whether such an event is a +/// repeat or the initial keypress. An application may emulate this by, for +/// example keeping a Map/Set of pressed keys and determining whether a keypress +/// corresponds to an already pressed key. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct KeyboardInput { - /// Identifies the physical key pressed - /// - /// This should not change if the user adjusts the host's keyboard map. Use when the physical location of the - /// key is more important than the key's host GUI semantics, such as for movement controls in a first-person - /// game. - pub scancode: ScanCode, - +pub struct RawKeyEvent { + pub physical_key: keyboard::KeyCode, pub state: ElementState, +} + +/// Describes a keyboard input targeting a window. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct KeyEvent { + /// Represents the position of a key independent of the currently active layout. + /// + /// It also uniquely identifies the physical key (i.e. it's mostly synonymous with a scancode). + /// The most prevalent use case for this is games. For example the default keys for the player + /// to move around might be the W, A, S, and D keys on a US layout. The position of these keys + /// is more important than their label, so they should map to Z, Q, S, and D on an "AZERTY" + /// layout. (This value is `KeyCode::KeyW` for the Z key on an AZERTY layout.) + /// + /// Note that `Fn` and `FnLock` key events are not guaranteed to be emitted by `winit`. These + /// keys are usually handled at the hardware or OS level. + pub physical_key: keyboard::KeyCode, - /// Identifies the semantic meaning of the key + /// This value is affected by all modifiers except Ctrl. + /// + /// This has two use cases: + /// - Allows querying whether the current input is a Dead key. + /// - Allows handling key-bindings on platforms which don't + /// support [`key_without_modifiers`]. + /// + /// ## Platform-specific + /// - **Web:** Dead keys might be reported as the real key instead + /// of `Dead` depending on the browser/OS. /// - /// Use when the semantics of the key are more important than the physical location of the key, such as when - /// implementing appropriate behavior for "page up." - pub virtual_keycode: Option, + /// [`key_without_modifiers`]: crate::platform::modifier_supplement::KeyEventExtModifierSupplement::key_without_modifiers + pub logical_key: keyboard::Key<'static>, - /// Modifier keys active at the time of this input. + /// Contains the text produced by this keypress. + /// + /// In most cases this is identical to the content + /// of the `Character` variant of `logical_key`. + /// However, on Windows when a dead key was pressed earlier + /// but cannot be combined with the character from this + /// keypress, the produced text will consist of two characters: + /// the dead-key-character followed by the character resulting + /// from this keypress. + /// + /// An additional difference from `logical_key` is that + /// this field stores the text representation of any key + /// that has such a representation. For example when + /// `logical_key` is `Key::Enter`, this field is `Some("\r")`. /// - /// This is tracked internally to avoid tracking errors arising from modifier key state changes when events from - /// this device are not being delivered to the application, e.g. due to keyboard focus being elsewhere. - #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"] - pub modifiers: ModifiersState, + /// This is `None` if the current keypress cannot + /// be interpreted as text. + /// + /// See also: `text_with_all_modifiers()` + pub text: Option<&'static str>, + + pub location: keyboard::KeyLocation, + pub state: ElementState, + pub repeat: bool, + + pub(crate) platform_specific: platform_impl::KeyEventExtra, } /// Describes touch-screen input state. @@ -725,9 +780,6 @@ impl Force { } } -/// Hardware-dependent keyboard scan code. -pub type ScanCode = u32; - /// Identifier for a specific analog axis on some device. pub type AxisId = u32; @@ -770,303 +822,3 @@ pub enum MouseScrollDelta { /// platform. PixelDelta(PhysicalPosition), } - -/// Symbolic name for a keyboard key. -#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)] -#[repr(u32)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum VirtualKeyCode { - /// The '1' key over the letters. - Key1, - /// The '2' key over the letters. - Key2, - /// The '3' key over the letters. - Key3, - /// The '4' key over the letters. - Key4, - /// The '5' key over the letters. - Key5, - /// The '6' key over the letters. - Key6, - /// The '7' key over the letters. - Key7, - /// The '8' key over the letters. - Key8, - /// The '9' key over the letters. - Key9, - /// The '0' key over the 'O' and 'P' keys. - Key0, - - A, - B, - C, - D, - E, - F, - G, - H, - I, - J, - K, - L, - M, - N, - O, - P, - Q, - R, - S, - T, - U, - V, - W, - X, - Y, - Z, - - /// The Escape key, next to F1. - Escape, - - F1, - F2, - F3, - F4, - F5, - F6, - F7, - F8, - F9, - F10, - F11, - F12, - F13, - F14, - F15, - F16, - F17, - F18, - F19, - F20, - F21, - F22, - F23, - F24, - - /// Print Screen/SysRq. - Snapshot, - /// Scroll Lock. - Scroll, - /// Pause/Break key, next to Scroll lock. - Pause, - - /// `Insert`, next to Backspace. - Insert, - Home, - Delete, - End, - PageDown, - PageUp, - - Left, - Up, - Right, - Down, - - /// The Backspace key, right over Enter. - // TODO: rename - Back, - /// The Enter key. - Return, - /// The space bar. - Space, - - /// The "Compose" key on Linux. - Compose, - - Caret, - - Numlock, - Numpad0, - Numpad1, - Numpad2, - Numpad3, - Numpad4, - Numpad5, - Numpad6, - Numpad7, - Numpad8, - Numpad9, - NumpadAdd, - NumpadDivide, - NumpadDecimal, - NumpadComma, - NumpadEnter, - NumpadEquals, - NumpadMultiply, - NumpadSubtract, - - AbntC1, - AbntC2, - Apostrophe, - Apps, - Asterisk, - At, - Ax, - Backslash, - Calculator, - Capital, - Colon, - Comma, - Convert, - Equals, - Grave, - Kana, - Kanji, - LAlt, - LBracket, - LControl, - LShift, - LWin, - Mail, - MediaSelect, - MediaStop, - Minus, - Mute, - MyComputer, - // also called "Next" - NavigateForward, - // also called "Prior" - NavigateBackward, - NextTrack, - NoConvert, - OEM102, - Period, - PlayPause, - Plus, - Power, - PrevTrack, - RAlt, - RBracket, - RControl, - RShift, - RWin, - Semicolon, - Slash, - Sleep, - Stop, - Sysrq, - Tab, - Underline, - Unlabeled, - VolumeDown, - VolumeUp, - Wake, - WebBack, - WebFavorites, - WebForward, - WebHome, - WebRefresh, - WebSearch, - WebStop, - Yen, - Copy, - Paste, - Cut, -} - -impl ModifiersState { - /// Returns `true` if the shift key is pressed. - pub fn shift(&self) -> bool { - self.intersects(Self::SHIFT) - } - /// Returns `true` if the control key is pressed. - pub fn ctrl(&self) -> bool { - self.intersects(Self::CTRL) - } - /// Returns `true` if the alt key is pressed. - pub fn alt(&self) -> bool { - self.intersects(Self::ALT) - } - /// Returns `true` if the logo key is pressed. - pub fn logo(&self) -> bool { - self.intersects(Self::LOGO) - } -} - -bitflags! { - /// Represents the current state of the keyboard modifiers - /// - /// Each flag represents a modifier and is set if this modifier is active. - #[derive(Default)] - pub struct ModifiersState: u32 { - // left and right modifiers are currently commented out, but we should be able to support - // them in a future release - /// The "shift" key. - const SHIFT = 0b100; - // const LSHIFT = 0b010; - // const RSHIFT = 0b001; - /// The "control" key. - const CTRL = 0b100 << 3; - // const LCTRL = 0b010 << 3; - // const RCTRL = 0b001 << 3; - /// The "alt" key. - const ALT = 0b100 << 6; - // const LALT = 0b010 << 6; - // const RALT = 0b001 << 6; - /// This is the "windows" key on PC and "command" key on Mac. - const LOGO = 0b100 << 9; - // const LLOGO = 0b010 << 9; - // const RLOGO = 0b001 << 9; - } -} - -#[cfg(feature = "serde")] -mod modifiers_serde { - use super::ModifiersState; - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - - #[derive(Default, Serialize, Deserialize)] - #[serde(default)] - #[serde(rename = "ModifiersState")] - pub struct ModifiersStateSerialize { - pub shift: bool, - pub ctrl: bool, - pub alt: bool, - pub logo: bool, - } - - impl Serialize for ModifiersState { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let s = ModifiersStateSerialize { - shift: self.shift(), - ctrl: self.ctrl(), - alt: self.alt(), - logo: self.logo(), - }; - s.serialize(serializer) - } - } - - impl<'de> Deserialize<'de> for ModifiersState { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let ModifiersStateSerialize { - shift, - ctrl, - alt, - logo, - } = ModifiersStateSerialize::deserialize(deserializer)?; - let mut m = ModifiersState::empty(); - m.set(ModifiersState::SHIFT, shift); - m.set(ModifiersState::CTRL, ctrl); - m.set(ModifiersState::ALT, alt); - m.set(ModifiersState::LOGO, logo); - Ok(m) - } - } -} diff --git a/src/keyboard.rs b/src/keyboard.rs new file mode 100644 index 0000000000..28983cfaf4 --- /dev/null +++ b/src/keyboard.rs @@ -0,0 +1,1417 @@ +//! Types related to the keyboard. + +// This file contains a substantial portion of the UI Events Specification by the W3C. In +// particular, the variant names within `Key` and `KeyCode` and their documentation are modified +// versions of contents of the aforementioned specification. +// +// The original documents are: +// +// ### For `Key` +// UI Events KeyboardEvent key Values +// https://www.w3.org/TR/2017/CR-uievents-key-20170601/ +// Copyright © 2017 W3C® (MIT, ERCIM, Keio, Beihang). +// +// ### For `KeyCode` +// UI Events KeyboardEvent code Values +// https://www.w3.org/TR/2017/CR-uievents-code-20170601/ +// Copyright © 2017 W3C® (MIT, ERCIM, Keio, Beihang). +// +// These documents were used under the terms of the following license. This W3C license as well as +// the W3C short notice apply to the `Key` and `KeyCode` enums and their variants and the +// documentation attached to their variants. + +// --------- BEGGINING OF W3C LICENSE -------------------------------------------------------------- +// +// License +// +// By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, +// and will comply with the following terms and conditions. +// +// Permission to copy, modify, and distribute this work, with or without modification, for any +// purpose and without fee or royalty is hereby granted, provided that you include the following on +// ALL copies of the work or portions thereof, including modifications: +// +// - The full text of this NOTICE in a location viewable to users of the redistributed or derivative +// work. +// - Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none +// exist, the W3C Software and Document Short Notice should be included. +// - Notice of any changes or modifications, through a copyright statement on the new code or +// document such as "This software or document includes material copied from or derived from +// [title and URI of the W3C document]. Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)." +// +// Disclaimers +// +// THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR +// ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD +// PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. +// +// COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES +// ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. +// +// The name and trademarks of copyright holders may NOT be used in advertising or publicity +// pertaining to the work without specific, written prior permission. Title to copyright in this +// work will at all times remain with copyright holders. +// +// --------- END OF W3C LICENSE -------------------------------------------------------------------- + +// --------- BEGGINING OF W3C SHORT NOTICE --------------------------------------------------------- +// +// winit: https://github.com/rust-windowing/winit +// +// Copyright © 2021 World Wide Web Consortium, (Massachusetts Institute of Technology, European +// Research Consortium for Informatics and Mathematics, Keio University, Beihang). All Rights +// Reserved. This work is distributed under the W3C® Software License [1] in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// [1] http://www.w3.org/Consortium/Legal/copyright-software +// +// --------- END OF W3C SHORT NOTICE --------------------------------------------------------------- + +use nameof::name_of; + +impl ModifiersState { + /// Returns `true` if the shift key is pressed. + pub fn shift_key(&self) -> bool { + self.intersects(Self::SHIFT) + } + /// Returns `true` if the control key is pressed. + pub fn control_key(&self) -> bool { + self.intersects(Self::CONTROL) + } + /// Returns `true` if the alt key is pressed. + pub fn alt_key(&self) -> bool { + self.intersects(Self::ALT) + } + /// Returns `true` if the super key is pressed. + pub fn super_key(&self) -> bool { + self.intersects(Self::SUPER) + } +} + +bitflags! { + /// Represents the current state of the keyboard modifiers + /// + /// Each flag represents a modifier and is set if this modifier is active. + #[derive(Default)] + pub struct ModifiersState: u32 { + // left and right modifiers are currently commented out, but we should be able to support + // them in a future release + /// The "shift" key. + const SHIFT = 0b100 << 0; + // const LSHIFT = 0b010 << 0; + // const RSHIFT = 0b001 << 0; + /// The "control" key. + const CONTROL = 0b100 << 3; + // const LCTRL = 0b010 << 3; + // const RCTRL = 0b001 << 3; + /// The "alt" key. + const ALT = 0b100 << 6; + // const LALT = 0b010 << 6; + // const RALT = 0b001 << 6; + /// This is the "windows" key on PC and "command" key on Mac. + const SUPER = 0b100 << 9; + // const LSUPER = 0b010 << 9; + // const RSUPER = 0b001 << 9; + } +} + +#[cfg(feature = "serde")] +mod modifiers_serde { + use super::ModifiersState; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + #[derive(Default, Serialize, Deserialize)] + #[serde(default)] + #[serde(rename = "ModifiersState")] + pub struct ModifiersStateSerialize { + pub shift_key: bool, + pub control_key: bool, + pub alt_key: bool, + pub super_key: bool, + } + + impl Serialize for ModifiersState { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let s = ModifiersStateSerialize { + shift_key: self.shift_key(), + control_key: self.control_key(), + alt_key: self.alt_key(), + super_key: self.super_key(), + }; + s.serialize(serializer) + } + } + + impl<'de> Deserialize<'de> for ModifiersState { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let ModifiersStateSerialize { + shift_key, + control_key, + alt_key, + super_key, + } = ModifiersStateSerialize::deserialize(deserializer)?; + let mut m = ModifiersState::empty(); + m.set(ModifiersState::SHIFT, shift_key); + m.set(ModifiersState::CONTROL, control_key); + m.set(ModifiersState::ALT, alt_key); + m.set(ModifiersState::SUPER, super_key); + Ok(m) + } + } +} + +/// Contains the platform-native physical key identifier (aka scancode) +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum NativeKeyCode { + Unidentified, + Windows(u16), + MacOS(u32), + XKB(u32), +} +impl std::fmt::Debug for NativeKeyCode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use NativeKeyCode::{MacOS, Unidentified, Windows, XKB}; + let mut debug_tuple; + match self { + Unidentified => { + debug_tuple = f.debug_tuple(name_of!(Unidentified)); + } + Windows(v) => { + debug_tuple = f.debug_tuple(name_of!(Windows)); + debug_tuple.field(&format_args!("0x{:04X}", v)); + } + MacOS(v) => { + debug_tuple = f.debug_tuple(name_of!(MacOS)); + debug_tuple.field(v); + } + XKB(v) => { + debug_tuple = f.debug_tuple(name_of!(XKB)); + debug_tuple.field(v); + } + } + debug_tuple.finish() + } +} + +/// Represents the location of a physical key. +/// +/// This mostly conforms to the UI Events Specification's [`KeyboardEvent.code`] with a few +/// exceptions: +/// - The keys that the specification calls "MetaLeft" and "MetaRight" are named "SuperLeft" and +/// "SuperRight" here. +/// - The key that the specification calls "Super" is reported as `Unidentified` here. +/// - The `Unidentified` variant here, can still identifiy a key through it's `NativeKeyCode`. +/// +/// [`KeyboardEvent.code`]: https://w3c.github.io/uievents-code/#code-value-tables +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum KeyCode { + /// This variant is used when the key cannot be translated to any + /// other variant. + /// + /// The native scancode is provided (if available) in order + /// to allow the user to specify keybindings for keys which + /// are not defined by this API. + Unidentified(NativeKeyCode), + /// ` on a US keyboard. This is the 半角/全角/漢字 + /// (hankaku/zenkaku/kanji) key on Japanese keyboards + Backquote, + /// Used for both the US \\ (on the 101-key layout) and also for the key + /// located between the " and Enter keys on row C of the 102-, + /// 104- and 106-key layouts. + /// Labeled # on a UK (102) keyboard. + Backslash, + /// [ on a US keyboard. + BracketLeft, + /// ] on a US keyboard. + BracketRight, + /// , on a US keyboard. + Comma, + /// 0 on a US keyboard. + Digit0, + /// 1 on a US keyboard. + Digit1, + /// 2 on a US keyboard. + Digit2, + /// 3 on a US keyboard. + Digit3, + /// 4 on a US keyboard. + Digit4, + /// 5 on a US keyboard. + Digit5, + /// 6 on a US keyboard. + Digit6, + /// 7 on a US keyboard. + Digit7, + /// 8 on a US keyboard. + Digit8, + /// 9 on a US keyboard. + Digit9, + /// = on a US keyboard. + Equal, + /// Located between the left Shift and Z keys. + /// Labeled \\ on a UK keyboard. + IntlBackslash, + /// Located between the / and right Shift keys. + /// Labeled \\ (ro) on a Japanese keyboard. + IntlRo, + /// Located between the = and Backspace keys. + /// Labeled ¥ (yen) on a Japanese keyboard. \\ on a + /// Russian keyboard. + IntlYen, + /// a on a US keyboard. + /// Labeled q on an AZERTY (e.g., French) keyboard. + KeyA, + /// b on a US keyboard. + KeyB, + /// c on a US keyboard. + KeyC, + /// d on a US keyboard. + KeyD, + /// e on a US keyboard. + KeyE, + /// f on a US keyboard. + KeyF, + /// g on a US keyboard. + KeyG, + /// h on a US keyboard. + KeyH, + /// i on a US keyboard. + KeyI, + /// j on a US keyboard. + KeyJ, + /// k on a US keyboard. + KeyK, + /// l on a US keyboard. + KeyL, + /// m on a US keyboard. + KeyM, + /// n on a US keyboard. + KeyN, + /// o on a US keyboard. + KeyO, + /// p on a US keyboard. + KeyP, + /// q on a US keyboard. + /// Labeled a on an AZERTY (e.g., French) keyboard. + KeyQ, + /// r on a US keyboard. + KeyR, + /// s on a US keyboard. + KeyS, + /// t on a US keyboard. + KeyT, + /// u on a US keyboard. + KeyU, + /// v on a US keyboard. + KeyV, + /// w on a US keyboard. + /// Labeled z on an AZERTY (e.g., French) keyboard. + KeyW, + /// x on a US keyboard. + KeyX, + /// y on a US keyboard. + /// Labeled z on a QWERTZ (e.g., German) keyboard. + KeyY, + /// z on a US keyboard. + /// Labeled w on an AZERTY (e.g., French) keyboard, and y on a + /// QWERTZ (e.g., German) keyboard. + KeyZ, + /// - on a US keyboard. + Minus, + /// . on a US keyboard. + Period, + /// ' on a US keyboard. + Quote, + /// ; on a US keyboard. + Semicolon, + /// / on a US keyboard. + Slash, + /// Alt, Option, or . + AltLeft, + /// Alt, Option, or . + /// This is labeled AltGr on many keyboard layouts. + AltRight, + /// Backspace or . + /// Labeled Delete on Apple keyboards. + Backspace, + /// CapsLock or + CapsLock, + /// The application context menu key, which is typically found between the right + /// Super key and the right Control key. + ContextMenu, + /// Control or + ControlLeft, + /// Control or + ControlRight, + /// Enter or . Labeled Return on Apple keyboards. + Enter, + /// The Windows, , Command, or other OS symbol key. + SuperLeft, + /// The Windows, , Command, or other OS symbol key. + SuperRight, + /// Shift or + ShiftLeft, + /// Shift or + ShiftRight, + ///   (space) + Space, + /// Tab or + Tab, + /// Japanese: (henkan) + Convert, + /// Japanese: カタカナ/ひらがな/ローマ字 (katakana/hiragana/romaji) + KanaMode, + /// Korean: HangulMode 한/영 (han/yeong) + /// + /// Japanese (Mac keyboard): (kana) + Lang1, + /// Korean: Hanja (hanja) + /// + /// Japanese (Mac keyboard): (eisu) + Lang2, + /// Japanese (word-processing keyboard): Katakana + Lang3, + /// Japanese (word-processing keyboard): Hiragana + Lang4, + /// Japanese (word-processing keyboard): Zenkaku/Hankaku + Lang5, + /// Japanese: 無変換 (muhenkan) + NonConvert, + /// . The forward delete key. + /// Note that on Apple keyboards, the key labelled Delete on the main part of + /// the keyboard is encoded as [`Backspace`]. + /// + /// [`Backspace`]: Self::Backspace + Delete, + /// Page Down, End, or + End, + /// Help. Not present on standard PC keyboards. + Help, + /// Home or + Home, + /// Insert or Ins. Not present on Apple keyboards. + Insert, + /// Page Down, PgDn, or + PageDown, + /// Page Up, PgUp, or + PageUp, + /// + ArrowDown, + /// + ArrowLeft, + /// + ArrowRight, + /// + ArrowUp, + /// On the Mac, this is used for the numpad Clear key. + NumLock, + /// 0 Ins on a keyboard. 0 on a phone or remote control + Numpad0, + /// 1 End on a keyboard. 1 or 1 QZ on a phone or remote control + Numpad1, + /// 2 ↓ on a keyboard. 2 ABC on a phone or remote control + Numpad2, + /// 3 PgDn on a keyboard. 3 DEF on a phone or remote control + Numpad3, + /// 4 ← on a keyboard. 4 GHI on a phone or remote control + Numpad4, + /// 5 on a keyboard. 5 JKL on a phone or remote control + Numpad5, + /// 6 → on a keyboard. 6 MNO on a phone or remote control + Numpad6, + /// 7 Home on a keyboard. 7 PQRS or 7 PRS on a phone + /// or remote control + Numpad7, + /// 8 ↑ on a keyboard. 8 TUV on a phone or remote control + Numpad8, + /// 9 PgUp on a keyboard. 9 WXYZ or 9 WXY on a phone + /// or remote control + Numpad9, + /// + + NumpadAdd, + /// Found on the Microsoft Natural Keyboard. + NumpadBackspace, + /// C or A (All Clear). Also for use with numpads that have a + /// Clear key that is separate from the NumLock key. On the Mac, the + /// numpad Clear key is encoded as [`NumLock`]. + /// + /// [`NumLock`]: Self::NumLock + NumpadClear, + /// C (Clear Entry) + NumpadClearEntry, + /// , (thousands separator). For locales where the thousands separator + /// is a "." (e.g., Brazil), this key may generate a .. + NumpadComma, + /// . Del. For locales where the decimal separator is "," (e.g., + /// Brazil), this key may generate a ,. + NumpadDecimal, + /// / + NumpadDivide, + NumpadEnter, + /// = + NumpadEqual, + /// # on a phone or remote control device. This key is typically found + /// below the 9 key and to the right of the 0 key. + NumpadHash, + /// M Add current entry to the value stored in memory. + NumpadMemoryAdd, + /// M Clear the value stored in memory. + NumpadMemoryClear, + /// M Replace the current entry with the value stored in memory. + NumpadMemoryRecall, + /// M Replace the value stored in memory with the current entry. + NumpadMemoryStore, + /// M Subtract current entry from the value stored in memory. + NumpadMemorySubtract, + /// * on a keyboard. For use with numpads that provide mathematical + /// operations (+, - * and /). + /// + /// Use `NumpadStar` for the * key on phones and remote controls. + NumpadMultiply, + /// ( Found on the Microsoft Natural Keyboard. + NumpadParenLeft, + /// ) Found on the Microsoft Natural Keyboard. + NumpadParenRight, + /// * on a phone or remote control device. + /// + /// This key is typically found below the 7 key and to the left of + /// the 0 key. + /// + /// Use "NumpadMultiply" for the * key on + /// numeric keypads. + NumpadStar, + /// - + NumpadSubtract, + /// Esc or + Escape, + /// Fn This is typically a hardware key that does not generate a separate code. + Fn, + /// FLock or FnLock. Function Lock key. Found on the Microsoft + /// Natural Keyboard. + FnLock, + /// PrtScr SysRq or Print Screen + PrintScreen, + /// Scroll Lock + ScrollLock, + /// Pause Break + Pause, + /// Some laptops place this key to the left of the key. + BrowserBack, + BrowserFavorites, + /// Some laptops place this key to the right of the key. + BrowserForward, + BrowserHome, + BrowserRefresh, + BrowserSearch, + BrowserStop, + /// Eject or . This key is placed in the function section on some Apple + /// keyboards. + Eject, + /// Sometimes labelled My Computer on the keyboard + LaunchApp1, + /// Sometimes labelled Calculator on the keyboard + LaunchApp2, + LaunchMail, + MediaPlayPause, + MediaSelect, + MediaStop, + MediaTrackNext, + MediaTrackPrevious, + /// This key is placed in the function section on some Apple keyboards, replacing the + /// Eject key. + Power, + Sleep, + AudioVolumeDown, + AudioVolumeMute, + AudioVolumeUp, + WakeUp, + Hyper, + Turbo, + Abort, + Resume, + Suspend, + /// Found on Sun’s USB keyboard. + Again, + /// Found on Sun’s USB keyboard. + Copy, + /// Found on Sun’s USB keyboard. + Cut, + /// Found on Sun’s USB keyboard. + Find, + /// Found on Sun’s USB keyboard. + Open, + /// Found on Sun’s USB keyboard. + Paste, + /// Found on Sun’s USB keyboard. + Props, + /// Found on Sun’s USB keyboard. + Select, + /// Found on Sun’s USB keyboard. + Undo, + /// Use for dedicated ひらがな key found on some Japanese word processing keyboards. + Hiragana, + /// Use for dedicated カタカナ key found on some Japanese word processing keyboards. + Katakana, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F1, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F2, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F3, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F4, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F5, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F6, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F7, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F8, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F9, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F10, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F11, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F12, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F13, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F14, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F15, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F16, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F17, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F18, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F19, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F20, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F21, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F22, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F23, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F24, + /// General-purpose function key. + F25, + /// General-purpose function key. + F26, + /// General-purpose function key. + F27, + /// General-purpose function key. + F28, + /// General-purpose function key. + F29, + /// General-purpose function key. + F30, + /// General-purpose function key. + F31, + /// General-purpose function key. + F32, + /// General-purpose function key. + F33, + /// General-purpose function key. + F34, + /// General-purpose function key. + F35, +} + +/// Key represents the meaning of a keypress. +/// +/// This mostly conforms to the UI Events Specification's [`KeyboardEvent.key`] with a few +/// exceptions: +/// - The `Super` variant here, is named `Meta` in the aforementioned specification. (There's +/// another key which the specification calls `Super`. That does not exist here.) +/// - The `Space` variant here, can be identified by the character it generates in the +/// specificaiton. +/// - The `Unidentified` variant here, can still identifiy a key through it's `NativeKeyCode`. +/// - The `Dead` variant here, can specify the character which is inserted when pressing the +/// dead-key twice. +/// +/// [`KeyboardEvent.key`]: https://w3c.github.io/uievents-key/ +#[non_exhaustive] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum Key<'a> { + /// A key string that corresponds to the character typed by the user, taking into account the + /// user’s current locale setting, and any system-level keyboard mapping overrides that are in + /// effect. + Character(&'a str), + + /// This variant is used when the key cannot be translated to any other variant. + /// + /// The native scancode is provided (if available) in order to allow the user to specify + /// keybindings for keys which are not defined by this API. + Unidentified(NativeKeyCode), + + /// Contains the text representation of the dead-key when available. + /// + /// ## Platform-specific + /// - **Web:** Always contains `None` + Dead(Option), + + /// The `Alt` (Alternative) key. + /// + /// This key enables the alternate modifier function for interpreting concurrent or subsequent + /// keyboard input. This key value is also used for the Apple Option key. + Alt, + /// The Alternate Graphics (AltGr or AltGraph) key. + /// + /// This key is used enable the ISO Level 3 shift modifier (the standard `Shift` key is the + /// level 2 modifier). + AltGraph, + /// The `Caps Lock` (Capital) key. + /// + /// Toggle capital character lock function for interpreting subsequent keyboard input event. + CapsLock, + /// The `Control` or `Ctrl` key. + /// + /// Used to enable control modifier function for interpreting concurrent or subsequent keyboard + /// input. + Control, + /// The Function switch `Fn` key. Activating this key simultaneously with another key changes + /// that key’s value to an alternate character or function. This key is often handled directly + /// in the keyboard hardware and does not usually generate key events. + Fn, + /// The Function-Lock (`FnLock` or `F-Lock`) key. Activating this key switches the mode of the + /// keyboard to changes some keys' values to an alternate character or function. This key is + /// often handled directly in the keyboard hardware and does not usually generate key events. + FnLock, + /// The `NumLock` or Number Lock key. Used to toggle numpad mode function for interpreting + /// subsequent keyboard input. + NumLock, + /// Toggle between scrolling and cursor movement modes. + ScrollLock, + /// Used to enable shift modifier function for interpreting concurrent or subsequent keyboard + /// input. + Shift, + /// The Symbol modifier key (used on some virtual keyboards). + Symbol, + SymbolLock, + Hyper, + /// Used to enable "super" modifier function for interpreting concurrent or subsequent keyboard + /// input. This key value is used for the "Windows Logo" key and the Apple `Command` or `⌘` key. + /// + /// Note: In some contexts (e.g. the Web) this is referred to as the "Meta" key. + Super, + /// The `Enter` or `↵` key. Used to activate current selection or accept current input. This key + /// value is also used for the `Return` (Macintosh numpad) key. This key value is also used for + /// the Android `KEYCODE_DPAD_CENTER`. + Enter, + /// The Horizontal Tabulation `Tab` key. + Tab, + /// Used in text to insert a space between words. Usually located below the character keys. + Space, + /// Navigate or traverse downward. (`KEYCODE_DPAD_DOWN`) + ArrowDown, + /// Navigate or traverse leftward. (`KEYCODE_DPAD_LEFT`) + ArrowLeft, + /// Navigate or traverse rightward. (`KEYCODE_DPAD_RIGHT`) + ArrowRight, + /// Navigate or traverse upward. (`KEYCODE_DPAD_UP`) + ArrowUp, + /// The End key, used with keyboard entry to go to the end of content (`KEYCODE_MOVE_END`). + End, + /// The Home key, used with keyboard entry, to go to start of content (`KEYCODE_MOVE_HOME`). + /// For the mobile phone `Home` key (which goes to the phone’s main screen), use [`GoHome`]. + /// + /// [`GoHome`]: Self::GoHome + Home, + /// Scroll down or display next page of content. + PageDown, + /// Scroll up or display previous page of content. + PageUp, + /// Used to remove the character to the left of the cursor. This key value is also used for + /// the key labeled `Delete` on MacOS keyboards. + Backspace, + /// Remove the currently selected input. + Clear, + /// Copy the current selection. (`APPCOMMAND_COPY`) + Copy, + /// The Cursor Select key. + CrSel, + /// Cut the current selection. (`APPCOMMAND_CUT`) + Cut, + /// Used to delete the character to the right of the cursor. This key value is also used for the + /// key labeled `Delete` on MacOS keyboards when `Fn` is active. + Delete, + /// The Erase to End of Field key. This key deletes all characters from the current cursor + /// position to the end of the current field. + EraseEof, + /// The Extend Selection (Exsel) key. + ExSel, + /// Toggle between text modes for insertion or overtyping. + /// (`KEYCODE_INSERT`) + Insert, + /// The Paste key. (`APPCOMMAND_PASTE`) + Paste, + /// Redo the last action. (`APPCOMMAND_REDO`) + Redo, + /// Undo the last action. (`APPCOMMAND_UNDO`) + Undo, + /// The Accept (Commit, OK) key. Accept current option or input method sequence conversion. + Accept, + /// Redo or repeat an action. + Again, + /// The Attention (Attn) key. + Attn, + Cancel, + /// Show the application’s context menu. + /// This key is commonly found between the right `Super` key and the right `Control` key. + ContextMenu, + /// The `Esc` key. This key was originally used to initiate an escape sequence, but is + /// now more generally used to exit or "escape" the current context, such as closing a dialog + /// or exiting full screen mode. + Escape, + Execute, + /// Open the Find dialog. (`APPCOMMAND_FIND`) + Find, + /// Open a help dialog or toggle display of help information. (`APPCOMMAND_HELP`, + /// `KEYCODE_HELP`) + Help, + /// Pause the current state or application (as appropriate). + /// + /// Note: Do not use this value for the `Pause` button on media controllers. Use `"MediaPause"` + /// instead. + Pause, + /// Play or resume the current state or application (as appropriate). + /// + /// Note: Do not use this value for the `Play` button on media controllers. Use `"MediaPlay"` + /// instead. + Play, + /// The properties (Props) key. + Props, + Select, + /// The ZoomIn key. (`KEYCODE_ZOOM_IN`) + ZoomIn, + /// The ZoomOut key. (`KEYCODE_ZOOM_OUT`) + ZoomOut, + /// The Brightness Down key. Typically controls the display brightness. + /// (`KEYCODE_BRIGHTNESS_DOWN`) + BrightnessDown, + /// The Brightness Up key. Typically controls the display brightness. (`KEYCODE_BRIGHTNESS_UP`) + BrightnessUp, + /// Toggle removable media to eject (open) and insert (close) state. (`KEYCODE_MEDIA_EJECT`) + Eject, + LogOff, + /// Toggle power state. (`KEYCODE_POWER`) + /// Note: Note: Some devices might not expose this key to the operating environment. + Power, + /// The `PowerOff` key. Sometime called `PowerDown`. + PowerOff, + /// Initiate print-screen function. + PrintScreen, + /// The Hibernate key. This key saves the current state of the computer to disk so that it can + /// be restored. The computer will then shutdown. + Hibernate, + /// The Standby key. This key turns off the display and places the computer into a low-power + /// mode without completely shutting down. It is sometimes labelled `Suspend` or `Sleep` key. + /// (`KEYCODE_SLEEP`) + Standby, + /// The WakeUp key. (`KEYCODE_WAKEUP`) + WakeUp, + /// Initate the multi-candidate mode. + AllCandidates, + Alphanumeric, + /// Initiate the Code Input mode to allow characters to be entered by + /// their code points. + CodeInput, + /// The Compose key, also known as "Multi_key" on the X Window System. This key acts in a + /// manner similar to a dead key, triggering a mode where subsequent key presses are combined to + /// produce a different character. + Compose, + /// Convert the current input method sequence. + Convert, + /// The Final Mode `Final` key used on some Asian keyboards, to enable the final mode for IMEs. + FinalMode, + /// Switch to the first character group. (ISO/IEC 9995) + GroupFirst, + /// Switch to the last character group. (ISO/IEC 9995) + GroupLast, + /// Switch to the next character group. (ISO/IEC 9995) + GroupNext, + /// Switch to the previous character group. (ISO/IEC 9995) + GroupPrevious, + /// Toggle between or cycle through input modes of IMEs. + ModeChange, + NextCandidate, + /// Accept current input method sequence without + /// conversion in IMEs. + NonConvert, + PreviousCandidate, + Process, + SingleCandidate, + /// Toggle between Hangul and English modes. + HangulMode, + HanjaMode, + JunjaMode, + /// The Eisu key. This key may close the IME, but its purpose is defined by the current IME. + /// (`KEYCODE_EISU`) + Eisu, + /// The (Half-Width) Characters key. + Hankaku, + /// The Hiragana (Japanese Kana characters) key. + Hiragana, + /// The Hiragana/Katakana toggle key. (`KEYCODE_KATAKANA_HIRAGANA`) + HiraganaKatakana, + /// The Kana Mode (Kana Lock) key. This key is used to enter hiragana mode (typically from + /// romaji mode). + KanaMode, + /// The Kanji (Japanese name for ideographic characters of Chinese origin) Mode key. This key is + /// typically used to switch to a hiragana keyboard for the purpose of converting input into + /// kanji. (`KEYCODE_KANA`) + KanjiMode, + /// The Katakana (Japanese Kana characters) key. + Katakana, + /// The Roman characters function key. + Romaji, + /// The Zenkaku (Full-Width) Characters key. + Zenkaku, + /// The Zenkaku/Hankaku (full-width/half-width) toggle key. (`KEYCODE_ZENKAKU_HANKAKU`) + ZenkakuHankaku, + /// General purpose virtual function key, as index 1. + Soft1, + /// General purpose virtual function key, as index 2. + Soft2, + /// General purpose virtual function key, as index 3. + Soft3, + /// General purpose virtual function key, as index 4. + Soft4, + /// Select next (numerically or logically) lower channel. (`APPCOMMAND_MEDIA_CHANNEL_DOWN`, + /// `KEYCODE_CHANNEL_DOWN`) + ChannelDown, + /// Select next (numerically or logically) higher channel. (`APPCOMMAND_MEDIA_CHANNEL_UP`, + /// `KEYCODE_CHANNEL_UP`) + ChannelUp, + /// Close the current document or message (Note: This doesn’t close the application). + /// (`APPCOMMAND_CLOSE`) + Close, + /// Open an editor to forward the current message. (`APPCOMMAND_FORWARD_MAIL`) + MailForward, + /// Open an editor to reply to the current message. (`APPCOMMAND_REPLY_TO_MAIL`) + MailReply, + /// Send the current message. (`APPCOMMAND_SEND_MAIL`) + MailSend, + /// Close the current media, for example to close a CD or DVD tray. (`KEYCODE_MEDIA_CLOSE`) + MediaClose, + /// Initiate or continue forward playback at faster than normal speed, or increase speed if + /// already fast forwarding. (`APPCOMMAND_MEDIA_FAST_FORWARD`, `KEYCODE_MEDIA_FAST_FORWARD`) + MediaFastForward, + /// Pause the currently playing media. (`APPCOMMAND_MEDIA_PAUSE`, `KEYCODE_MEDIA_PAUSE`) + /// + /// Note: Media controller devices should use this value rather than `"Pause"` for their pause + /// keys. + MediaPause, + /// Initiate or continue media playback at normal speed, if not currently playing at normal + /// speed. (`APPCOMMAND_MEDIA_PLAY`, `KEYCODE_MEDIA_PLAY`) + MediaPlay, + /// Toggle media between play and pause states. (`APPCOMMAND_MEDIA_PLAY_PAUSE`, + /// `KEYCODE_MEDIA_PLAY_PAUSE`) + MediaPlayPause, + /// Initiate or resume recording of currently selected media. (`APPCOMMAND_MEDIA_RECORD`, + /// `KEYCODE_MEDIA_RECORD`) + MediaRecord, + /// Initiate or continue reverse playback at faster than normal speed, or increase speed if + /// already rewinding. (`APPCOMMAND_MEDIA_REWIND`, `KEYCODE_MEDIA_REWIND`) + MediaRewind, + /// Stop media playing, pausing, forwarding, rewinding, or recording, if not already stopped. + /// (`APPCOMMAND_MEDIA_STOP`, `KEYCODE_MEDIA_STOP`) + MediaStop, + /// Seek to next media or program track. (`APPCOMMAND_MEDIA_NEXTTRACK`, `KEYCODE_MEDIA_NEXT`) + MediaTrackNext, + /// Seek to previous media or program track. (`APPCOMMAND_MEDIA_PREVIOUSTRACK`, + /// `KEYCODE_MEDIA_PREVIOUS`) + MediaTrackPrevious, + /// Open a new document or message. (`APPCOMMAND_NEW`) + New, + /// Open an existing document or message. (`APPCOMMAND_OPEN`) + Open, + /// Print the current document or message. (`APPCOMMAND_PRINT`) + Print, + /// Save the current document or message. (`APPCOMMAND_SAVE`) + Save, + /// Spellcheck the current document or selection. (`APPCOMMAND_SPELL_CHECK`) + SpellCheck, + /// The `11` key found on media numpads that + /// have buttons from `1` ... `12`. + Key11, + /// The `12` key found on media numpads that + /// have buttons from `1` ... `12`. + Key12, + /// Adjust audio balance leftward. (`VK_AUDIO_BALANCE_LEFT`) + AudioBalanceLeft, + /// Adjust audio balance rightward. (`VK_AUDIO_BALANCE_RIGHT`) + AudioBalanceRight, + /// Decrease audio bass boost or cycle down through bass boost states. (`APPCOMMAND_BASS_DOWN`, + /// `VK_BASS_BOOST_DOWN`) + AudioBassBoostDown, + /// Toggle bass boost on/off. (`APPCOMMAND_BASS_BOOST`) + AudioBassBoostToggle, + /// Increase audio bass boost or cycle up through bass boost states. (`APPCOMMAND_BASS_UP`, + /// `VK_BASS_BOOST_UP`) + AudioBassBoostUp, + /// Adjust audio fader towards front. (`VK_FADER_FRONT`) + AudioFaderFront, + /// Adjust audio fader towards rear. (`VK_FADER_REAR`) + AudioFaderRear, + /// Advance surround audio mode to next available mode. (`VK_SURROUND_MODE_NEXT`) + AudioSurroundModeNext, + /// Decrease treble. (`APPCOMMAND_TREBLE_DOWN`) + AudioTrebleDown, + /// Increase treble. (`APPCOMMAND_TREBLE_UP`) + AudioTrebleUp, + /// Decrease audio volume. (`APPCOMMAND_VOLUME_DOWN`, `KEYCODE_VOLUME_DOWN`) + AudioVolumeDown, + /// Increase audio volume. (`APPCOMMAND_VOLUME_UP`, `KEYCODE_VOLUME_UP`) + AudioVolumeUp, + /// Toggle between muted state and prior volume level. (`APPCOMMAND_VOLUME_MUTE`, + /// `KEYCODE_VOLUME_MUTE`) + AudioVolumeMute, + /// Toggle the microphone on/off. (`APPCOMMAND_MIC_ON_OFF_TOGGLE`) + MicrophoneToggle, + /// Decrease microphone volume. (`APPCOMMAND_MICROPHONE_VOLUME_DOWN`) + MicrophoneVolumeDown, + /// Increase microphone volume. (`APPCOMMAND_MICROPHONE_VOLUME_UP`) + MicrophoneVolumeUp, + /// Mute the microphone. (`APPCOMMAND_MICROPHONE_VOLUME_MUTE`, `KEYCODE_MUTE`) + MicrophoneVolumeMute, + /// Show correction list when a word is incorrectly identified. (`APPCOMMAND_CORRECTION_LIST`) + SpeechCorrectionList, + /// Toggle between dictation mode and command/control mode. + /// (`APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE`) + SpeechInputToggle, + /// The first generic "LaunchApplication" key. This is commonly associated with launching "My + /// Computer", and may have a computer symbol on the key. (`APPCOMMAND_LAUNCH_APP1`) + LaunchApplication1, + /// The second generic "LaunchApplication" key. This is commonly associated with launching + /// "Calculator", and may have a calculator symbol on the key. (`APPCOMMAND_LAUNCH_APP2`, + /// `KEYCODE_CALCULATOR`) + LaunchApplication2, + /// The "Calendar" key. (`KEYCODE_CALENDAR`) + LaunchCalendar, + /// The "Contacts" key. (`KEYCODE_CONTACTS`) + LaunchContacts, + /// The "Mail" key. (`APPCOMMAND_LAUNCH_MAIL`) + LaunchMail, + /// The "Media Player" key. (`APPCOMMAND_LAUNCH_MEDIA_SELECT`) + LaunchMediaPlayer, + LaunchMusicPlayer, + LaunchPhone, + LaunchScreenSaver, + LaunchSpreadsheet, + LaunchWebBrowser, + LaunchWebCam, + LaunchWordProcessor, + /// Navigate to previous content or page in current history. (`APPCOMMAND_BROWSER_BACKWARD`) + BrowserBack, + /// Open the list of browser favorites. (`APPCOMMAND_BROWSER_FAVORITES`) + BrowserFavorites, + /// Navigate to next content or page in current history. (`APPCOMMAND_BROWSER_FORWARD`) + BrowserForward, + /// Go to the user’s preferred home page. (`APPCOMMAND_BROWSER_HOME`) + BrowserHome, + /// Refresh the current page or content. (`APPCOMMAND_BROWSER_REFRESH`) + BrowserRefresh, + /// Call up the user’s preferred search page. (`APPCOMMAND_BROWSER_SEARCH`) + BrowserSearch, + /// Stop loading the current page or content. (`APPCOMMAND_BROWSER_STOP`) + BrowserStop, + /// The Application switch key, which provides a list of recent apps to switch between. + /// (`KEYCODE_APP_SWITCH`) + AppSwitch, + /// The Call key. (`KEYCODE_CALL`) + Call, + /// The Camera key. (`KEYCODE_CAMERA`) + Camera, + /// The Camera focus key. (`KEYCODE_FOCUS`) + CameraFocus, + /// The End Call key. (`KEYCODE_ENDCALL`) + EndCall, + /// The Back key. (`KEYCODE_BACK`) + GoBack, + /// The Home key, which goes to the phone’s main screen. (`KEYCODE_HOME`) + GoHome, + /// The Headset Hook key. (`KEYCODE_HEADSETHOOK`) + HeadsetHook, + LastNumberRedial, + /// The Notification key. (`KEYCODE_NOTIFICATION`) + Notification, + /// Toggle between manner mode state: silent, vibrate, ring, ... (`KEYCODE_MANNER_MODE`) + MannerMode, + VoiceDial, + /// Switch to viewing TV. (`KEYCODE_TV`) + TV, + /// TV 3D Mode. (`KEYCODE_3D_MODE`) + TV3DMode, + /// Toggle between antenna and cable input. (`KEYCODE_TV_ANTENNA_CABLE`) + TVAntennaCable, + /// Audio description. (`KEYCODE_TV_AUDIO_DESCRIPTION`) + TVAudioDescription, + /// Audio description mixing volume down. (`KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN`) + TVAudioDescriptionMixDown, + /// Audio description mixing volume up. (`KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP`) + TVAudioDescriptionMixUp, + /// Contents menu. (`KEYCODE_TV_CONTENTS_MENU`) + TVContentsMenu, + /// Contents menu. (`KEYCODE_TV_DATA_SERVICE`) + TVDataService, + /// Switch the input mode on an external TV. (`KEYCODE_TV_INPUT`) + TVInput, + /// Switch to component input #1. (`KEYCODE_TV_INPUT_COMPONENT_1`) + TVInputComponent1, + /// Switch to component input #2. (`KEYCODE_TV_INPUT_COMPONENT_2`) + TVInputComponent2, + /// Switch to composite input #1. (`KEYCODE_TV_INPUT_COMPOSITE_1`) + TVInputComposite1, + /// Switch to composite input #2. (`KEYCODE_TV_INPUT_COMPOSITE_2`) + TVInputComposite2, + /// Switch to HDMI input #1. (`KEYCODE_TV_INPUT_HDMI_1`) + TVInputHDMI1, + /// Switch to HDMI input #2. (`KEYCODE_TV_INPUT_HDMI_2`) + TVInputHDMI2, + /// Switch to HDMI input #3. (`KEYCODE_TV_INPUT_HDMI_3`) + TVInputHDMI3, + /// Switch to HDMI input #4. (`KEYCODE_TV_INPUT_HDMI_4`) + TVInputHDMI4, + /// Switch to VGA input #1. (`KEYCODE_TV_INPUT_VGA_1`) + TVInputVGA1, + /// Media context menu. (`KEYCODE_TV_MEDIA_CONTEXT_MENU`) + TVMediaContext, + /// Toggle network. (`KEYCODE_TV_NETWORK`) + TVNetwork, + /// Number entry. (`KEYCODE_TV_NUMBER_ENTRY`) + TVNumberEntry, + /// Toggle the power on an external TV. (`KEYCODE_TV_POWER`) + TVPower, + /// Radio. (`KEYCODE_TV_RADIO_SERVICE`) + TVRadioService, + /// Satellite. (`KEYCODE_TV_SATELLITE`) + TVSatellite, + /// Broadcast Satellite. (`KEYCODE_TV_SATELLITE_BS`) + TVSatelliteBS, + /// Communication Satellite. (`KEYCODE_TV_SATELLITE_CS`) + TVSatelliteCS, + /// Toggle between available satellites. (`KEYCODE_TV_SATELLITE_SERVICE`) + TVSatelliteToggle, + /// Analog Terrestrial. (`KEYCODE_TV_TERRESTRIAL_ANALOG`) + TVTerrestrialAnalog, + /// Digital Terrestrial. (`KEYCODE_TV_TERRESTRIAL_DIGITAL`) + TVTerrestrialDigital, + /// Timer programming. (`KEYCODE_TV_TIMER_PROGRAMMING`) + TVTimer, + /// Switch the input mode on an external AVR (audio/video receiver). (`KEYCODE_AVR_INPUT`) + AVRInput, + /// Toggle the power on an external AVR (audio/video receiver). (`KEYCODE_AVR_POWER`) + AVRPower, + /// General purpose color-coded media function key, as index 0 (red). (`VK_COLORED_KEY_0`, + /// `KEYCODE_PROG_RED`) + ColorF0Red, + /// General purpose color-coded media function key, as index 1 (green). (`VK_COLORED_KEY_1`, + /// `KEYCODE_PROG_GREEN`) + ColorF1Green, + /// General purpose color-coded media function key, as index 2 (yellow). (`VK_COLORED_KEY_2`, + /// `KEYCODE_PROG_YELLOW`) + ColorF2Yellow, + /// General purpose color-coded media function key, as index 3 (blue). (`VK_COLORED_KEY_3`, + /// `KEYCODE_PROG_BLUE`) + ColorF3Blue, + /// General purpose color-coded media function key, as index 4 (grey). (`VK_COLORED_KEY_4`) + ColorF4Grey, + /// General purpose color-coded media function key, as index 5 (brown). (`VK_COLORED_KEY_5`) + ColorF5Brown, + /// Toggle the display of Closed Captions. (`VK_CC`, `KEYCODE_CAPTIONS`) + ClosedCaptionToggle, + /// Adjust brightness of device, by toggling between or cycling through states. (`VK_DIMMER`) + Dimmer, + /// Swap video sources. (`VK_DISPLAY_SWAP`) + DisplaySwap, + /// Select Digital Video Rrecorder. (`KEYCODE_DVR`) + DVR, + /// Exit the current application. (`VK_EXIT`) + Exit, + /// Clear program or content stored as favorite 0. (`VK_CLEAR_FAVORITE_0`) + FavoriteClear0, + /// Clear program or content stored as favorite 1. (`VK_CLEAR_FAVORITE_1`) + FavoriteClear1, + /// Clear program or content stored as favorite 2. (`VK_CLEAR_FAVORITE_2`) + FavoriteClear2, + /// Clear program or content stored as favorite 3. (`VK_CLEAR_FAVORITE_3`) + FavoriteClear3, + /// Select (recall) program or content stored as favorite 0. (`VK_RECALL_FAVORITE_0`) + FavoriteRecall0, + /// Select (recall) program or content stored as favorite 1. (`VK_RECALL_FAVORITE_1`) + FavoriteRecall1, + /// Select (recall) program or content stored as favorite 2. (`VK_RECALL_FAVORITE_2`) + FavoriteRecall2, + /// Select (recall) program or content stored as favorite 3. (`VK_RECALL_FAVORITE_3`) + FavoriteRecall3, + /// Store current program or content as favorite 0. (`VK_STORE_FAVORITE_0`) + FavoriteStore0, + /// Store current program or content as favorite 1. (`VK_STORE_FAVORITE_1`) + FavoriteStore1, + /// Store current program or content as favorite 2. (`VK_STORE_FAVORITE_2`) + FavoriteStore2, + /// Store current program or content as favorite 3. (`VK_STORE_FAVORITE_3`) + FavoriteStore3, + /// Toggle display of program or content guide. (`VK_GUIDE`, `KEYCODE_GUIDE`) + Guide, + /// If guide is active and displayed, then display next day’s content. (`VK_NEXT_DAY`) + GuideNextDay, + /// If guide is active and displayed, then display previous day’s content. (`VK_PREV_DAY`) + GuidePreviousDay, + /// Toggle display of information about currently selected context or media. (`VK_INFO`, + /// `KEYCODE_INFO`) + Info, + /// Toggle instant replay. (`VK_INSTANT_REPLAY`) + InstantReplay, + /// Launch linked content, if available and appropriate. (`VK_LINK`) + Link, + /// List the current program. (`VK_LIST`) + ListProgram, + /// Toggle display listing of currently available live content or programs. (`VK_LIVE`) + LiveContent, + /// Lock or unlock current content or program. (`VK_LOCK`) + Lock, + /// Show a list of media applications: audio/video players and image viewers. (`VK_APPS`) + /// + /// Note: Do not confuse this key value with the Windows' `VK_APPS` / `VK_CONTEXT_MENU` key, + /// which is encoded as `"ContextMenu"`. + MediaApps, + /// Audio track key. (`KEYCODE_MEDIA_AUDIO_TRACK`) + MediaAudioTrack, + /// Select previously selected channel or media. (`VK_LAST`, `KEYCODE_LAST_CHANNEL`) + MediaLast, + /// Skip backward to next content or program. (`KEYCODE_MEDIA_SKIP_BACKWARD`) + MediaSkipBackward, + /// Skip forward to next content or program. (`VK_SKIP`, `KEYCODE_MEDIA_SKIP_FORWARD`) + MediaSkipForward, + /// Step backward to next content or program. (`KEYCODE_MEDIA_STEP_BACKWARD`) + MediaStepBackward, + /// Step forward to next content or program. (`KEYCODE_MEDIA_STEP_FORWARD`) + MediaStepForward, + /// Media top menu. (`KEYCODE_MEDIA_TOP_MENU`) + MediaTopMenu, + /// Navigate in. (`KEYCODE_NAVIGATE_IN`) + NavigateIn, + /// Navigate to next key. (`KEYCODE_NAVIGATE_NEXT`) + NavigateNext, + /// Navigate out. (`KEYCODE_NAVIGATE_OUT`) + NavigateOut, + /// Navigate to previous key. (`KEYCODE_NAVIGATE_PREVIOUS`) + NavigatePrevious, + /// Cycle to next favorite channel (in favorites list). (`VK_NEXT_FAVORITE_CHANNEL`) + NextFavoriteChannel, + /// Cycle to next user profile (if there are multiple user profiles). (`VK_USER`) + NextUserProfile, + /// Access on-demand content or programs. (`VK_ON_DEMAND`) + OnDemand, + /// Pairing key to pair devices. (`KEYCODE_PAIRING`) + Pairing, + /// Move picture-in-picture window down. (`VK_PINP_DOWN`) + PinPDown, + /// Move picture-in-picture window. (`VK_PINP_MOVE`) + PinPMove, + /// Toggle display of picture-in-picture window. (`VK_PINP_TOGGLE`) + PinPToggle, + /// Move picture-in-picture window up. (`VK_PINP_UP`) + PinPUp, + /// Decrease media playback speed. (`VK_PLAY_SPEED_DOWN`) + PlaySpeedDown, + /// Reset playback to normal speed. (`VK_PLAY_SPEED_RESET`) + PlaySpeedReset, + /// Increase media playback speed. (`VK_PLAY_SPEED_UP`) + PlaySpeedUp, + /// Toggle random media or content shuffle mode. (`VK_RANDOM_TOGGLE`) + RandomToggle, + /// Not a physical key, but this key code is sent when the remote control battery is low. + /// (`VK_RC_LOW_BATTERY`) + RcLowBattery, + /// Toggle or cycle between media recording speeds. (`VK_RECORD_SPEED_NEXT`) + RecordSpeedNext, + /// Toggle RF (radio frequency) input bypass mode (pass RF input directly to the RF output). + /// (`VK_RF_BYPASS`) + RfBypass, + /// Toggle scan channels mode. (`VK_SCAN_CHANNELS_TOGGLE`) + ScanChannelsToggle, + /// Advance display screen mode to next available mode. (`VK_SCREEN_MODE_NEXT`) + ScreenModeNext, + /// Toggle display of device settings screen. (`VK_SETTINGS`, `KEYCODE_SETTINGS`) + Settings, + /// Toggle split screen mode. (`VK_SPLIT_SCREEN_TOGGLE`) + SplitScreenToggle, + /// Switch the input mode on an external STB (set top box). (`KEYCODE_STB_INPUT`) + STBInput, + /// Toggle the power on an external STB (set top box). (`KEYCODE_STB_POWER`) + STBPower, + /// Toggle display of subtitles, if available. (`VK_SUBTITLE`) + Subtitle, + /// Toggle display of teletext, if available (`VK_TELETEXT`, `KEYCODE_TV_TELETEXT`). + Teletext, + /// Advance video mode to next available mode. (`VK_VIDEO_MODE_NEXT`) + VideoModeNext, + /// Cause device to identify itself in some manner, e.g., audibly or visibly. (`VK_WINK`) + Wink, + /// Toggle between full-screen and scaled content, or alter magnification level. (`VK_ZOOM`, + /// `KEYCODE_TV_ZOOM_MODE`) + ZoomToggle, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F1, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F2, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F3, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F4, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F5, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F6, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F7, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F8, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F9, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F10, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F11, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F12, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F13, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F14, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F15, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F16, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F17, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F18, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F19, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F20, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F21, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F22, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F23, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F24, + /// General-purpose function key. + F25, + /// General-purpose function key. + F26, + /// General-purpose function key. + F27, + /// General-purpose function key. + F28, + /// General-purpose function key. + F29, + /// General-purpose function key. + F30, + /// General-purpose function key. + F31, + /// General-purpose function key. + F32, + /// General-purpose function key. + F33, + /// General-purpose function key. + F34, + /// General-purpose function key. + F35, +} + +impl<'a> Key<'a> { + pub fn to_text(&self) -> Option<&'a str> { + match self { + Key::Character(ch) => Some(*ch), + Key::Enter => Some("\r"), + Key::Backspace => Some("\x08"), + Key::Tab => Some("\t"), + Key::Space => Some(" "), + Key::Escape => Some("\x1b"), + _ => None, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum KeyLocation { + Standard, + Left, + Right, + Numpad, +} diff --git a/src/lib.rs b/src/lib.rs index 9b54930213..6b98130b98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -153,6 +153,7 @@ pub mod error; pub mod event; pub mod event_loop; mod icon; +pub mod keyboard; pub mod monitor; mod platform_impl; pub mod window; diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 1ee5fce2bb..84f016c2d2 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -21,5 +21,7 @@ pub mod macos; pub mod unix; pub mod windows; +pub mod modifier_supplement; pub mod run_return; +pub mod scancode; pub mod web; diff --git a/src/platform/modifier_supplement.rs b/src/platform/modifier_supplement.rs new file mode 100644 index 0000000000..361ed05d04 --- /dev/null +++ b/src/platform/modifier_supplement.rs @@ -0,0 +1,32 @@ +#![cfg(any( + target_os = "windows", + target_os = "macos", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] + +use crate::keyboard::Key; + +/// Additional methods for the `KeyEvent` which cannot be implemented on all +/// platforms. +pub trait KeyEventExtModifierSupplement { + /// Identical to `KeyEvent::text` but this is affected by Ctrl. + /// + /// For example, pressing Ctrl+a produces `Some("\x01")`. + fn text_with_all_modifiers(&self) -> Option<&str>; + + /// This value ignores all modifiers including, + /// but not limited to Shift, Caps Lock, + /// and Ctrl. In most cases this means that the + /// unicode character in the resulting string is lowercase. + /// + /// This is useful for key-bindings / shortcut key combinations. + /// + /// In case `logical_key` reports `Dead`, this will still report the + /// key as `Character` according to the current keyboard layout. This value + /// cannot be `Dead`. + fn key_without_modifiers(&self) -> Key<'static>; +} diff --git a/src/platform/scancode.rs b/src/platform/scancode.rs new file mode 100644 index 0000000000..078fe74dea --- /dev/null +++ b/src/platform/scancode.rs @@ -0,0 +1,31 @@ +#![cfg(any( + target_os = "windows", + target_os = "macos", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] + +// TODO: Maybe merge this with `modifier_supplement` if the two are indeed supported on the same +// set of platforms + +use crate::keyboard::KeyCode; + +pub trait KeyCodeExtScancode { + /// The raw value of the platform-specific physical key identifier. + /// + /// Returns `Some(key_id)` if the conversion was succesful; returns `None` otherwise. + /// + /// ## Platform-specific + /// - **Windows:** A 16bit extended scancode + // TODO: Describe what this value contains for each platform + fn to_scancode(self) -> Option; + + /// Constructs a `KeyCode` from a platform-specific physical key identifier. + /// + /// Note that this conversion may be lossy, i.e. converting the returned `KeyCode` back + /// using `to_scancode` might not yield the original value. + fn from_scancode(scancode: u32) -> KeyCode; +} diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 3499ba77fd..826e6cba7f 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -3,14 +3,24 @@ use std::os::raw::c_void; use std::path::Path; -use winapi::shared::minwindef::WORD; -use winapi::shared::windef::{HMENU, HWND}; +use winapi::{ + shared::{ + minwindef::{LOWORD, WORD}, + windef::{HMENU, HWND}, + }, + um::{ + winnt::{LANG_KOREAN, PRIMARYLANGID}, + winuser::GetKeyboardLayout, + }, +}; use crate::{ dpi::PhysicalSize, - event::DeviceId, + event::{DeviceId, KeyEvent}, event_loop::EventLoop, + keyboard::{Key, KeyCode, NativeKeyCode}, monitor::MonitorHandle, + platform::{modifier_supplement::KeyEventExtModifierSupplement, scancode::KeyCodeExtScancode}, platform_impl::{EventLoop as WindowsEventLoop, Parent, WinIcon}, window::{BadIcon, Icon, Theme, Window, WindowBuilder}, }; @@ -291,3 +301,349 @@ impl IconExtWindows for Icon { Ok(Icon { inner: win_icon }) } } + +impl KeyEventExtModifierSupplement for KeyEvent { + #[inline] + fn text_with_all_modifiers(&self) -> Option<&str> { + self.platform_specific.text_with_all_modifers + } + + #[inline] + fn key_without_modifiers(&self) -> Key<'static> { + self.platform_specific.key_without_modifiers + } +} + +impl KeyCodeExtScancode for KeyCode { + fn to_scancode(self) -> Option { + // See `from_scancode` for more info + + let hkl = unsafe { GetKeyboardLayout(0) }; + + let primary_lang_id = PRIMARYLANGID(LOWORD(hkl as u32)); + let is_korean = primary_lang_id == LANG_KOREAN; + + match self { + KeyCode::Backquote => Some(0x0029), + KeyCode::Backslash => Some(0x002B), + KeyCode::Backspace => Some(0x000E), + KeyCode::BracketLeft => Some(0x001A), + KeyCode::BracketRight => Some(0x001B), + KeyCode::Comma => Some(0x0033), + KeyCode::Digit0 => Some(0x000B), + KeyCode::Digit1 => Some(0x0002), + KeyCode::Digit2 => Some(0x0003), + KeyCode::Digit3 => Some(0x0004), + KeyCode::Digit4 => Some(0x0005), + KeyCode::Digit5 => Some(0x0006), + KeyCode::Digit6 => Some(0x0007), + KeyCode::Digit7 => Some(0x0008), + KeyCode::Digit8 => Some(0x0009), + KeyCode::Digit9 => Some(0x000A), + KeyCode::Equal => Some(0x000D), + KeyCode::IntlBackslash => Some(0x0056), + KeyCode::IntlRo => Some(0x0073), + KeyCode::IntlYen => Some(0x007D), + KeyCode::KeyA => Some(0x001E), + KeyCode::KeyB => Some(0x0030), + KeyCode::KeyC => Some(0x002E), + KeyCode::KeyD => Some(0x0020), + KeyCode::KeyE => Some(0x0012), + KeyCode::KeyF => Some(0x0021), + KeyCode::KeyG => Some(0x0022), + KeyCode::KeyH => Some(0x0023), + KeyCode::KeyI => Some(0x0017), + KeyCode::KeyJ => Some(0x0024), + KeyCode::KeyK => Some(0x0025), + KeyCode::KeyL => Some(0x0026), + KeyCode::KeyM => Some(0x0032), + KeyCode::KeyN => Some(0x0031), + KeyCode::KeyO => Some(0x0018), + KeyCode::KeyP => Some(0x0019), + KeyCode::KeyQ => Some(0x0010), + KeyCode::KeyR => Some(0x0013), + KeyCode::KeyS => Some(0x001F), + KeyCode::KeyT => Some(0x0014), + KeyCode::KeyU => Some(0x0016), + KeyCode::KeyV => Some(0x002F), + KeyCode::KeyW => Some(0x0011), + KeyCode::KeyX => Some(0x002D), + KeyCode::KeyY => Some(0x0015), + KeyCode::KeyZ => Some(0x002C), + KeyCode::Minus => Some(0x000C), + KeyCode::Period => Some(0x0034), + KeyCode::Quote => Some(0x0028), + KeyCode::Semicolon => Some(0x0027), + KeyCode::Slash => Some(0x0035), + KeyCode::AltLeft => Some(0x0038), + KeyCode::AltRight => Some(0xE038), + KeyCode::CapsLock => Some(0x003A), + KeyCode::ContextMenu => Some(0xE05D), + KeyCode::ControlLeft => Some(0x001D), + KeyCode::ControlRight => Some(0xE01D), + KeyCode::Enter => Some(0x001C), + KeyCode::SuperLeft => Some(0xE05B), + KeyCode::SuperRight => Some(0xE05C), + KeyCode::ShiftLeft => Some(0x002A), + KeyCode::ShiftRight => Some(0x0036), + KeyCode::Space => Some(0x0039), + KeyCode::Tab => Some(0x000F), + KeyCode::Convert => Some(0x0079), + KeyCode::Lang1 => { + if is_korean { + Some(0xE0F2) + } else { + Some(0x0072) + } + } + KeyCode::Lang2 => { + if is_korean { + Some(0xE0F1) + } else { + Some(0x0071) + } + } + KeyCode::KanaMode => Some(0x0070), + KeyCode::NonConvert => Some(0x007B), + KeyCode::Delete => Some(0xE053), + KeyCode::End => Some(0xE04F), + KeyCode::Home => Some(0xE047), + KeyCode::Insert => Some(0xE052), + KeyCode::PageDown => Some(0xE051), + KeyCode::PageUp => Some(0xE049), + KeyCode::ArrowDown => Some(0xE050), + KeyCode::ArrowLeft => Some(0xE04B), + KeyCode::ArrowRight => Some(0xE04D), + KeyCode::ArrowUp => Some(0xE048), + KeyCode::NumLock => Some(0xE045), + KeyCode::Numpad0 => Some(0x0052), + KeyCode::Numpad1 => Some(0x004F), + KeyCode::Numpad2 => Some(0x0050), + KeyCode::Numpad3 => Some(0x0051), + KeyCode::Numpad4 => Some(0x004B), + KeyCode::Numpad5 => Some(0x004C), + KeyCode::Numpad6 => Some(0x004D), + KeyCode::Numpad7 => Some(0x0047), + KeyCode::Numpad8 => Some(0x0048), + KeyCode::Numpad9 => Some(0x0049), + KeyCode::NumpadAdd => Some(0x004E), + KeyCode::NumpadComma => Some(0x007E), + KeyCode::NumpadDecimal => Some(0x0053), + KeyCode::NumpadDivide => Some(0xE035), + KeyCode::NumpadEnter => Some(0xE01C), + KeyCode::NumpadEqual => Some(0x0059), + KeyCode::NumpadMultiply => Some(0x0037), + KeyCode::NumpadSubtract => Some(0x004A), + KeyCode::Escape => Some(0x0001), + KeyCode::F1 => Some(0x003B), + KeyCode::F2 => Some(0x003C), + KeyCode::F3 => Some(0x003D), + KeyCode::F4 => Some(0x003E), + KeyCode::F5 => Some(0x003F), + KeyCode::F6 => Some(0x0040), + KeyCode::F7 => Some(0x0041), + KeyCode::F8 => Some(0x0042), + KeyCode::F9 => Some(0x0043), + KeyCode::F10 => Some(0x0044), + KeyCode::F11 => Some(0x0057), + KeyCode::F12 => Some(0x0058), + KeyCode::F13 => Some(0x0064), + KeyCode::F14 => Some(0x0065), + KeyCode::F15 => Some(0x0066), + KeyCode::F16 => Some(0x0067), + KeyCode::F17 => Some(0x0068), + KeyCode::F18 => Some(0x0069), + KeyCode::F19 => Some(0x006A), + KeyCode::F20 => Some(0x006B), + KeyCode::F21 => Some(0x006C), + KeyCode::F22 => Some(0x006D), + KeyCode::F23 => Some(0x006E), + KeyCode::F24 => Some(0x0076), + KeyCode::PrintScreen => Some(0xE037), + //KeyCode::PrintScreen => Some(0x0054), // Alt + PrintScreen + KeyCode::ScrollLock => Some(0x0046), + KeyCode::Pause => Some(0x0045), + //KeyCode::Pause => Some(0xE046), // Ctrl + Pause + KeyCode::BrowserBack => Some(0xE06A), + KeyCode::BrowserFavorites => Some(0xE066), + KeyCode::BrowserForward => Some(0xE069), + KeyCode::BrowserHome => Some(0xE032), + KeyCode::BrowserRefresh => Some(0xE067), + KeyCode::BrowserSearch => Some(0xE065), + KeyCode::BrowserStop => Some(0xE068), + KeyCode::LaunchApp1 => Some(0xE06B), + KeyCode::LaunchApp2 => Some(0xE021), + KeyCode::LaunchMail => Some(0xE06C), + KeyCode::MediaPlayPause => Some(0xE022), + KeyCode::MediaSelect => Some(0xE06D), + KeyCode::MediaStop => Some(0xE024), + KeyCode::MediaTrackNext => Some(0xE019), + KeyCode::MediaTrackPrevious => Some(0xE010), + KeyCode::Power => Some(0xE05E), + KeyCode::AudioVolumeDown => Some(0xE02E), + KeyCode::AudioVolumeMute => Some(0xE020), + KeyCode::AudioVolumeUp => Some(0xE030), + KeyCode::Unidentified(NativeKeyCode::Windows(scancode)) => Some(scancode as u32), + _ => None, + } + } + + fn from_scancode(scancode: u32) -> KeyCode { + // See: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html + // and: https://www.w3.org/TR/uievents-code/ + // and: The widget/NativeKeyToDOMCodeName.h file in the firefox source + + match scancode { + 0x0029 => KeyCode::Backquote, + 0x002B => KeyCode::Backslash, + 0x000E => KeyCode::Backspace, + 0x001A => KeyCode::BracketLeft, + 0x001B => KeyCode::BracketRight, + 0x0033 => KeyCode::Comma, + 0x000B => KeyCode::Digit0, + 0x0002 => KeyCode::Digit1, + 0x0003 => KeyCode::Digit2, + 0x0004 => KeyCode::Digit3, + 0x0005 => KeyCode::Digit4, + 0x0006 => KeyCode::Digit5, + 0x0007 => KeyCode::Digit6, + 0x0008 => KeyCode::Digit7, + 0x0009 => KeyCode::Digit8, + 0x000A => KeyCode::Digit9, + 0x000D => KeyCode::Equal, + 0x0056 => KeyCode::IntlBackslash, + 0x0073 => KeyCode::IntlRo, + 0x007D => KeyCode::IntlYen, + 0x001E => KeyCode::KeyA, + 0x0030 => KeyCode::KeyB, + 0x002E => KeyCode::KeyC, + 0x0020 => KeyCode::KeyD, + 0x0012 => KeyCode::KeyE, + 0x0021 => KeyCode::KeyF, + 0x0022 => KeyCode::KeyG, + 0x0023 => KeyCode::KeyH, + 0x0017 => KeyCode::KeyI, + 0x0024 => KeyCode::KeyJ, + 0x0025 => KeyCode::KeyK, + 0x0026 => KeyCode::KeyL, + 0x0032 => KeyCode::KeyM, + 0x0031 => KeyCode::KeyN, + 0x0018 => KeyCode::KeyO, + 0x0019 => KeyCode::KeyP, + 0x0010 => KeyCode::KeyQ, + 0x0013 => KeyCode::KeyR, + 0x001F => KeyCode::KeyS, + 0x0014 => KeyCode::KeyT, + 0x0016 => KeyCode::KeyU, + 0x002F => KeyCode::KeyV, + 0x0011 => KeyCode::KeyW, + 0x002D => KeyCode::KeyX, + 0x0015 => KeyCode::KeyY, + 0x002C => KeyCode::KeyZ, + 0x000C => KeyCode::Minus, + 0x0034 => KeyCode::Period, + 0x0028 => KeyCode::Quote, + 0x0027 => KeyCode::Semicolon, + 0x0035 => KeyCode::Slash, + 0x0038 => KeyCode::AltLeft, + 0xE038 => KeyCode::AltRight, + 0x003A => KeyCode::CapsLock, + 0xE05D => KeyCode::ContextMenu, + 0x001D => KeyCode::ControlLeft, + 0xE01D => KeyCode::ControlRight, + 0x001C => KeyCode::Enter, + 0xE05B => KeyCode::SuperLeft, + 0xE05C => KeyCode::SuperRight, + 0x002A => KeyCode::ShiftLeft, + 0x0036 => KeyCode::ShiftRight, + 0x0039 => KeyCode::Space, + 0x000F => KeyCode::Tab, + 0x0079 => KeyCode::Convert, + 0x0072 => KeyCode::Lang1, // for non-Korean layout + 0xE0F2 => KeyCode::Lang1, // for Korean layout + 0x0071 => KeyCode::Lang2, // for non-Korean layout + 0xE0F1 => KeyCode::Lang2, // for Korean layout + 0x0070 => KeyCode::KanaMode, + 0x007B => KeyCode::NonConvert, + 0xE053 => KeyCode::Delete, + 0xE04F => KeyCode::End, + 0xE047 => KeyCode::Home, + 0xE052 => KeyCode::Insert, + 0xE051 => KeyCode::PageDown, + 0xE049 => KeyCode::PageUp, + 0xE050 => KeyCode::ArrowDown, + 0xE04B => KeyCode::ArrowLeft, + 0xE04D => KeyCode::ArrowRight, + 0xE048 => KeyCode::ArrowUp, + 0xE045 => KeyCode::NumLock, + 0x0052 => KeyCode::Numpad0, + 0x004F => KeyCode::Numpad1, + 0x0050 => KeyCode::Numpad2, + 0x0051 => KeyCode::Numpad3, + 0x004B => KeyCode::Numpad4, + 0x004C => KeyCode::Numpad5, + 0x004D => KeyCode::Numpad6, + 0x0047 => KeyCode::Numpad7, + 0x0048 => KeyCode::Numpad8, + 0x0049 => KeyCode::Numpad9, + 0x004E => KeyCode::NumpadAdd, + 0x007E => KeyCode::NumpadComma, + 0x0053 => KeyCode::NumpadDecimal, + 0xE035 => KeyCode::NumpadDivide, + 0xE01C => KeyCode::NumpadEnter, + 0x0059 => KeyCode::NumpadEqual, + 0x0037 => KeyCode::NumpadMultiply, + 0x004A => KeyCode::NumpadSubtract, + 0x0001 => KeyCode::Escape, + 0x003B => KeyCode::F1, + 0x003C => KeyCode::F2, + 0x003D => KeyCode::F3, + 0x003E => KeyCode::F4, + 0x003F => KeyCode::F5, + 0x0040 => KeyCode::F6, + 0x0041 => KeyCode::F7, + 0x0042 => KeyCode::F8, + 0x0043 => KeyCode::F9, + 0x0044 => KeyCode::F10, + 0x0057 => KeyCode::F11, + 0x0058 => KeyCode::F12, + 0x0064 => KeyCode::F13, + 0x0065 => KeyCode::F14, + 0x0066 => KeyCode::F15, + 0x0067 => KeyCode::F16, + 0x0068 => KeyCode::F17, + 0x0069 => KeyCode::F18, + 0x006A => KeyCode::F19, + 0x006B => KeyCode::F20, + 0x006C => KeyCode::F21, + 0x006D => KeyCode::F22, + 0x006E => KeyCode::F23, + 0x0076 => KeyCode::F24, + 0xE037 => KeyCode::PrintScreen, + 0x0054 => KeyCode::PrintScreen, // Alt + PrintScreen + 0x0046 => KeyCode::ScrollLock, + 0x0045 => KeyCode::Pause, + 0xE046 => KeyCode::Pause, // Ctrl + Pause + 0xE06A => KeyCode::BrowserBack, + 0xE066 => KeyCode::BrowserFavorites, + 0xE069 => KeyCode::BrowserForward, + 0xE032 => KeyCode::BrowserHome, + 0xE067 => KeyCode::BrowserRefresh, + 0xE065 => KeyCode::BrowserSearch, + 0xE068 => KeyCode::BrowserStop, + 0xE06B => KeyCode::LaunchApp1, + 0xE021 => KeyCode::LaunchApp2, + 0xE06C => KeyCode::LaunchMail, + 0xE022 => KeyCode::MediaPlayPause, + 0xE06D => KeyCode::MediaSelect, + 0xE024 => KeyCode::MediaStop, + 0xE019 => KeyCode::MediaTrackNext, + 0xE010 => KeyCode::MediaTrackPrevious, + 0xE05E => KeyCode::Power, + 0xE02E => KeyCode::AudioVolumeDown, + 0xE020 => KeyCode::AudioVolumeMute, + 0xE030 => KeyCode::AudioVolumeUp, + _ => KeyCode::Unidentified(NativeKeyCode::Windows(scancode as u16)), + } + } +} diff --git a/src/platform_impl/windows/event.rs b/src/platform_impl/windows/event.rs deleted file mode 100644 index 77bd31d2ae..0000000000 --- a/src/platform_impl/windows/event.rs +++ /dev/null @@ -1,417 +0,0 @@ -use std::{ - char, - os::raw::c_int, - ptr, - sync::atomic::{AtomicBool, AtomicPtr, Ordering}, -}; - -use crate::event::{ModifiersState, ScanCode, VirtualKeyCode}; - -use winapi::{ - shared::minwindef::{HKL, HKL__, LPARAM, UINT, WPARAM}, - um::winuser, -}; - -fn key_pressed(vkey: c_int) -> bool { - unsafe { (winuser::GetKeyState(vkey) & (1 << 15)) == (1 << 15) } -} - -pub fn get_key_mods() -> ModifiersState { - let filter_out_altgr = layout_uses_altgr() && key_pressed(winuser::VK_RMENU); - - let mut mods = ModifiersState::empty(); - mods.set(ModifiersState::SHIFT, key_pressed(winuser::VK_SHIFT)); - mods.set( - ModifiersState::CTRL, - key_pressed(winuser::VK_CONTROL) && !filter_out_altgr, - ); - mods.set( - ModifiersState::ALT, - key_pressed(winuser::VK_MENU) && !filter_out_altgr, - ); - mods.set( - ModifiersState::LOGO, - key_pressed(winuser::VK_LWIN) || key_pressed(winuser::VK_RWIN), - ); - mods -} - -bitflags! { - #[derive(Default)] - pub struct ModifiersStateSide: u32 { - const LSHIFT = 0b010; - const RSHIFT = 0b001; - - const LCTRL = 0b010 << 3; - const RCTRL = 0b001 << 3; - - const LALT = 0b010 << 6; - const RALT = 0b001 << 6; - - const LLOGO = 0b010 << 9; - const RLOGO = 0b001 << 9; - } -} - -impl ModifiersStateSide { - pub fn filter_out_altgr(&self) -> ModifiersStateSide { - match layout_uses_altgr() && self.contains(Self::RALT) { - false => *self, - true => *self & !(Self::LCTRL | Self::RCTRL | Self::LALT | Self::RALT), - } - } -} - -impl From for ModifiersState { - fn from(side: ModifiersStateSide) -> Self { - let mut state = ModifiersState::default(); - state.set( - Self::SHIFT, - side.intersects(ModifiersStateSide::LSHIFT | ModifiersStateSide::RSHIFT), - ); - state.set( - Self::CTRL, - side.intersects(ModifiersStateSide::LCTRL | ModifiersStateSide::RCTRL), - ); - state.set( - Self::ALT, - side.intersects(ModifiersStateSide::LALT | ModifiersStateSide::RALT), - ); - state.set( - Self::LOGO, - side.intersects(ModifiersStateSide::LLOGO | ModifiersStateSide::RLOGO), - ); - state - } -} - -pub fn get_pressed_keys() -> impl Iterator { - let mut keyboard_state = vec![0u8; 256]; - unsafe { winuser::GetKeyboardState(keyboard_state.as_mut_ptr()) }; - keyboard_state - .into_iter() - .enumerate() - .filter(|(_, p)| (*p & (1 << 7)) != 0) // whether or not a key is pressed is communicated via the high-order bit - .map(|(i, _)| i as c_int) -} - -unsafe fn get_char(keyboard_state: &[u8; 256], v_key: u32, hkl: HKL) -> Option { - let mut unicode_bytes = [0u16; 5]; - let len = winuser::ToUnicodeEx( - v_key, - 0, - keyboard_state.as_ptr(), - unicode_bytes.as_mut_ptr(), - unicode_bytes.len() as _, - 0, - hkl, - ); - if len >= 1 { - char::decode_utf16(unicode_bytes.iter().cloned()) - .next() - .and_then(|c| c.ok()) - } else { - None - } -} - -/// Figures out if the keyboard layout has an AltGr key instead of an Alt key. -/// -/// Unfortunately, the Windows API doesn't give a way for us to conveniently figure that out. So, -/// we use a technique blatantly stolen from [the Firefox source code][source]: iterate over every -/// possible virtual key and compare the `char` output when AltGr is pressed vs when it isn't. If -/// pressing AltGr outputs characters that are different from the standard characters, the layout -/// uses AltGr. Otherwise, it doesn't. -/// -/// [source]: https://github.com/mozilla/gecko-dev/blob/265e6721798a455604328ed5262f430cfcc37c2f/widget/windows/KeyboardLayout.cpp#L4356-L4416 -fn layout_uses_altgr() -> bool { - unsafe { - static ACTIVE_LAYOUT: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - static USES_ALTGR: AtomicBool = AtomicBool::new(false); - - let hkl = winuser::GetKeyboardLayout(0); - let old_hkl = ACTIVE_LAYOUT.swap(hkl, Ordering::SeqCst); - - if hkl == old_hkl { - return USES_ALTGR.load(Ordering::SeqCst); - } - - let mut keyboard_state_altgr = [0u8; 256]; - // AltGr is an alias for Ctrl+Alt for... some reason. Whatever it is, those are the keypresses - // we have to emulate to do an AltGr test. - keyboard_state_altgr[winuser::VK_MENU as usize] = 0x80; - keyboard_state_altgr[winuser::VK_CONTROL as usize] = 0x80; - - let keyboard_state_empty = [0u8; 256]; - - for v_key in 0..=255 { - let key_noaltgr = get_char(&keyboard_state_empty, v_key, hkl); - let key_altgr = get_char(&keyboard_state_altgr, v_key, hkl); - if let (Some(noaltgr), Some(altgr)) = (key_noaltgr, key_altgr) { - if noaltgr != altgr { - USES_ALTGR.store(true, Ordering::SeqCst); - return true; - } - } - } - - USES_ALTGR.store(false, Ordering::SeqCst); - false - } -} - -pub fn vkey_to_winit_vkey(vkey: c_int) -> Option { - // VK_* codes are documented here https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx - match vkey { - //winuser::VK_LBUTTON => Some(VirtualKeyCode::Lbutton), - //winuser::VK_RBUTTON => Some(VirtualKeyCode::Rbutton), - //winuser::VK_CANCEL => Some(VirtualKeyCode::Cancel), - //winuser::VK_MBUTTON => Some(VirtualKeyCode::Mbutton), - //winuser::VK_XBUTTON1 => Some(VirtualKeyCode::Xbutton1), - //winuser::VK_XBUTTON2 => Some(VirtualKeyCode::Xbutton2), - winuser::VK_BACK => Some(VirtualKeyCode::Back), - winuser::VK_TAB => Some(VirtualKeyCode::Tab), - //winuser::VK_CLEAR => Some(VirtualKeyCode::Clear), - winuser::VK_RETURN => Some(VirtualKeyCode::Return), - winuser::VK_LSHIFT => Some(VirtualKeyCode::LShift), - winuser::VK_RSHIFT => Some(VirtualKeyCode::RShift), - winuser::VK_LCONTROL => Some(VirtualKeyCode::LControl), - winuser::VK_RCONTROL => Some(VirtualKeyCode::RControl), - winuser::VK_LMENU => Some(VirtualKeyCode::LAlt), - winuser::VK_RMENU => Some(VirtualKeyCode::RAlt), - winuser::VK_PAUSE => Some(VirtualKeyCode::Pause), - winuser::VK_CAPITAL => Some(VirtualKeyCode::Capital), - winuser::VK_KANA => Some(VirtualKeyCode::Kana), - //winuser::VK_HANGUEL => Some(VirtualKeyCode::Hanguel), - //winuser::VK_HANGUL => Some(VirtualKeyCode::Hangul), - //winuser::VK_JUNJA => Some(VirtualKeyCode::Junja), - //winuser::VK_FINAL => Some(VirtualKeyCode::Final), - //winuser::VK_HANJA => Some(VirtualKeyCode::Hanja), - winuser::VK_KANJI => Some(VirtualKeyCode::Kanji), - winuser::VK_ESCAPE => Some(VirtualKeyCode::Escape), - winuser::VK_CONVERT => Some(VirtualKeyCode::Convert), - winuser::VK_NONCONVERT => Some(VirtualKeyCode::NoConvert), - //winuser::VK_ACCEPT => Some(VirtualKeyCode::Accept), - //winuser::VK_MODECHANGE => Some(VirtualKeyCode::Modechange), - winuser::VK_SPACE => Some(VirtualKeyCode::Space), - winuser::VK_PRIOR => Some(VirtualKeyCode::PageUp), - winuser::VK_NEXT => Some(VirtualKeyCode::PageDown), - winuser::VK_END => Some(VirtualKeyCode::End), - winuser::VK_HOME => Some(VirtualKeyCode::Home), - winuser::VK_LEFT => Some(VirtualKeyCode::Left), - winuser::VK_UP => Some(VirtualKeyCode::Up), - winuser::VK_RIGHT => Some(VirtualKeyCode::Right), - winuser::VK_DOWN => Some(VirtualKeyCode::Down), - //winuser::VK_SELECT => Some(VirtualKeyCode::Select), - //winuser::VK_PRINT => Some(VirtualKeyCode::Print), - //winuser::VK_EXECUTE => Some(VirtualKeyCode::Execute), - winuser::VK_SNAPSHOT => Some(VirtualKeyCode::Snapshot), - winuser::VK_INSERT => Some(VirtualKeyCode::Insert), - winuser::VK_DELETE => Some(VirtualKeyCode::Delete), - //winuser::VK_HELP => Some(VirtualKeyCode::Help), - 0x30 => Some(VirtualKeyCode::Key0), - 0x31 => Some(VirtualKeyCode::Key1), - 0x32 => Some(VirtualKeyCode::Key2), - 0x33 => Some(VirtualKeyCode::Key3), - 0x34 => Some(VirtualKeyCode::Key4), - 0x35 => Some(VirtualKeyCode::Key5), - 0x36 => Some(VirtualKeyCode::Key6), - 0x37 => Some(VirtualKeyCode::Key7), - 0x38 => Some(VirtualKeyCode::Key8), - 0x39 => Some(VirtualKeyCode::Key9), - 0x41 => Some(VirtualKeyCode::A), - 0x42 => Some(VirtualKeyCode::B), - 0x43 => Some(VirtualKeyCode::C), - 0x44 => Some(VirtualKeyCode::D), - 0x45 => Some(VirtualKeyCode::E), - 0x46 => Some(VirtualKeyCode::F), - 0x47 => Some(VirtualKeyCode::G), - 0x48 => Some(VirtualKeyCode::H), - 0x49 => Some(VirtualKeyCode::I), - 0x4A => Some(VirtualKeyCode::J), - 0x4B => Some(VirtualKeyCode::K), - 0x4C => Some(VirtualKeyCode::L), - 0x4D => Some(VirtualKeyCode::M), - 0x4E => Some(VirtualKeyCode::N), - 0x4F => Some(VirtualKeyCode::O), - 0x50 => Some(VirtualKeyCode::P), - 0x51 => Some(VirtualKeyCode::Q), - 0x52 => Some(VirtualKeyCode::R), - 0x53 => Some(VirtualKeyCode::S), - 0x54 => Some(VirtualKeyCode::T), - 0x55 => Some(VirtualKeyCode::U), - 0x56 => Some(VirtualKeyCode::V), - 0x57 => Some(VirtualKeyCode::W), - 0x58 => Some(VirtualKeyCode::X), - 0x59 => Some(VirtualKeyCode::Y), - 0x5A => Some(VirtualKeyCode::Z), - winuser::VK_LWIN => Some(VirtualKeyCode::LWin), - winuser::VK_RWIN => Some(VirtualKeyCode::RWin), - winuser::VK_APPS => Some(VirtualKeyCode::Apps), - winuser::VK_SLEEP => Some(VirtualKeyCode::Sleep), - winuser::VK_NUMPAD0 => Some(VirtualKeyCode::Numpad0), - winuser::VK_NUMPAD1 => Some(VirtualKeyCode::Numpad1), - winuser::VK_NUMPAD2 => Some(VirtualKeyCode::Numpad2), - winuser::VK_NUMPAD3 => Some(VirtualKeyCode::Numpad3), - winuser::VK_NUMPAD4 => Some(VirtualKeyCode::Numpad4), - winuser::VK_NUMPAD5 => Some(VirtualKeyCode::Numpad5), - winuser::VK_NUMPAD6 => Some(VirtualKeyCode::Numpad6), - winuser::VK_NUMPAD7 => Some(VirtualKeyCode::Numpad7), - winuser::VK_NUMPAD8 => Some(VirtualKeyCode::Numpad8), - winuser::VK_NUMPAD9 => Some(VirtualKeyCode::Numpad9), - winuser::VK_MULTIPLY => Some(VirtualKeyCode::NumpadMultiply), - winuser::VK_ADD => Some(VirtualKeyCode::NumpadAdd), - //winuser::VK_SEPARATOR => Some(VirtualKeyCode::Separator), - winuser::VK_SUBTRACT => Some(VirtualKeyCode::NumpadSubtract), - winuser::VK_DECIMAL => Some(VirtualKeyCode::NumpadDecimal), - winuser::VK_DIVIDE => Some(VirtualKeyCode::NumpadDivide), - winuser::VK_F1 => Some(VirtualKeyCode::F1), - winuser::VK_F2 => Some(VirtualKeyCode::F2), - winuser::VK_F3 => Some(VirtualKeyCode::F3), - winuser::VK_F4 => Some(VirtualKeyCode::F4), - winuser::VK_F5 => Some(VirtualKeyCode::F5), - winuser::VK_F6 => Some(VirtualKeyCode::F6), - winuser::VK_F7 => Some(VirtualKeyCode::F7), - winuser::VK_F8 => Some(VirtualKeyCode::F8), - winuser::VK_F9 => Some(VirtualKeyCode::F9), - winuser::VK_F10 => Some(VirtualKeyCode::F10), - winuser::VK_F11 => Some(VirtualKeyCode::F11), - winuser::VK_F12 => Some(VirtualKeyCode::F12), - winuser::VK_F13 => Some(VirtualKeyCode::F13), - winuser::VK_F14 => Some(VirtualKeyCode::F14), - winuser::VK_F15 => Some(VirtualKeyCode::F15), - winuser::VK_F16 => Some(VirtualKeyCode::F16), - winuser::VK_F17 => Some(VirtualKeyCode::F17), - winuser::VK_F18 => Some(VirtualKeyCode::F18), - winuser::VK_F19 => Some(VirtualKeyCode::F19), - winuser::VK_F20 => Some(VirtualKeyCode::F20), - winuser::VK_F21 => Some(VirtualKeyCode::F21), - winuser::VK_F22 => Some(VirtualKeyCode::F22), - winuser::VK_F23 => Some(VirtualKeyCode::F23), - winuser::VK_F24 => Some(VirtualKeyCode::F24), - winuser::VK_NUMLOCK => Some(VirtualKeyCode::Numlock), - winuser::VK_SCROLL => Some(VirtualKeyCode::Scroll), - winuser::VK_BROWSER_BACK => Some(VirtualKeyCode::NavigateBackward), - winuser::VK_BROWSER_FORWARD => Some(VirtualKeyCode::NavigateForward), - winuser::VK_BROWSER_REFRESH => Some(VirtualKeyCode::WebRefresh), - winuser::VK_BROWSER_STOP => Some(VirtualKeyCode::WebStop), - winuser::VK_BROWSER_SEARCH => Some(VirtualKeyCode::WebSearch), - winuser::VK_BROWSER_FAVORITES => Some(VirtualKeyCode::WebFavorites), - winuser::VK_BROWSER_HOME => Some(VirtualKeyCode::WebHome), - winuser::VK_VOLUME_MUTE => Some(VirtualKeyCode::Mute), - winuser::VK_VOLUME_DOWN => Some(VirtualKeyCode::VolumeDown), - winuser::VK_VOLUME_UP => Some(VirtualKeyCode::VolumeUp), - winuser::VK_MEDIA_NEXT_TRACK => Some(VirtualKeyCode::NextTrack), - winuser::VK_MEDIA_PREV_TRACK => Some(VirtualKeyCode::PrevTrack), - winuser::VK_MEDIA_STOP => Some(VirtualKeyCode::MediaStop), - winuser::VK_MEDIA_PLAY_PAUSE => Some(VirtualKeyCode::PlayPause), - winuser::VK_LAUNCH_MAIL => Some(VirtualKeyCode::Mail), - winuser::VK_LAUNCH_MEDIA_SELECT => Some(VirtualKeyCode::MediaSelect), - /*winuser::VK_LAUNCH_APP1 => Some(VirtualKeyCode::Launch_app1), - winuser::VK_LAUNCH_APP2 => Some(VirtualKeyCode::Launch_app2),*/ - winuser::VK_OEM_PLUS => Some(VirtualKeyCode::Equals), - winuser::VK_OEM_COMMA => Some(VirtualKeyCode::Comma), - winuser::VK_OEM_MINUS => Some(VirtualKeyCode::Minus), - winuser::VK_OEM_PERIOD => Some(VirtualKeyCode::Period), - winuser::VK_OEM_1 => map_text_keys(vkey), - winuser::VK_OEM_2 => map_text_keys(vkey), - winuser::VK_OEM_3 => map_text_keys(vkey), - winuser::VK_OEM_4 => map_text_keys(vkey), - winuser::VK_OEM_5 => map_text_keys(vkey), - winuser::VK_OEM_6 => map_text_keys(vkey), - winuser::VK_OEM_7 => map_text_keys(vkey), - /* winuser::VK_OEM_8 => Some(VirtualKeyCode::Oem_8), */ - winuser::VK_OEM_102 => Some(VirtualKeyCode::OEM102), - /*winuser::VK_PROCESSKEY => Some(VirtualKeyCode::Processkey), - winuser::VK_PACKET => Some(VirtualKeyCode::Packet), - winuser::VK_ATTN => Some(VirtualKeyCode::Attn), - winuser::VK_CRSEL => Some(VirtualKeyCode::Crsel), - winuser::VK_EXSEL => Some(VirtualKeyCode::Exsel), - winuser::VK_EREOF => Some(VirtualKeyCode::Ereof), - winuser::VK_PLAY => Some(VirtualKeyCode::Play), - winuser::VK_ZOOM => Some(VirtualKeyCode::Zoom), - winuser::VK_NONAME => Some(VirtualKeyCode::Noname), - winuser::VK_PA1 => Some(VirtualKeyCode::Pa1), - winuser::VK_OEM_CLEAR => Some(VirtualKeyCode::Oem_clear),*/ - _ => None, - } -} - -pub fn handle_extended_keys( - vkey: c_int, - mut scancode: UINT, - extended: bool, -) -> Option<(c_int, UINT)> { - // Welcome to hell https://blog.molecular-matters.com/2011/09/05/properly-handling-keyboard-input/ - scancode |= if extended { 0xE000 } else { 0x0000 }; - let vkey = match vkey { - winuser::VK_SHIFT => unsafe { - winuser::MapVirtualKeyA(scancode, winuser::MAPVK_VSC_TO_VK_EX) as _ - }, - winuser::VK_CONTROL => { - if extended { - winuser::VK_RCONTROL - } else { - winuser::VK_LCONTROL - } - } - winuser::VK_MENU => { - if extended { - winuser::VK_RMENU - } else { - winuser::VK_LMENU - } - } - _ => { - match scancode { - // When VK_PAUSE is pressed it emits a LeftControl + NumLock scancode event sequence, but reports VK_PAUSE - // as the virtual key on both events, or VK_PAUSE on the first event or 0xFF when using raw input. - // Don't emit anything for the LeftControl event in the pair... - 0xE01D if vkey == winuser::VK_PAUSE => return None, - // ...and emit the Pause event for the second event in the pair. - 0x45 if vkey == winuser::VK_PAUSE || vkey == 0xFF => { - scancode = 0xE059; - winuser::VK_PAUSE - } - // VK_PAUSE has an incorrect vkey value when used with modifiers. VK_PAUSE also reports a different - // scancode when used with modifiers than when used without - 0xE046 => { - scancode = 0xE059; - winuser::VK_PAUSE - } - // VK_SCROLL has an incorrect vkey value when used with modifiers. - 0x46 => winuser::VK_SCROLL, - _ => vkey, - } - } - }; - Some((vkey, scancode)) -} - -pub fn process_key_params( - wparam: WPARAM, - lparam: LPARAM, -) -> Option<(ScanCode, Option)> { - let scancode = ((lparam >> 16) & 0xff) as UINT; - let extended = (lparam & 0x01000000) != 0; - handle_extended_keys(wparam as _, scancode, extended) - .map(|(vkey, scancode)| (scancode, vkey_to_winit_vkey(vkey))) -} - -// This is needed as windows doesn't properly distinguish -// some virtual key codes for different keyboard layouts -fn map_text_keys(win_virtual_key: i32) -> Option { - let char_key = - unsafe { winuser::MapVirtualKeyA(win_virtual_key as u32, winuser::MAPVK_VK_TO_CHAR) } - & 0x7FFF; - match char::from_u32(char_key) { - Some(';') => Some(VirtualKeyCode::Semicolon), - Some('/') => Some(VirtualKeyCode::Slash), - Some('`') => Some(VirtualKeyCode::Grave), - Some('[') => Some(VirtualKeyCode::LBracket), - Some(']') => Some(VirtualKeyCode::RBracket), - Some('\'') => Some(VirtualKeyCode::Apostrophe), - Some('\\') => Some(VirtualKeyCode::Backslash), - _ => None, - } -} diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index b7bc1cd42b..2684017ad5 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -18,6 +18,7 @@ use std::{ }; use winapi::{ + ctypes::c_int, shared::{ basetsd::LONG_PTR, minwindef::{BOOL, DWORD, HIWORD, INT, LOWORD, LPARAM, LRESULT, UINT, WORD, WPARAM}, @@ -27,20 +28,24 @@ use winapi::{ um::{ libloaderapi, mmsystem, ole2, processthreadsapi, timeapi, winbase, winnt::{HANDLE, LONG, LPCSTR, SHORT}, - winuser, + winuser::{self, RAWINPUT}, }, }; use crate::{ dpi::{PhysicalPosition, PhysicalSize}, - event::{DeviceEvent, Event, Force, KeyboardInput, Touch, TouchPhase, WindowEvent}, + event::{DeviceEvent, Event, Force, RawKeyEvent, Touch, TouchPhase, WindowEvent}, event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW}, + keyboard::{KeyCode, ModifiersState}, monitor::MonitorHandle as RootMonitorHandle, + platform::scancode::KeyCodeExtScancode, platform_impl::platform::{ dark_mode::try_theme, dpi::{become_dpi_aware, dpi_to_scale_factor}, drop_handler::FileDropHandler, - event::{self, handle_extended_keys, process_key_params, vkey_to_winit_vkey}, + keyboard::is_msg_keyboard_related, + keyboard_layout::LAYOUT_CACHE, + minimal_ime::is_msg_ime_related, monitor::{self, MonitorHandle}, raw_input, util, window::InitData, @@ -108,6 +113,18 @@ impl ThreadMsgTargetData { } } +/// The result of a subclass procedure (the message handling callback) +#[derive(Clone, Copy)] +pub(crate) enum ProcResult { + DefWindowProc, + Value(isize), +} +impl Default for ProcResult { + fn default() -> Self { + ProcResult::DefWindowProc + } +} + pub struct EventLoop { thread_msg_sender: Sender, window_target: RootELW, @@ -768,10 +785,15 @@ unsafe fn process_control_flow(runner: &EventLoopRunner) { } /// Emit a `ModifiersChanged` event whenever modifiers have changed. -fn update_modifiers(window: HWND, userdata: &WindowData) { +/// Returns the current modifier state +fn update_modifiers(window: HWND, userdata: &WindowData) -> ModifiersState { use crate::event::WindowEvent::ModifiersChanged; - let modifiers = event::get_key_mods(); + let modifiers = { + let mut layouts = LAYOUT_CACHE.lock().unwrap(); + layouts.get_agnostic_mods() + }; + let mut window_state = userdata.window_state.lock(); if window_state.modifiers_state != modifiers { window_state.modifiers_state = modifiers; @@ -786,6 +808,7 @@ fn update_modifiers(window: HWND, userdata: &WindowData) { }); } } + modifiers } #[cfg(target_arch = "x86_64")] @@ -873,6 +896,75 @@ unsafe fn public_window_callback_inner( winuser::RDW_INTERNALPAINT, ); + let mut result = ProcResult::DefWindowProc; + + // Send new modifiers before sending key events. + let mods_changed_callback = || match msg { + winuser::WM_KEYDOWN | winuser::WM_SYSKEYDOWN | winuser::WM_KEYUP | winuser::WM_SYSKEYUP => { + update_modifiers(window, userdata); + result = ProcResult::Value(0); + } + _ => (), + }; + userdata + .event_loop_runner + .catch_unwind(mods_changed_callback) + .unwrap_or_else(|| result = ProcResult::Value(-1)); + + let keyboard_callback = || { + use crate::event::WindowEvent::KeyboardInput; + let is_keyboard_related = is_msg_keyboard_related(msg); + if !is_keyboard_related { + // We return early to avoid a deadlock from locking the window state + // when not appropriate. + return; + } + let events = { + let mut window_state = userdata.window_state.lock(); + window_state + .key_event_builder + .process_message(window, msg, wparam, lparam, &mut result) + }; + for event in events { + userdata.send_event(Event::WindowEvent { + window_id: RootWindowId(WindowId(window)), + event: KeyboardInput { + device_id: DEVICE_ID, + event: event.event, + is_synthetic: event.is_synthetic, + }, + }); + } + }; + userdata + .event_loop_runner + .catch_unwind(keyboard_callback) + .unwrap_or_else(|| result = ProcResult::Value(-1)); + + let ime_callback = || { + use crate::event::WindowEvent::ReceivedImeText; + let is_ime_related = is_msg_ime_related(msg); + if !is_ime_related { + return; + } + let text = { + let mut window_state = userdata.window_state.lock(); + window_state + .ime_handler + .process_message(window, msg, wparam, lparam, &mut result) + }; + if let Some(str) = text { + userdata.send_event(Event::WindowEvent { + window_id: RootWindowId(WindowId(window)), + event: ReceivedImeText(str), + }); + } + }; + userdata + .event_loop_runner + .catch_unwind(ime_callback) + .unwrap_or_else(|| result = ProcResult::Value(-1)); + // I decided to bind the closure to `callback` and pass it to catch_unwind rather than passing // the closure to catch_unwind directly so that the match body indendation wouldn't change and // the git blame and history would be preserved. @@ -882,7 +974,7 @@ unsafe fn public_window_callback_inner( .window_state .lock() .set_window_flags_in_place(|f| f.insert(WindowFlags::MARKER_IN_SIZE_MOVE)); - 0 + result = ProcResult::Value(0); } winuser::WM_EXITSIZEMOVE => { @@ -890,14 +982,14 @@ unsafe fn public_window_callback_inner( .window_state .lock() .set_window_flags_in_place(|f| f.remove(WindowFlags::MARKER_IN_SIZE_MOVE)); - 0 + result = ProcResult::Value(0); } winuser::WM_NCLBUTTONDOWN => { if wparam == winuser::HTCAPTION as _ { winuser::PostMessageW(window, winuser::WM_MOUSEMOVE, 0, lparam); } - winuser::DefWindowProcW(window, msg, wparam, lparam) + result = ProcResult::DefWindowProc; } winuser::WM_CLOSE => { @@ -906,7 +998,7 @@ unsafe fn public_window_callback_inner( window_id: RootWindowId(WindowId(window)), event: CloseRequested, }); - 0 + result = ProcResult::Value(0); } winuser::WM_DESTROY => { @@ -917,13 +1009,13 @@ unsafe fn public_window_callback_inner( event: Destroyed, }); userdata.event_loop_runner.remove_window(window); - 0 + result = ProcResult::Value(0); } winuser::WM_NCDESTROY => { winuser::SetWindowLongPtrW(window, winuser::GWL_USERDATA, 0); userdata.userdata_removed.set(true); - 0 + result = ProcResult::Value(0); } winuser::WM_PAINT => { @@ -945,8 +1037,7 @@ unsafe fn public_window_callback_inner( process_control_flow(&userdata.event_loop_runner); } } - - winuser::DefWindowProcW(window, msg, wparam, lparam) + result = ProcResult::DefWindowProc; } winuser::WM_WINDOWPOSCHANGING => { @@ -994,7 +1085,7 @@ unsafe fn public_window_callback_inner( } } - 0 + result = ProcResult::Value(0); } // WM_MOVE supplies client area positions, so we send Moved here instead. @@ -1012,7 +1103,7 @@ unsafe fn public_window_callback_inner( } // This is necessary for us to still get sent WM_SIZE. - winuser::DefWindowProcW(window, msg, wparam, lparam) + result = ProcResult::DefWindowProc; } winuser::WM_SIZE => { @@ -1037,42 +1128,8 @@ unsafe fn public_window_callback_inner( w.set_window_flags_in_place(|f| f.set(WindowFlags::MAXIMIZED, maximized)); } } - userdata.send_event(event); - 0 - } - - winuser::WM_CHAR | winuser::WM_SYSCHAR => { - use crate::event::WindowEvent::ReceivedCharacter; - use std::char; - let is_high_surrogate = (0xD800..=0xDBFF).contains(&wparam); - let is_low_surrogate = (0xDC00..=0xDFFF).contains(&wparam); - - if is_high_surrogate { - userdata.window_state.lock().high_surrogate = Some(wparam as u16); - } else if is_low_surrogate { - let high_surrogate = userdata.window_state.lock().high_surrogate.take(); - - if let Some(high_surrogate) = high_surrogate { - let pair = [high_surrogate, wparam as u16]; - if let Some(Ok(chr)) = char::decode_utf16(pair.iter().copied()).next() { - userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), - event: ReceivedCharacter(chr), - }); - } - } - } else { - userdata.window_state.lock().high_surrogate = None; - - if let Some(chr) = char::from_u32(wparam as u32) { - userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), - event: ReceivedCharacter(chr), - }); - } - } - 0 + result = ProcResult::Value(0); } // this is necessary for us to maintain minimize/restore state @@ -1090,11 +1147,12 @@ unsafe fn public_window_callback_inner( if wparam == winuser::SC_SCREENSAVE { let window_state = userdata.window_state.lock(); if window_state.fullscreen.is_some() { - return 0; + result = ProcResult::Value(0); + return; } } - winuser::DefWindowProcW(window, msg, wparam, lparam) + result = ProcResult::DefWindowProc; } winuser::WM_MOUSEMOVE => { @@ -1139,19 +1197,19 @@ unsafe fn public_window_callback_inner( w.mouse.last_position = Some(position); } if cursor_moved { - update_modifiers(window, userdata); + let modifiers = update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), event: CursorMoved { device_id: DEVICE_ID, position, - modifiers: event::get_key_mods(), + modifiers, }, }); } - 0 + result = ProcResult::Value(0); } winuser::WM_MOUSELEAVE => { @@ -1170,7 +1228,7 @@ unsafe fn public_window_callback_inner( }, }); - 0 + result = ProcResult::Value(0); } winuser::WM_MOUSEWHEEL => { @@ -1180,7 +1238,7 @@ unsafe fn public_window_callback_inner( let value = value as i32; let value = value as f32 / winuser::WHEEL_DELTA as f32; - update_modifiers(window, userdata); + let modifiers = update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), @@ -1188,11 +1246,11 @@ unsafe fn public_window_callback_inner( device_id: DEVICE_ID, delta: LineDelta(0.0, value), phase: TouchPhase::Moved, - modifiers: event::get_key_mods(), + modifiers, }, }); - 0 + result = ProcResult::Value(0); } winuser::WM_MOUSEHWHEEL => { @@ -1202,7 +1260,7 @@ unsafe fn public_window_callback_inner( let value = value as i32; let value = value as f32 / winuser::WHEEL_DELTA as f32; - update_modifiers(window, userdata); + let modifiers = update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), @@ -1210,69 +1268,17 @@ unsafe fn public_window_callback_inner( device_id: DEVICE_ID, delta: LineDelta(value, 0.0), phase: TouchPhase::Moved, - modifiers: event::get_key_mods(), + modifiers, }, }); - 0 + result = ProcResult::Value(0); } winuser::WM_KEYDOWN | winuser::WM_SYSKEYDOWN => { - use crate::event::{ElementState::Pressed, VirtualKeyCode}; if msg == winuser::WM_SYSKEYDOWN && wparam as i32 == winuser::VK_F4 { - winuser::DefWindowProcW(window, msg, wparam, lparam) - } else { - if let Some((scancode, vkey)) = process_key_params(wparam, lparam) { - update_modifiers(window, userdata); - - #[allow(deprecated)] - userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), - event: WindowEvent::KeyboardInput { - device_id: DEVICE_ID, - input: KeyboardInput { - state: Pressed, - scancode, - virtual_keycode: vkey, - modifiers: event::get_key_mods(), - }, - is_synthetic: false, - }, - }); - // 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) { - userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), - event: WindowEvent::ReceivedCharacter('\u{7F}'), - }); - } - } - 0 - } - } - - winuser::WM_KEYUP | winuser::WM_SYSKEYUP => { - use crate::event::ElementState::Released; - if let Some((scancode, vkey)) = process_key_params(wparam, lparam) { - update_modifiers(window, userdata); - - #[allow(deprecated)] - userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), - event: WindowEvent::KeyboardInput { - device_id: DEVICE_ID, - input: KeyboardInput { - state: Released, - scancode, - virtual_keycode: vkey, - modifiers: event::get_key_mods(), - }, - is_synthetic: false, - }, - }); + result = ProcResult::DefWindowProc; } - 0 } winuser::WM_LBUTTONDOWN => { @@ -1280,7 +1286,7 @@ unsafe fn public_window_callback_inner( capture_mouse(window, &mut *userdata.window_state.lock()); - update_modifiers(window, userdata); + let modifiers = update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), @@ -1288,10 +1294,10 @@ unsafe fn public_window_callback_inner( device_id: DEVICE_ID, state: Pressed, button: Left, - modifiers: event::get_key_mods(), + modifiers, }, }); - 0 + result = ProcResult::Value(0); } winuser::WM_LBUTTONUP => { @@ -1301,7 +1307,7 @@ unsafe fn public_window_callback_inner( release_mouse(userdata.window_state.lock()); - update_modifiers(window, userdata); + let modifiers = update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), @@ -1309,10 +1315,10 @@ unsafe fn public_window_callback_inner( device_id: DEVICE_ID, state: Released, button: Left, - modifiers: event::get_key_mods(), + modifiers, }, }); - 0 + result = ProcResult::Value(0); } winuser::WM_RBUTTONDOWN => { @@ -1322,7 +1328,7 @@ unsafe fn public_window_callback_inner( capture_mouse(window, &mut *userdata.window_state.lock()); - update_modifiers(window, userdata); + let modifiers = update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), @@ -1330,10 +1336,10 @@ unsafe fn public_window_callback_inner( device_id: DEVICE_ID, state: Pressed, button: Right, - modifiers: event::get_key_mods(), + modifiers, }, }); - 0 + result = ProcResult::Value(0); } winuser::WM_RBUTTONUP => { @@ -1343,7 +1349,7 @@ unsafe fn public_window_callback_inner( release_mouse(userdata.window_state.lock()); - update_modifiers(window, userdata); + let modifiers = update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), @@ -1351,10 +1357,10 @@ unsafe fn public_window_callback_inner( device_id: DEVICE_ID, state: Released, button: Right, - modifiers: event::get_key_mods(), + modifiers, }, }); - 0 + result = ProcResult::Value(0); } winuser::WM_MBUTTONDOWN => { @@ -1364,7 +1370,7 @@ unsafe fn public_window_callback_inner( capture_mouse(window, &mut *userdata.window_state.lock()); - update_modifiers(window, userdata); + let modifiers = update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), @@ -1372,10 +1378,10 @@ unsafe fn public_window_callback_inner( device_id: DEVICE_ID, state: Pressed, button: Middle, - modifiers: event::get_key_mods(), + modifiers, }, }); - 0 + result = ProcResult::Value(0); } winuser::WM_MBUTTONUP => { @@ -1385,7 +1391,7 @@ unsafe fn public_window_callback_inner( release_mouse(userdata.window_state.lock()); - update_modifiers(window, userdata); + let modifiers = update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), @@ -1393,10 +1399,10 @@ unsafe fn public_window_callback_inner( device_id: DEVICE_ID, state: Released, button: Middle, - modifiers: event::get_key_mods(), + modifiers, }, }); - 0 + result = ProcResult::Value(0); } winuser::WM_XBUTTONDOWN => { @@ -1407,7 +1413,7 @@ unsafe fn public_window_callback_inner( capture_mouse(window, &mut *userdata.window_state.lock()); - update_modifiers(window, userdata); + let modifiers = update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), @@ -1415,10 +1421,10 @@ unsafe fn public_window_callback_inner( device_id: DEVICE_ID, state: Pressed, button: Other(xbutton), - modifiers: event::get_key_mods(), + modifiers, }, }); - 0 + result = ProcResult::Value(0); } winuser::WM_XBUTTONUP => { @@ -1429,7 +1435,7 @@ unsafe fn public_window_callback_inner( release_mouse(userdata.window_state.lock()); - update_modifiers(window, userdata); + let modifiers = update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), @@ -1437,10 +1443,10 @@ unsafe fn public_window_callback_inner( device_id: DEVICE_ID, state: Released, button: Other(xbutton), - modifiers: event::get_key_mods(), + modifiers, }, }); - 0 + result = ProcResult::Value(0); } winuser::WM_CAPTURECHANGED => { @@ -1451,7 +1457,7 @@ unsafe fn public_window_callback_inner( if lparam != window as isize { userdata.window_state.lock().mouse.capture_count = 0; } - 0 + result = ProcResult::Value(0); } winuser::WM_TOUCH => { @@ -1500,7 +1506,7 @@ unsafe fn public_window_callback_inner( } } winuser::CloseTouchInputHandle(htouch); - 0 + result = ProcResult::Value(0); } winuser::WM_POINTERDOWN | winuser::WM_POINTERUPDATE | winuser::WM_POINTERUP => { @@ -1523,7 +1529,8 @@ unsafe fn public_window_callback_inner( std::ptr::null_mut(), ) == 0 { - return 0; + result = ProcResult::Value(0); + return; } let pointer_info_count = (entries_count * pointers_count) as usize; @@ -1536,7 +1543,8 @@ unsafe fn public_window_callback_inner( pointer_infos.as_mut_ptr(), ) == 0 { - return 0; + result = ProcResult::Value(0); + return; } // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getpointerframeinfohistory @@ -1640,68 +1648,23 @@ unsafe fn public_window_callback_inner( SkipPointerFrameMessages(pointer_id); } - 0 + result = ProcResult::Value(0); } winuser::WM_SETFOCUS => { - use crate::event::{ElementState::Released, WindowEvent::Focused}; - for windows_keycode in event::get_pressed_keys() { - let scancode = - winuser::MapVirtualKeyA(windows_keycode as _, winuser::MAPVK_VK_TO_VSC); - let virtual_keycode = event::vkey_to_winit_vkey(windows_keycode); - - update_modifiers(window, userdata); - - #[allow(deprecated)] - userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), - event: WindowEvent::KeyboardInput { - device_id: DEVICE_ID, - input: KeyboardInput { - scancode, - virtual_keycode, - state: Released, - modifiers: event::get_key_mods(), - }, - is_synthetic: true, - }, - }) - } + use crate::event::WindowEvent::Focused; + update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), event: Focused(true), }); - 0 + result = ProcResult::Value(0); } winuser::WM_KILLFOCUS => { - use crate::event::{ - ElementState::Released, - ModifiersState, - WindowEvent::{Focused, ModifiersChanged}, - }; - for windows_keycode in event::get_pressed_keys() { - let scancode = - winuser::MapVirtualKeyA(windows_keycode as _, winuser::MAPVK_VK_TO_VSC); - let virtual_keycode = event::vkey_to_winit_vkey(windows_keycode); - - #[allow(deprecated)] - userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), - event: WindowEvent::KeyboardInput { - device_id: DEVICE_ID, - input: KeyboardInput { - scancode, - virtual_keycode, - state: Released, - modifiers: event::get_key_mods(), - }, - is_synthetic: true, - }, - }) - } + use crate::event::WindowEvent::{Focused, ModifiersChanged}; userdata.window_state.lock().modifiers_state = ModifiersState::empty(); userdata.send_event(Event::WindowEvent { @@ -1713,7 +1676,7 @@ unsafe fn public_window_callback_inner( window_id: RootWindowId(WindowId(window)), event: Focused(false), }); - 0 + result = ProcResult::Value(0); } winuser::WM_SETCURSOR => { @@ -1734,17 +1697,12 @@ unsafe fn public_window_callback_inner( Some(cursor) => { let cursor = winuser::LoadCursorW(ptr::null_mut(), cursor.to_windows_cursor()); winuser::SetCursor(cursor); - 0 + result = ProcResult::Value(0); } - None => winuser::DefWindowProcW(window, msg, wparam, lparam), + None => result = ProcResult::DefWindowProc, } } - winuser::WM_DROPFILES => { - // See `FileDropHandler` for implementation. - 0 - } - winuser::WM_GETMINMAXINFO => { let mmi = lparam as *mut winuser::MINMAXINFO; @@ -1769,7 +1727,7 @@ unsafe fn public_window_callback_inner( } } - 0 + result = ProcResult::Value(0); } // Only sent on Windows 8.1 or newer. On Windows 7 and older user has to log out to change @@ -1791,7 +1749,8 @@ unsafe fn public_window_callback_inner( window_state.scale_factor = new_scale_factor; if new_scale_factor == old_scale_factor { - return 0; + result = ProcResult::Value(0); + return; } window_state.fullscreen.is_none() @@ -1986,7 +1945,7 @@ unsafe fn public_window_callback_inner( winuser::SWP_NOZORDER | winuser::SWP_NOACTIVATE, ); - 0 + result = ProcResult::Value(0); } winuser::WM_SETTINGCHANGE => { @@ -2007,22 +1966,21 @@ unsafe fn public_window_callback_inner( }); } } - - winuser::DefWindowProcW(window, msg, wparam, lparam) + result = ProcResult::DefWindowProc; } _ => { if msg == *DESTROY_MSG_ID { winuser::DestroyWindow(window); - 0 + result = ProcResult::Value(0); } else if msg == *SET_RETAIN_STATE_ON_SIZE_MSG_ID { let mut window_state = userdata.window_state.lock(); window_state.set_window_flags_in_place(|f| { f.set(WindowFlags::MARKER_RETAIN_STATE_ON_SIZE, wparam != 0) }); - 0 + result = ProcResult::Value(0); } else { - winuser::DefWindowProcW(window, msg, wparam, lparam) + result = ProcResult::DefWindowProc; } } }; @@ -2030,7 +1988,12 @@ unsafe fn public_window_callback_inner( userdata .event_loop_runner .catch_unwind(callback) - .unwrap_or(-1) + .unwrap_or_else(|| result = ProcResult::Value(-1)); + + match result { + ProcResult::DefWindowProc => winuser::DefWindowProcW(window, msg, wparam, lparam), + ProcResult::Value(val) => val, + } } unsafe extern "system" fn thread_event_target_callback( @@ -2114,102 +2077,8 @@ unsafe extern "system" fn thread_event_target_callback( } winuser::WM_INPUT => { - use crate::event::{ - DeviceEvent::{Button, Key, Motion, MouseMotion, MouseWheel}, - ElementState::{Pressed, Released}, - MouseScrollDelta::LineDelta, - }; - if let Some(data) = raw_input::get_raw_input_data(lparam as _) { - let device_id = wrap_device_id(data.header.hDevice as _); - - if data.header.dwType == winuser::RIM_TYPEMOUSE { - let mouse = data.data.mouse(); - - if util::has_flag(mouse.usFlags, winuser::MOUSE_MOVE_RELATIVE) { - let x = mouse.lLastX as f64; - let y = mouse.lLastY as f64; - - if x != 0.0 { - userdata.send_event(Event::DeviceEvent { - device_id, - event: Motion { axis: 0, value: x }, - }); - } - - if y != 0.0 { - userdata.send_event(Event::DeviceEvent { - device_id, - event: Motion { axis: 1, value: y }, - }); - } - - if x != 0.0 || y != 0.0 { - userdata.send_event(Event::DeviceEvent { - device_id, - event: MouseMotion { delta: (x, y) }, - }); - } - } - - if util::has_flag(mouse.usButtonFlags, winuser::RI_MOUSE_WHEEL) { - let delta = - mouse.usButtonData as SHORT as f32 / winuser::WHEEL_DELTA as f32; - userdata.send_event(Event::DeviceEvent { - device_id, - event: MouseWheel { - delta: LineDelta(0.0, delta), - }, - }); - } - - let button_state = raw_input::get_raw_mouse_button_state(mouse.usButtonFlags); - // Left, middle, and right, respectively. - for (index, state) in button_state.iter().enumerate() { - if let Some(state) = *state { - // This gives us consistency with X11, since there doesn't - // seem to be anything else reasonable to do for a mouse - // button ID. - let button = (index + 1) as _; - userdata.send_event(Event::DeviceEvent { - device_id, - event: Button { button, state }, - }); - } - } - } else if data.header.dwType == winuser::RIM_TYPEKEYBOARD { - let keyboard = data.data.keyboard(); - - let pressed = keyboard.Message == winuser::WM_KEYDOWN - || keyboard.Message == winuser::WM_SYSKEYDOWN; - let released = keyboard.Message == winuser::WM_KEYUP - || keyboard.Message == winuser::WM_SYSKEYUP; - - if pressed || released { - let state = if pressed { Pressed } else { Released }; - - let scancode = keyboard.MakeCode as _; - let extended = util::has_flag(keyboard.Flags, winuser::RI_KEY_E0 as _) - | util::has_flag(keyboard.Flags, winuser::RI_KEY_E1 as _); - - if let Some((vkey, scancode)) = - handle_extended_keys(keyboard.VKey as _, scancode, extended) - { - let virtual_keycode = vkey_to_winit_vkey(vkey); - - #[allow(deprecated)] - userdata.send_event(Event::DeviceEvent { - device_id, - event: Key(KeyboardInput { - scancode, - state, - virtual_keycode, - modifiers: event::get_key_mods(), - }), - }); - } - } - } + handle_raw_input(&userdata, data); } winuser::DefWindowProcW(window, msg, wparam, lparam) @@ -2279,3 +2148,184 @@ unsafe extern "system" fn thread_event_target_callback( } result } + +unsafe fn handle_raw_input( + userdata: &ThreadMsgTargetData, + data: RAWINPUT, +) { + use crate::event::{ + DeviceEvent::{Button, Key, Motion, MouseMotion, MouseWheel}, + ElementState::{Pressed, Released}, + MouseScrollDelta::LineDelta, + }; + + let device_id = wrap_device_id(data.header.hDevice as _); + + if data.header.dwType == winuser::RIM_TYPEMOUSE { + let mouse = data.data.mouse(); + + if util::has_flag(mouse.usFlags, winuser::MOUSE_MOVE_RELATIVE) { + let x = mouse.lLastX as f64; + let y = mouse.lLastY as f64; + + if x != 0.0 { + userdata.send_event(Event::DeviceEvent { + device_id, + event: Motion { axis: 0, value: x }, + }); + } + + if y != 0.0 { + userdata.send_event(Event::DeviceEvent { + device_id, + event: Motion { axis: 1, value: y }, + }); + } + + if x != 0.0 || y != 0.0 { + userdata.send_event(Event::DeviceEvent { + device_id, + event: MouseMotion { delta: (x, y) }, + }); + } + } + + if util::has_flag(mouse.usButtonFlags, winuser::RI_MOUSE_WHEEL) { + // We must cast to SHORT first, becaues `usButtonData` must be interpreted as signed. + let delta = mouse.usButtonData as SHORT as f32 / winuser::WHEEL_DELTA as f32; + userdata.send_event(Event::DeviceEvent { + device_id, + event: MouseWheel { + delta: LineDelta(0.0, delta), + }, + }); + } + + let button_state = raw_input::get_raw_mouse_button_state(mouse.usButtonFlags); + // Left, middle, and right, respectively. + for (index, state) in button_state.iter().enumerate() { + if let Some(state) = *state { + // This gives us consistency with X11, since there doesn't + // seem to be anything else reasonable to do for a mouse + // button ID. + let button = (index + 1) as _; + userdata.send_event(Event::DeviceEvent { + device_id, + event: Button { button, state }, + }); + } + } + } else if data.header.dwType == winuser::RIM_TYPEKEYBOARD { + let keyboard = data.data.keyboard(); + + let pressed = + keyboard.Message == winuser::WM_KEYDOWN || keyboard.Message == winuser::WM_SYSKEYDOWN; + let released = + keyboard.Message == winuser::WM_KEYUP || keyboard.Message == winuser::WM_SYSKEYUP; + + if !pressed && !released { + return; + } + + let state = if pressed { Pressed } else { Released }; + let extension = { + if util::has_flag(keyboard.Flags, winuser::RI_KEY_E0 as _) { + 0xE000 + } else if util::has_flag(keyboard.Flags, winuser::RI_KEY_E1 as _) { + 0xE100 + } else { + 0x0000 + } + }; + let scancode; + if keyboard.MakeCode == 0 { + // In some cases (often with media keys) the device reports a scancode of 0 but a + // valid virtual key. In these cases we obtain the scancode from the virtual key. + scancode = + winuser::MapVirtualKeyW(keyboard.VKey as u32, winuser::MAPVK_VK_TO_VSC_EX) as u16; + } else { + scancode = keyboard.MakeCode | extension; + } + if scancode == 0xE11D || scancode == 0xE02A { + // At the hardware (or driver?) level, pressing the Pause key is equivalent to pressing + // Ctrl+NumLock. + // This equvalence means that if the user presses Pause, the keyboard will emit two + // subsequent keypresses: + // 1, 0xE11D - Which is a left Ctrl (0x1D) with an extension flag (0xE100) + // 2, 0x0045 - Which on its own can be interpreted as Pause + // + // There's another combination which isn't quite an equivalence: + // PrtSc used to be Shift+Asterisk. This means that on some keyboards, presssing + // PrtSc (print screen) produces the following sequence: + // 1, 0xE02A - Which is a left shift (0x2A) with an extension flag (0xE000) + // 2, 0xE037 - Which is a numpad multiply (0x37) with an exteion flag (0xE000). This on + // its own it can be interpreted as PrtSc + // + // For this reason, if we encounter the first keypress, we simply ignore it, trusting + // that there's going to be another event coming, from which we can extract the + // appropriate key. + // For more on this, read the article by Raymond Chen, titled: + // "Why does Ctrl+ScrollLock cancel dialogs?" + // https://devblogs.microsoft.com/oldnewthing/20080211-00/?p=23503 + return; + } + let code; + if keyboard.VKey as c_int == winuser::VK_NUMLOCK { + // Historically, the NumLock and the Pause key were one and the same physical key. + // The user could trigger Pause by pressing Ctrl+NumLock. + // Now these are often physically separate and the two keys can be differentiated by + // checking the extension flag of the scancode. NumLock is 0xE045, Pause is 0x0045. + // + // However in this event, both keys are reported as 0x0045 even on modern hardware. + // Therefore we use the virtual key instead to determine whether it's a NumLock and + // set the KeyCode accordingly. + // + // For more on this, read the article by Raymond Chen, titled: + // "Why does Ctrl+ScrollLock cancel dialogs?" + // https://devblogs.microsoft.com/oldnewthing/20080211-00/?p=23503 + code = KeyCode::NumLock; + } else { + code = KeyCode::from_scancode(scancode as u32); + } + if keyboard.VKey as c_int == winuser::VK_SHIFT { + match code { + KeyCode::NumpadDecimal + | KeyCode::Numpad0 + | KeyCode::Numpad1 + | KeyCode::Numpad2 + | KeyCode::Numpad3 + | KeyCode::Numpad4 + | KeyCode::Numpad5 + | KeyCode::Numpad6 + | KeyCode::Numpad7 + | KeyCode::Numpad8 + | KeyCode::Numpad9 => { + // On Windows, holding the Shift key makes numpad keys behave as if NumLock + // wasn't active. The way this is exposed to applications by the system is that + // the application receives a fake key release event for the shift key at the + // moment when the numpad key is pressed, just before receiving the numpad key + // as well. + // + // The issue is that in the raw device event (here), the fake shift release + // event reports the numpad key as the scancode. Unfortunately, the event doesn't + // have any information to tell whether it's the left shift or the right shift + // that needs to get the fake release (or press) event so we don't forward this + // event to the application at all. + // + // For more on this, read the article by Raymond Chen, titled: + // "The shift key overrides NumLock" + // https://devblogs.microsoft.com/oldnewthing/20040906-00/?p=37953 + return; + } + _ => (), + } + } + userdata.send_event(Event::DeviceEvent { + device_id, + event: Key(RawKeyEvent { + physical_key: code, + state, + }), + }); + } +} diff --git a/src/platform_impl/windows/keyboard.rs b/src/platform_impl/windows/keyboard.rs new file mode 100644 index 0000000000..00235ed018 --- /dev/null +++ b/src/platform_impl/windows/keyboard.rs @@ -0,0 +1,802 @@ +use std::{ + char, collections::HashSet, ffi::OsString, mem::MaybeUninit, os::raw::c_int, + os::windows::ffi::OsStringExt, sync::MutexGuard, +}; + +use winapi::{ + shared::{ + minwindef::{HKL, LPARAM, UINT, WPARAM}, + windef::HWND, + }, + um::winuser, +}; + +use unicode_segmentation::UnicodeSegmentation; + +use crate::{ + event::{ElementState, KeyEvent}, + keyboard::{Key, KeyCode, KeyLocation, NativeKeyCode}, + platform::scancode::KeyCodeExtScancode, + platform_impl::platform::{ + event_loop::ProcResult, + keyboard_layout::{get_or_insert_str, Layout, LayoutCache, WindowsModifiers, LAYOUT_CACHE}, + KeyEventExtra, + }, +}; + +pub fn is_msg_keyboard_related(msg: u32) -> bool { + use winuser::{WM_KEYFIRST, WM_KEYLAST, WM_KILLFOCUS, WM_SETFOCUS}; + let is_keyboard_msg = WM_KEYFIRST <= msg && msg <= WM_KEYLAST; + + is_keyboard_msg || msg == WM_SETFOCUS || msg == WM_KILLFOCUS +} + +pub type ExScancode = u16; + +pub struct MessageAsKeyEvent { + pub event: KeyEvent, + pub is_synthetic: bool, +} + +/// Stores information required to make `KeyEvent`s. +/// +/// A single Winit `KeyEvent` contains information which the Windows API passes to the application +/// in multiple window messages. In other words: a Winit `KeyEvent` cannot be built from a single +/// window message. Therefore, this type keeps track of certain information from previous events so +/// that a `KeyEvent` can be constructed when the last event related to a keypress is received. +/// +/// `PeekMessage` is sometimes used to determine whether the next window message still belongs to the +/// current keypress. If it doesn't and the current state represents a key event waiting to be +/// dispatched, then said event is considered complete and is dispatched. +/// +/// The sequence of window messages for a key press event is the following: +/// - Exactly one WM_KEYDOWN / WM_SYSKEYDOWN +/// - Zero or one WM_DEADCHAR / WM_SYSDEADCHAR +/// - Zero or more WM_CHAR / WM_SYSCHAR. These messages each come with a UTF-16 code unit which when +/// put together in the sequence they arrived in, forms the text which is the result of pressing the +/// key. +/// +/// Key release messages are a bit different due to the fact that they don't contribute to +/// text input. The "sequence" only consists of one WM_KEYUP / WM_SYSKEYUP event. +pub struct KeyEventBuilder { + event_info: Option, +} +impl Default for KeyEventBuilder { + fn default() -> Self { + KeyEventBuilder { event_info: None } + } +} +impl KeyEventBuilder { + /// Call this function for every window message. + /// Returns Some() if this window message completes a KeyEvent. + /// Returns None otherwise. + pub(crate) fn process_message( + &mut self, + hwnd: HWND, + msg_kind: u32, + wparam: WPARAM, + lparam: LPARAM, + result: &mut ProcResult, + ) -> Vec { + match msg_kind { + winuser::WM_SETFOCUS => { + // synthesize keydown events + let kbd_state = get_async_kbd_state(); + let key_events = self.synthesize_kbd_state(ElementState::Pressed, &kbd_state); + if !key_events.is_empty() { + return key_events; + } + } + winuser::WM_KILLFOCUS => { + // sythesize keyup events + let kbd_state = get_kbd_state(); + let key_events = self.synthesize_kbd_state(ElementState::Released, &kbd_state); + if !key_events.is_empty() { + return key_events; + } + } + winuser::WM_KEYDOWN | winuser::WM_SYSKEYDOWN => { + if msg_kind == winuser::WM_SYSKEYDOWN && wparam as i32 == winuser::VK_F4 { + // Don't dispatch Alt+F4 to the application. + // This is handled in `event_loop.rs` + return vec![]; + } + *result = ProcResult::Value(0); + + let mut layouts = LAYOUT_CACHE.lock().unwrap(); + let event_info = PartialKeyEventInfo::from_message( + wparam, + lparam, + ElementState::Pressed, + &mut layouts, + ); + + let mut next_msg = MaybeUninit::uninit(); + let peek_retval = unsafe { + winuser::PeekMessageW( + next_msg.as_mut_ptr(), + hwnd, + winuser::WM_KEYFIRST, + winuser::WM_KEYLAST, + winuser::PM_NOREMOVE, + ) + }; + let has_next_key_message = peek_retval != 0; + self.event_info = None; + let mut finished_event_info = Some(event_info); + if has_next_key_message { + let next_msg = unsafe { next_msg.assume_init() }; + let next_msg_kind = next_msg.message; + let next_belongs_to_this = !matches!( + next_msg_kind, + winuser::WM_KEYDOWN + | winuser::WM_SYSKEYDOWN + | winuser::WM_KEYUP + | winuser::WM_SYSKEYUP + ); + if next_belongs_to_this { + self.event_info = finished_event_info.take(); + } else { + let (_, layout) = layouts.get_current_layout(); + let is_fake = { + let curr_event = finished_event_info.as_ref().unwrap(); + is_current_fake(curr_event, next_msg, layout) + }; + if is_fake { + finished_event_info = None; + } + } + } + if let Some(event_info) = finished_event_info { + let ev = event_info.finalize(&mut layouts.strings); + return vec![MessageAsKeyEvent { + event: ev, + is_synthetic: false, + }]; + } + } + winuser::WM_DEADCHAR | winuser::WM_SYSDEADCHAR => { + *result = ProcResult::Value(0); + // At this point, we know that there isn't going to be any more events related to + // this key press + let event_info = self.event_info.take().unwrap(); + let mut layouts = LAYOUT_CACHE.lock().unwrap(); + let ev = event_info.finalize(&mut layouts.strings); + return vec![MessageAsKeyEvent { + event: ev, + is_synthetic: false, + }]; + } + winuser::WM_CHAR | winuser::WM_SYSCHAR => { + if self.event_info.is_none() { + trace!("Received a CHAR message but no `event_info` was available. The message is probably IME, returning."); + return vec![]; + } + *result = ProcResult::Value(0); + let is_high_surrogate = 0xD800 <= wparam && wparam <= 0xDBFF; + let is_low_surrogate = 0xDC00 <= wparam && wparam <= 0xDFFF; + + let is_utf16 = is_high_surrogate || is_low_surrogate; + + let more_char_coming; + unsafe { + let mut next_msg = MaybeUninit::uninit(); + let has_message = winuser::PeekMessageW( + next_msg.as_mut_ptr(), + hwnd, + winuser::WM_KEYFIRST, + winuser::WM_KEYLAST, + winuser::PM_NOREMOVE, + ); + let has_message = has_message != 0; + if !has_message { + more_char_coming = false; + } else { + let next_msg = next_msg.assume_init().message; + if next_msg == winuser::WM_CHAR || next_msg == winuser::WM_SYSCHAR { + more_char_coming = true; + } else { + more_char_coming = false; + } + } + } + + if is_utf16 { + if let Some(ev_info) = self.event_info.as_mut() { + ev_info.utf16parts.push(wparam as u16); + } + } else { + // In this case, wparam holds a UTF-32 character. + // Let's encode it as UTF-16 and append it to the end of `utf16parts` + let utf16parts = match self.event_info.as_mut() { + Some(ev_info) => &mut ev_info.utf16parts, + None => { + warn!("The event_info was None when it was expected to be some"); + return vec![]; + } + }; + let start_offset = utf16parts.len(); + let new_size = utf16parts.len() + 2; + utf16parts.resize(new_size, 0); + if let Some(ch) = char::from_u32(wparam as u32) { + let encode_len = ch.encode_utf16(&mut utf16parts[start_offset..]).len(); + let new_size = start_offset + encode_len; + utf16parts.resize(new_size, 0); + } + } + if !more_char_coming { + let mut event_info = match self.event_info.take() { + Some(ev_info) => ev_info, + None => { + warn!("The event_info was None when it was expected to be some"); + return vec![]; + } + }; + let mut layouts = LAYOUT_CACHE.lock().unwrap(); + // It's okay to call `ToUnicode` here, because at this point the dead key + // is already consumed by the character. + let kbd_state = get_kbd_state(); + let mod_state = WindowsModifiers::active_modifiers(&kbd_state); + + let (_, layout) = layouts.get_current_layout(); + let ctrl_on; + if layout.has_alt_graph { + let alt_on = mod_state.contains(WindowsModifiers::ALT); + ctrl_on = !alt_on && mod_state.contains(WindowsModifiers::CONTROL) + } else { + ctrl_on = mod_state.contains(WindowsModifiers::CONTROL) + } + + // If Ctrl is not pressed, just use the text with all + // modifiers because that already consumed the dead key. Otherwise, + // we would interpret the character incorrectly, missing the dead key. + if !ctrl_on { + event_info.text = PartialText::System(event_info.utf16parts.clone()); + } else { + let mod_no_ctrl = mod_state.remove_only_ctrl(); + let num_lock_on = kbd_state[winuser::VK_NUMLOCK as usize] & 1 != 0; + let vkey = event_info.vkey; + let scancode = event_info.scancode; + let keycode = event_info.code; + let key = layout.get_key(mod_no_ctrl, num_lock_on, vkey, scancode, keycode); + event_info.text = PartialText::Text(key.to_text()); + } + let ev = event_info.finalize(&mut layouts.strings); + return vec![MessageAsKeyEvent { + event: ev, + is_synthetic: false, + }]; + } + } + winuser::WM_KEYUP | winuser::WM_SYSKEYUP => { + *result = ProcResult::Value(0); + + let mut layouts = LAYOUT_CACHE.lock().unwrap(); + let event_info = PartialKeyEventInfo::from_message( + wparam, + lparam, + ElementState::Released, + &mut layouts, + ); + let mut next_msg = MaybeUninit::uninit(); + let peek_retval = unsafe { + winuser::PeekMessageW( + next_msg.as_mut_ptr(), + hwnd, + winuser::WM_KEYFIRST, + winuser::WM_KEYLAST, + winuser::PM_NOREMOVE, + ) + }; + let has_next_key_message = peek_retval != 0; + let mut valid_event_info = Some(event_info); + if has_next_key_message { + let next_msg = unsafe { next_msg.assume_init() }; + let (_, layout) = layouts.get_current_layout(); + let is_fake = { + let event_info = valid_event_info.as_ref().unwrap(); + is_current_fake(&event_info, next_msg, layout) + }; + if is_fake { + valid_event_info = None; + } + } + if let Some(event_info) = valid_event_info { + let event = event_info.finalize(&mut layouts.strings); + return vec![MessageAsKeyEvent { + event, + is_synthetic: false, + }]; + } + } + _ => (), + } + + Vec::new() + } + + fn synthesize_kbd_state( + &mut self, + key_state: ElementState, + kbd_state: &[u8; 256], + ) -> Vec { + let mut key_events = Vec::new(); + + let mut layouts = LAYOUT_CACHE.lock().unwrap(); + let (locale_id, _) = layouts.get_current_layout(); + + macro_rules! is_key_pressed { + ($vk:expr) => { + kbd_state[$vk as usize] & 0x80 != 0 + }; + } + + // Is caps-lock active? Note that this is different from caps-lock + // being held down. + let caps_lock_on = kbd_state[winuser::VK_CAPITAL as usize] & 1 != 0; + let num_lock_on = kbd_state[winuser::VK_NUMLOCK as usize] & 1 != 0; + + // We are synthesizing the press event for caps-lock first for the following reasons: + // 1. If caps-lock is *not* held down but *is* active, then we have to + // synthesize all printable keys, respecting the caps-lock state. + // 2. If caps-lock is held down, we could choose to sythesize its + // keypress after every other key, in which case all other keys *must* + // be sythesized as if the caps-lock state was be the opposite + // of what it currently is. + // -- + // For the sake of simplicity we are choosing to always sythesize + // caps-lock first, and always use the current caps-lock state + // to determine the produced text + if is_key_pressed!(winuser::VK_CAPITAL) { + let event = self.create_synthetic( + winuser::VK_CAPITAL, + key_state, + caps_lock_on, + num_lock_on, + locale_id as HKL, + &mut layouts, + ); + if let Some(event) = event { + key_events.push(event); + } + } + let do_non_modifier = |key_events: &mut Vec<_>, layouts: &mut _| { + for vk in 0..256 { + match vk { + winuser::VK_CONTROL + | winuser::VK_LCONTROL + | winuser::VK_RCONTROL + | winuser::VK_SHIFT + | winuser::VK_LSHIFT + | winuser::VK_RSHIFT + | winuser::VK_MENU + | winuser::VK_LMENU + | winuser::VK_RMENU + | winuser::VK_CAPITAL => continue, + _ => (), + } + if !is_key_pressed!(vk) { + continue; + } + let event = self.create_synthetic( + vk, + key_state, + caps_lock_on, + num_lock_on, + locale_id as HKL, + layouts, + ); + if let Some(event) = event { + key_events.push(event); + } + } + }; + let do_modifier = |key_events: &mut Vec<_>, layouts: &mut _| { + const CLEAR_MODIFIER_VKS: [i32; 6] = [ + winuser::VK_LCONTROL, + winuser::VK_LSHIFT, + winuser::VK_LMENU, + winuser::VK_RCONTROL, + winuser::VK_RSHIFT, + winuser::VK_RMENU, + ]; + for vk in CLEAR_MODIFIER_VKS.iter() { + if is_key_pressed!(*vk) { + let event = self.create_synthetic( + *vk, + key_state, + caps_lock_on, + num_lock_on, + locale_id as HKL, + layouts, + ); + if let Some(event) = event { + key_events.push(event); + } + } + } + }; + + // Be cheeky and sequence modifier and non-modifier + // key events such that non-modifier keys are not affected + // by modifiers (except for caps-lock) + match key_state { + ElementState::Pressed => { + do_non_modifier(&mut key_events, &mut layouts); + do_modifier(&mut key_events, &mut layouts); + } + ElementState::Released => { + do_modifier(&mut key_events, &mut layouts); + do_non_modifier(&mut key_events, &mut layouts); + } + } + + key_events + } + + fn create_synthetic( + &self, + vk: i32, + key_state: ElementState, + caps_lock_on: bool, + num_lock_on: bool, + locale_id: HKL, + layouts: &mut MutexGuard<'_, LayoutCache>, + ) -> Option { + let scancode = unsafe { + winuser::MapVirtualKeyExW(vk as UINT, winuser::MAPVK_VK_TO_VSC_EX, locale_id) + }; + if scancode == 0 { + return None; + } + let scancode = scancode as ExScancode; + let code = KeyCode::from_scancode(scancode as u32); + let mods = if caps_lock_on { + WindowsModifiers::CAPS_LOCK + } else { + WindowsModifiers::empty() + }; + let layout = layouts.layouts.get(&(locale_id as u64)).unwrap(); + let logical_key = layout.get_key(mods, num_lock_on, vk, scancode, code); + let key_without_modifiers = + layout.get_key(WindowsModifiers::empty(), false, vk, scancode, code); + let text; + if key_state == ElementState::Pressed { + text = logical_key.to_text(); + } else { + text = None; + } + let event_info = PartialKeyEventInfo { + vkey: vk, + logical_key: PartialLogicalKey::This(logical_key), + key_without_modifiers, + key_state, + scancode, + is_repeat: false, + code, + location: get_location(scancode, locale_id), + utf16parts: Vec::with_capacity(8), + text: PartialText::Text(text), + }; + + let mut event = event_info.finalize(&mut layouts.strings); + event.logical_key = logical_key; + event.platform_specific.text_with_all_modifers = text; + Some(MessageAsKeyEvent { + event, + is_synthetic: true, + }) + } +} + +enum PartialText { + // Unicode + System(Vec), + Text(Option<&'static str>), +} + +enum PartialLogicalKey { + /// Use the text provided by the WM_CHAR messages and report that as a `Character` variant. If + /// the text consists of multiple grapheme clusters (user-precieved characters) that means that + /// dead key could not be combined with the second input, and in that case we should fall back + /// to using what would have without a dead-key input. + TextOr(Key<'static>), + + /// Use the value directly provided by this variant + This(Key<'static>), +} + +struct PartialKeyEventInfo { + vkey: c_int, + scancode: ExScancode, + key_state: ElementState, + is_repeat: bool, + code: KeyCode, + location: KeyLocation, + logical_key: PartialLogicalKey, + + key_without_modifiers: Key<'static>, + + /// The UTF-16 code units of the text that was produced by the keypress event. + /// This take all modifiers into account. Including CTRL + utf16parts: Vec, + + text: PartialText, +} + +impl PartialKeyEventInfo { + fn from_message( + wparam: WPARAM, + lparam: LPARAM, + state: ElementState, + layouts: &mut MutexGuard<'_, LayoutCache>, + ) -> Self { + const NO_MODS: WindowsModifiers = WindowsModifiers::empty(); + + let (_, layout) = layouts.get_current_layout(); + let lparam_struct = destructure_key_lparam(lparam); + let scancode; + let vkey = wparam as c_int; + if lparam_struct.scancode == 0 { + // In some cases (often with media keys) the device reports a scancode of 0 but a + // valid virtual key. In these cases we obtain the scancode from the virtual key. + scancode = unsafe { + winuser::MapVirtualKeyExW( + vkey as u32, + winuser::MAPVK_VK_TO_VSC_EX, + layout.hkl as HKL, + ) as u16 + }; + } else { + scancode = new_ex_scancode(lparam_struct.scancode, lparam_struct.extended); + } + let code = KeyCode::from_scancode(scancode as u32); + let location = get_location(scancode, layout.hkl as HKL); + + let kbd_state = get_kbd_state(); + let mods = WindowsModifiers::active_modifiers(&kbd_state); + let mods_without_ctrl = mods.remove_only_ctrl(); + let num_lock_on = kbd_state[winuser::VK_NUMLOCK as usize] & 1 != 0; + + // On Windows Ctrl+NumLock = Pause (and apparently Ctrl+Pause -> NumLock). In these cases + // the KeyCode still stores the real key, so in the name of consistency across platforms, we + // circumvent this mapping and force the key values to match the keycode. + // For more on this, read the article by Raymond Chen, titled: + // "Why does Ctrl+ScrollLock cancel dialogs?" + // https://devblogs.microsoft.com/oldnewthing/20080211-00/?p=23503 + let code_as_key = if mods.contains(WindowsModifiers::CONTROL) { + match code { + KeyCode::NumLock => Some(Key::NumLock), + KeyCode::Pause => Some(Key::Pause), + _ => None, + } + } else { + None + }; + + let preliminary_logical_key = + layout.get_key(mods_without_ctrl, num_lock_on, vkey, scancode, code); + let key_is_char = matches!(preliminary_logical_key, Key::Character(_)); + let is_pressed = state == ElementState::Pressed; + + let logical_key = if let Some(key) = code_as_key { + PartialLogicalKey::This(key) + } else if is_pressed && key_is_char && !mods.contains(WindowsModifiers::CONTROL) { + // In some cases we want to use the UNICHAR text for logical_key in order to allow + // dead keys to have an effect on the character reported by `logical_key`. + PartialLogicalKey::TextOr(preliminary_logical_key) + } else { + PartialLogicalKey::This(preliminary_logical_key) + }; + let key_without_modifiers = if let Some(key) = code_as_key { + key + } else { + match layout.get_key(NO_MODS, false, vkey, scancode, code) { + // We convert dead keys into their character. + // The reason for this is that `key_without_modifiers` is designed for key-bindings, + // but the US International layout treats `'` (apostrophe) as a dead key and the + // reguar US layout treats it a character. In order for a single binding + // configuration to work with both layouts, we forward each dead key as a character. + Key::Dead(k) => { + if let Some(ch) = k { + // I'm avoiding the heap allocation. I don't want to talk about it :( + let mut utf8 = [0; 4]; + let s = ch.encode_utf8(&mut utf8); + let static_str = get_or_insert_str(&mut layouts.strings, s); + Key::Character(static_str) + } else { + Key::Unidentified(NativeKeyCode::Unidentified) + } + } + key => key, + } + }; + + PartialKeyEventInfo { + vkey, + scancode, + key_state: state, + logical_key, + key_without_modifiers, + is_repeat: lparam_struct.is_repeat, + code, + location, + utf16parts: Vec::with_capacity(8), + text: PartialText::System(Vec::new()), + } + } + + fn finalize(self, strings: &mut HashSet<&'static str>) -> KeyEvent { + let mut char_with_all_modifiers = None; + if !self.utf16parts.is_empty() { + let os_string = OsString::from_wide(&self.utf16parts); + if let Ok(string) = os_string.into_string() { + let static_str = get_or_insert_str(strings, string); + char_with_all_modifiers = Some(static_str); + } + } + + // The text without Ctrl + let mut text = None; + match self.text { + PartialText::System(wide) => { + if !wide.is_empty() { + let os_string = OsString::from_wide(&wide); + if let Ok(string) = os_string.into_string() { + let static_str = get_or_insert_str(strings, string); + text = Some(static_str); + } + } + } + PartialText::Text(s) => { + text = s; + } + } + + let logical_key = match self.logical_key { + PartialLogicalKey::TextOr(fallback) => match text { + Some(s) => { + if s.grapheme_indices(true).count() > 1 { + fallback + } else { + Key::Character(s) + } + } + None => Key::Unidentified(NativeKeyCode::Windows(self.scancode)), + }, + PartialLogicalKey::This(v) => v, + }; + + KeyEvent { + physical_key: self.code, + logical_key, + text, + location: self.location, + state: self.key_state, + repeat: self.is_repeat, + platform_specific: KeyEventExtra { + text_with_all_modifers: char_with_all_modifiers, + key_without_modifiers: self.key_without_modifiers, + }, + } + } +} + +#[derive(Debug, Copy, Clone)] +struct KeyLParam { + pub scancode: u8, + pub extended: bool, + + /// This is `previous_state XOR transition_state`. See the lParam for WM_KEYDOWN and WM_KEYUP for further details. + pub is_repeat: bool, +} + +fn destructure_key_lparam(lparam: LPARAM) -> KeyLParam { + let previous_state = (lparam >> 30) & 0x01; + let transition_state = (lparam >> 31) & 0x01; + KeyLParam { + scancode: ((lparam >> 16) & 0xFF) as u8, + extended: ((lparam >> 24) & 0x01) != 0, + is_repeat: (previous_state ^ transition_state) != 0, + } +} + +#[inline] +fn new_ex_scancode(scancode: u8, extended: bool) -> ExScancode { + (scancode as u16) | (if extended { 0xE000 } else { 0 }) +} + +#[inline] +fn ex_scancode_from_lparam(lparam: LPARAM) -> ExScancode { + let lparam = destructure_key_lparam(lparam); + new_ex_scancode(lparam.scancode, lparam.extended) +} + +/// Gets the keyboard state as reported by messages that have been removed from the event queue. +/// See also: get_async_kbd_state +fn get_kbd_state() -> [u8; 256] { + unsafe { + let mut kbd_state: MaybeUninit<[u8; 256]> = MaybeUninit::uninit(); + winuser::GetKeyboardState(kbd_state.as_mut_ptr() as *mut u8); + kbd_state.assume_init() + } +} + +/// Gets the current keyboard state regardless of whether the corresponding keyboard events have +/// been removed from the event queue. See also: get_kbd_state +fn get_async_kbd_state() -> [u8; 256] { + unsafe { + let mut kbd_state: [u8; 256] = MaybeUninit::uninit().assume_init(); + for (vk, state) in kbd_state.iter_mut().enumerate() { + let vk = vk as c_int; + let async_state = winuser::GetAsyncKeyState(vk as c_int); + let is_down = (async_state & (1 << 15)) != 0; + *state = if is_down { 0x80 } else { 0 }; + + if matches!( + vk, + winuser::VK_CAPITAL | winuser::VK_NUMLOCK | winuser::VK_SCROLL + ) { + // Toggle states aren't reported by `GetAsyncKeyState` + let toggle_state = winuser::GetKeyState(vk); + let is_active = (toggle_state & 1) != 0; + *state |= if is_active { 1 } else { 0 }; + } + } + kbd_state + } +} + +/// On windows, AltGr == Ctrl + Alt +/// +/// Due to this equivalence, the system generates a fake Ctrl key-press (and key-release) preceeding +/// every AltGr key-press (and key-release). We check if the current event is a Ctrl event and if +/// the next event is a right Alt (AltGr) event. If this is the case, the current event must be the +/// fake Ctrl event. +fn is_current_fake( + curr_info: &PartialKeyEventInfo, + next_msg: winuser::MSG, + layout: &Layout, +) -> bool { + let curr_is_ctrl = matches!(curr_info.logical_key, PartialLogicalKey::This(Key::Control)); + if layout.has_alt_graph { + let next_code = ex_scancode_from_lparam(next_msg.lParam); + let next_is_altgr = next_code == 0xE038; // 0xE038 is right alt + if curr_is_ctrl && next_is_altgr { + return true; + } + } + false +} + +fn get_location(scancode: ExScancode, hkl: HKL) -> KeyLocation { + use winuser::*; + const VK_ABNT_C2: c_int = 0xc2; + + let extension = 0xE000; + let extended = (scancode & extension) == extension; + let vkey = unsafe { + winuser::MapVirtualKeyExW(scancode as u32, winuser::MAPVK_VSC_TO_VK_EX, hkl) as i32 + }; + + // Use the native VKEY and the extended flag to cover most cases + // This is taken from the `druid` GUI library, specifically + // druid-shell/src/platform/windows/keyboard.rs + match vkey { + VK_LSHIFT | VK_LCONTROL | VK_LMENU | VK_LWIN => KeyLocation::Left, + VK_RSHIFT | VK_RCONTROL | VK_RMENU | VK_RWIN => KeyLocation::Right, + VK_RETURN if extended => KeyLocation::Numpad, + VK_INSERT | VK_DELETE | VK_END | VK_DOWN | VK_NEXT | VK_LEFT | VK_CLEAR | VK_RIGHT + | VK_HOME | VK_UP | VK_PRIOR => { + if extended { + KeyLocation::Standard + } else { + KeyLocation::Numpad + } + } + VK_NUMPAD0 | VK_NUMPAD1 | VK_NUMPAD2 | VK_NUMPAD3 | VK_NUMPAD4 | VK_NUMPAD5 + | VK_NUMPAD6 | VK_NUMPAD7 | VK_NUMPAD8 | VK_NUMPAD9 | VK_DECIMAL | VK_DIVIDE + | VK_MULTIPLY | VK_SUBTRACT | VK_ADD | VK_ABNT_C2 => KeyLocation::Numpad, + _ => KeyLocation::Standard, + } +} diff --git a/src/platform_impl/windows/keyboard_layout.rs b/src/platform_impl/windows/keyboard_layout.rs new file mode 100644 index 0000000000..3f1100b9b4 --- /dev/null +++ b/src/platform_impl/windows/keyboard_layout.rs @@ -0,0 +1,993 @@ +use std::{ + collections::{hash_map::Entry, HashMap, HashSet}, + ffi::OsString, + os::windows::ffi::OsStringExt, + sync::Mutex, +}; + +use lazy_static::lazy_static; + +use winapi::{ + ctypes::c_int, + shared::minwindef::{HKL, LOWORD}, + um::{ + winnt::{LANG_JAPANESE, LANG_KOREAN, PRIMARYLANGID}, + winuser, + }, +}; + +use crate::{ + keyboard::{Key, KeyCode, ModifiersState, NativeKeyCode}, + platform::scancode::KeyCodeExtScancode, + platform_impl::platform::keyboard::ExScancode, +}; + +lazy_static! { + pub(crate) static ref LAYOUT_CACHE: Mutex = Mutex::new(LayoutCache::default()); +} + +fn key_pressed(vkey: c_int) -> bool { + unsafe { (winuser::GetKeyState(vkey) & (1 << 15)) == (1 << 15) } +} + +const NUMPAD_VKEYS: [c_int; 16] = [ + winuser::VK_NUMPAD0, + winuser::VK_NUMPAD1, + winuser::VK_NUMPAD2, + winuser::VK_NUMPAD3, + winuser::VK_NUMPAD4, + winuser::VK_NUMPAD5, + winuser::VK_NUMPAD6, + winuser::VK_NUMPAD7, + winuser::VK_NUMPAD8, + winuser::VK_NUMPAD9, + winuser::VK_MULTIPLY, + winuser::VK_ADD, + winuser::VK_SEPARATOR, + winuser::VK_SUBTRACT, + winuser::VK_DECIMAL, + winuser::VK_DIVIDE, +]; + +lazy_static! { + static ref NUMPAD_KEYCODES: HashSet = { + let mut keycodes = HashSet::new(); + keycodes.insert(KeyCode::Numpad0); + keycodes.insert(KeyCode::Numpad1); + keycodes.insert(KeyCode::Numpad2); + keycodes.insert(KeyCode::Numpad3); + keycodes.insert(KeyCode::Numpad4); + keycodes.insert(KeyCode::Numpad5); + keycodes.insert(KeyCode::Numpad6); + keycodes.insert(KeyCode::Numpad7); + keycodes.insert(KeyCode::Numpad8); + keycodes.insert(KeyCode::Numpad9); + keycodes.insert(KeyCode::NumpadMultiply); + keycodes.insert(KeyCode::NumpadAdd); + keycodes.insert(KeyCode::NumpadComma); + keycodes.insert(KeyCode::NumpadSubtract); + keycodes.insert(KeyCode::NumpadDecimal); + keycodes.insert(KeyCode::NumpadDivide); + keycodes + }; +} + +bitflags! { + pub struct WindowsModifiers : u8 { + const SHIFT = 1 << 0; + const CONTROL = 1 << 1; + const ALT = 1 << 2; + const CAPS_LOCK = 1 << 3; + const FLAGS_END = 1 << 4; + } +} + +impl WindowsModifiers { + pub fn active_modifiers(key_state: &[u8; 256]) -> WindowsModifiers { + let shift = key_state[winuser::VK_SHIFT as usize] & 0x80 != 0; + let lshift = key_state[winuser::VK_LSHIFT as usize] & 0x80 != 0; + let rshift = key_state[winuser::VK_RSHIFT as usize] & 0x80 != 0; + + let control = key_state[winuser::VK_CONTROL as usize] & 0x80 != 0; + let lcontrol = key_state[winuser::VK_LCONTROL as usize] & 0x80 != 0; + let rcontrol = key_state[winuser::VK_RCONTROL as usize] & 0x80 != 0; + + let alt = key_state[winuser::VK_MENU as usize] & 0x80 != 0; + let lalt = key_state[winuser::VK_LMENU as usize] & 0x80 != 0; + let ralt = key_state[winuser::VK_RMENU as usize] & 0x80 != 0; + + let caps = key_state[winuser::VK_CAPITAL as usize] & 0x01 != 0; + + let mut result = WindowsModifiers::empty(); + if shift || lshift || rshift { + result.insert(WindowsModifiers::SHIFT); + } + if control || lcontrol || rcontrol { + result.insert(WindowsModifiers::CONTROL); + } + if alt || lalt || ralt { + result.insert(WindowsModifiers::ALT); + } + if caps { + result.insert(WindowsModifiers::CAPS_LOCK); + } + + result + } + + pub fn apply_to_kbd_state(self, key_state: &mut [u8; 256]) { + if self.intersects(Self::SHIFT) { + key_state[winuser::VK_SHIFT as usize] |= 0x80; + } else { + key_state[winuser::VK_SHIFT as usize] &= !0x80; + key_state[winuser::VK_LSHIFT as usize] &= !0x80; + key_state[winuser::VK_RSHIFT as usize] &= !0x80; + } + if self.intersects(Self::CONTROL) { + key_state[winuser::VK_CONTROL as usize] |= 0x80; + } else { + key_state[winuser::VK_CONTROL as usize] &= !0x80; + key_state[winuser::VK_LCONTROL as usize] &= !0x80; + key_state[winuser::VK_RCONTROL as usize] &= !0x80; + } + if self.intersects(Self::ALT) { + key_state[winuser::VK_MENU as usize] |= 0x80; + } else { + key_state[winuser::VK_MENU as usize] &= !0x80; + key_state[winuser::VK_LMENU as usize] &= !0x80; + key_state[winuser::VK_RMENU as usize] &= !0x80; + } + if self.intersects(Self::CAPS_LOCK) { + key_state[winuser::VK_CAPITAL as usize] |= 0x01; + } else { + key_state[winuser::VK_CAPITAL as usize] &= !0x01; + } + } + + /// Removes the control modifier if the alt modifier is not present. + /// This is useful because on Windows: (Control + Alt) == AltGr + /// but we don't want to interfere with the AltGr state. + pub fn remove_only_ctrl(mut self) -> WindowsModifiers { + if !self.contains(WindowsModifiers::ALT) { + self.remove(WindowsModifiers::CONTROL); + } + self + } +} + +pub(crate) struct Layout { + pub hkl: u64, + + /// Maps numpad keys from Windows virtual key to a `Key`. + /// + /// This is useful because some numpad keys generate different charcaters based on the locale. + /// For example `VK_DECIMAL` is sometimes "." and sometimes ",". Note: numpad-specific virtual + /// keys are only produced by Windows when the NumLock is active. + /// + /// Making this field separate from the `keys` field saves having to add NumLock as a modifier + /// to `WindowsModifiers`, which would double the number of items in keys. + pub numlock_on_keys: HashMap>, + /// Like `numlock_on_keys` but this will map to the key that would be produced if numlock was + /// off. The keys of this map are identical to the keys of `numlock_on_keys`. + pub numlock_off_keys: HashMap>, + + /// Maps a modifier state to group of key strings + /// We're not using `ModifiersState` here because that object cannot express caps lock, + /// but we need to handle caps lock too. + /// + /// This map shouldn't need to exist. + /// However currently this seems to be the only good way + /// of getting the label for the pressed key. Note that calling `ToUnicode` + /// just when the key is pressed/released would be enough if `ToUnicode` wouldn't + /// change the keyboard state (it clears the dead key). There is a flag to prevent + /// changing the state, but that flag requires Windows 10, version 1607 or newer) + pub keys: HashMap>>, + pub has_alt_graph: bool, +} + +impl Layout { + pub fn get_key( + &self, + mods: WindowsModifiers, + num_lock_on: bool, + vkey: c_int, + scancode: ExScancode, + keycode: KeyCode, + ) -> Key<'static> { + let native_code = NativeKeyCode::Windows(scancode); + + let unknown_alt = vkey == winuser::VK_MENU; + if !unknown_alt { + // Here we try using the virtual key directly but if the virtual key doesn't distinguish + // between left and right alt, we can't report AltGr. Therefore, we only do this if the + // key is not the "unknown alt" key. + // + // The reason for using the virtual key directly is that `MapVirtualKeyExW` (used when + // building the keys map) sometimes maps virtual keys to odd scancodes that don't match + // the scancode coming from the KEYDOWN message for the same key. For example: `VK_LEFT` + // is mapped to `0x004B`, but the scancode for the left arrow is `0xE04B`. + let key_from_vkey = + vkey_to_non_char_key(vkey, native_code, self.hkl, self.has_alt_graph); + + if !matches!(key_from_vkey, Key::Unidentified(_)) { + return key_from_vkey; + } + } + if num_lock_on { + if let Some(key) = self.numlock_on_keys.get(&vkey) { + return *key; + } + } else { + if let Some(key) = self.numlock_off_keys.get(&vkey) { + return *key; + } + } + if let Some(keys) = self.keys.get(&mods) { + if let Some(key) = keys.get(&keycode) { + return *key; + } + } + Key::Unidentified(native_code) + } +} + +#[derive(Default)] +pub(crate) struct LayoutCache { + /// Maps locale identifiers (HKL) to layouts + pub layouts: HashMap, + pub strings: HashSet<&'static str>, +} + +impl LayoutCache { + /// Checks whether the current layout is already known and + /// prepares the layout if it isn't known. + /// The current layout is then returned. + pub fn get_current_layout<'a>(&'a mut self) -> (u64, &'a Layout) { + let locale_id = unsafe { winuser::GetKeyboardLayout(0) } as u64; + match self.layouts.entry(locale_id) { + Entry::Occupied(entry) => (locale_id, entry.into_mut()), + Entry::Vacant(entry) => { + let layout = Self::prepare_layout(&mut self.strings, locale_id); + (locale_id, entry.insert(layout)) + } + } + } + + pub fn get_agnostic_mods(&mut self) -> ModifiersState { + let (_, layout) = self.get_current_layout(); + let filter_out_altgr = layout.has_alt_graph && key_pressed(winuser::VK_RMENU); + let mut mods = ModifiersState::empty(); + mods.set(ModifiersState::SHIFT, key_pressed(winuser::VK_SHIFT)); + mods.set( + ModifiersState::CONTROL, + key_pressed(winuser::VK_CONTROL) && !filter_out_altgr, + ); + mods.set( + ModifiersState::ALT, + key_pressed(winuser::VK_MENU) && !filter_out_altgr, + ); + mods.set( + ModifiersState::SUPER, + key_pressed(winuser::VK_LWIN) || key_pressed(winuser::VK_RWIN), + ); + mods + } + + fn prepare_layout(strings: &mut HashSet<&'static str>, locale_id: u64) -> Layout { + let mut layout = Layout { + hkl: locale_id, + numlock_on_keys: Default::default(), + numlock_off_keys: Default::default(), + keys: Default::default(), + has_alt_graph: false, + }; + + // We initialize the keyboard state with all zeros to + // simulate a scenario when no modifier is active. + let mut key_state = [0u8; 256]; + + // `MapVirtualKeyExW` maps (non-numpad-specific) virtual keys to scancodes as if numlock + // was off. We rely on this behavior to find all virtual keys which are not numpad-specific + // but map to the numpad. + // + // src_vkey: VK ==> scancode: u16 (on the numpad) + // + // Then we convert the source virtual key into a `Key` and the scancode into a virtual key + // to get the reverse mapping. + // + // src_vkey: VK ==> scancode: u16 (on the numpad) + // || || + // \/ \/ + // map_value: Key <- map_vkey: VK + layout.numlock_off_keys.reserve(NUMPAD_KEYCODES.len()); + for vk in 0..256 { + let scancode = unsafe { + winuser::MapVirtualKeyExW(vk, winuser::MAPVK_VK_TO_VSC_EX, locale_id as HKL) + }; + if scancode == 0 { + continue; + } + let keycode = KeyCode::from_scancode(scancode); + if !is_numpad_specific(vk as i32) && NUMPAD_KEYCODES.contains(&keycode) { + let native_code = NativeKeyCode::Windows(scancode as u16); + let map_vkey = keycode_to_vkey(keycode, locale_id); + if map_vkey == 0 { + continue; + } + let map_value = vkey_to_non_char_key(vk as i32, native_code, locale_id, false); + if matches!(map_value, Key::Unidentified(_)) { + continue; + } + layout.numlock_off_keys.insert(map_vkey, map_value); + } + } + + layout.numlock_on_keys.reserve(NUMPAD_VKEYS.len()); + for vk in NUMPAD_VKEYS.iter() { + let vk = (*vk) as u32; + let scancode = unsafe { + winuser::MapVirtualKeyExW(vk, winuser::MAPVK_VK_TO_VSC_EX, locale_id as HKL) + }; + let unicode = Self::to_unicode_string(&key_state, vk, scancode, locale_id); + if let ToUnicodeResult::Str(s) = unicode { + let static_str = get_or_insert_str(strings, s); + layout + .numlock_on_keys + .insert(vk as i32, Key::Character(static_str)); + } + } + + // Iterate through every combination of modifiers + let mods_end = WindowsModifiers::FLAGS_END.bits; + for mod_state in 0..mods_end { + let mut keys_for_this_mod = HashMap::with_capacity(256); + + let mod_state = unsafe { WindowsModifiers::from_bits_unchecked(mod_state) }; + mod_state.apply_to_kbd_state(&mut key_state); + + // Virtual key values are in the domain [0, 255]. + // This is reinforced by the fact that the keyboard state array has 256 + // elements. This array is allowed to be indexed by virtual key values + // giving the key state for the virtual key used for indexing. + for vk in 0..256 { + let scancode = unsafe { + winuser::MapVirtualKeyExW(vk, winuser::MAPVK_VK_TO_VSC_EX, locale_id as HKL) + }; + if scancode == 0 { + continue; + } + + let native_code = NativeKeyCode::Windows(scancode as ExScancode); + let key_code = KeyCode::from_scancode(scancode); + // Let's try to get the key from just the scancode and vk + // We don't necessarily know yet if AltGraph is present on this layout so we'll + // assume it isn't. Then we'll do a second pass where we set the "AltRight" keys to + // "AltGr" in case we find out that there's an AltGraph. + let preliminary_key = + vkey_to_non_char_key(vk as i32, native_code, locale_id, false); + match preliminary_key { + Key::Unidentified(_) => (), + _ => { + keys_for_this_mod.insert(key_code, preliminary_key); + continue; + } + } + + let unicode = Self::to_unicode_string(&key_state, vk, scancode, locale_id); + let key = match unicode { + ToUnicodeResult::Str(str) => { + let static_str = get_or_insert_str(strings, str); + Key::Character(static_str) + } + ToUnicodeResult::Dead(dead_char) => { + //println!("{:?} - {:?} produced dead {:?}", key_code, mod_state, dead_char); + Key::Dead(dead_char) + } + ToUnicodeResult::None => { + let has_alt = mod_state.contains(WindowsModifiers::ALT); + let has_ctrl = mod_state.contains(WindowsModifiers::CONTROL); + // HACK: `ToUnicodeEx` seems to fail getting the string for the numpad + // divide key, so we handle that explicitly here + if !has_alt && !has_ctrl && key_code == KeyCode::NumpadDivide { + Key::Character("/") + } else { + // Just use the unidentified key, we got earlier + preliminary_key + } + } + }; + + // Check for alt graph. + // The logic is that if a key pressed with no modifier produces + // a different `Character` from when it's pressed with CTRL+ALT then the layout + // has AltGr. + let ctrl_alt: WindowsModifiers = WindowsModifiers::CONTROL | WindowsModifiers::ALT; + let is_in_ctrl_alt = mod_state == ctrl_alt; + if !layout.has_alt_graph && is_in_ctrl_alt { + // Unwrapping here because if we are in the ctrl+alt modifier state + // then the alt modifier state must have come before. + let simple_keys = layout.keys.get(&WindowsModifiers::empty()).unwrap(); + if let Some(Key::Character(key_no_altgr)) = simple_keys.get(&key_code) { + if let Key::Character(key) = key { + layout.has_alt_graph = key != *key_no_altgr; + } + } + } + + keys_for_this_mod.insert(key_code, key); + } + layout.keys.insert(mod_state, keys_for_this_mod); + } + + // Second pass: replace right alt keys with AltGr if the layout has alt graph + if layout.has_alt_graph { + for mod_state in 0..mods_end { + let mod_state = unsafe { WindowsModifiers::from_bits_unchecked(mod_state) }; + if let Some(keys) = layout.keys.get_mut(&mod_state) { + if let Some(key) = keys.get_mut(&KeyCode::AltRight) { + *key = Key::AltGraph; + } + } + } + } + + layout + } + + fn to_unicode_string( + key_state: &[u8; 256], + vkey: u32, + scancode: u32, + locale_id: u64, + ) -> ToUnicodeResult { + unsafe { + let mut label_wide = [0u16; 8]; + let mut wide_len = winuser::ToUnicodeEx( + vkey, + scancode, + (&key_state[0]) as *const _, + (&mut label_wide[0]) as *mut _, + label_wide.len() as i32, + 0, + locale_id as HKL, + ); + if wide_len < 0 { + // If it's dead, we run `ToUnicode` again to consume the dead-key + wide_len = winuser::ToUnicodeEx( + vkey, + scancode, + (&key_state[0]) as *const _, + (&mut label_wide[0]) as *mut _, + label_wide.len() as i32, + 0, + locale_id as HKL, + ); + if wide_len > 0 { + let os_string = OsString::from_wide(&label_wide[0..wide_len as usize]); + if let Ok(label_str) = os_string.into_string() { + if let Some(ch) = label_str.chars().next() { + return ToUnicodeResult::Dead(Some(ch)); + } + } + } + return ToUnicodeResult::Dead(None); + } + if wide_len > 0 { + let os_string = OsString::from_wide(&label_wide[0..wide_len as usize]); + if let Ok(label_str) = os_string.into_string() { + return ToUnicodeResult::Str(label_str); + } + } + } + ToUnicodeResult::None + } +} + +pub fn get_or_insert_str(strings: &mut HashSet<&'static str>, string: T) -> &'static str +where + T: AsRef, + String: From, +{ + { + let str_ref = string.as_ref(); + if let Some(&existing) = strings.get(str_ref) { + return existing; + } + } + let leaked = Box::leak(Box::from(String::from(string))); + strings.insert(leaked); + leaked +} + +#[derive(Debug, Clone, Eq, PartialEq)] +enum ToUnicodeResult { + Str(String), + Dead(Option), + None, +} + +fn is_numpad_specific(vk: i32) -> bool { + match vk { + winuser::VK_NUMPAD0 => true, + winuser::VK_NUMPAD1 => true, + winuser::VK_NUMPAD2 => true, + winuser::VK_NUMPAD3 => true, + winuser::VK_NUMPAD4 => true, + winuser::VK_NUMPAD5 => true, + winuser::VK_NUMPAD6 => true, + winuser::VK_NUMPAD7 => true, + winuser::VK_NUMPAD8 => true, + winuser::VK_NUMPAD9 => true, + winuser::VK_ADD => true, + winuser::VK_SUBTRACT => true, + winuser::VK_DIVIDE => true, + winuser::VK_DECIMAL => true, + winuser::VK_SEPARATOR => true, + _ => false, + } +} + +fn keycode_to_vkey(keycode: KeyCode, hkl: u64) -> i32 { + let primary_lang_id = PRIMARYLANGID(LOWORD(hkl as u32)); + let is_korean = primary_lang_id == LANG_KOREAN; + let is_japanese = primary_lang_id == LANG_JAPANESE; + + match keycode { + KeyCode::Backquote => 0, + KeyCode::Backslash => 0, + KeyCode::BracketLeft => 0, + KeyCode::BracketRight => 0, + KeyCode::Comma => 0, + KeyCode::Digit0 => 0, + KeyCode::Digit1 => 0, + KeyCode::Digit2 => 0, + KeyCode::Digit3 => 0, + KeyCode::Digit4 => 0, + KeyCode::Digit5 => 0, + KeyCode::Digit6 => 0, + KeyCode::Digit7 => 0, + KeyCode::Digit8 => 0, + KeyCode::Digit9 => 0, + KeyCode::Equal => 0, + KeyCode::IntlBackslash => 0, + KeyCode::IntlRo => 0, + KeyCode::IntlYen => 0, + KeyCode::KeyA => 0, + KeyCode::KeyB => 0, + KeyCode::KeyC => 0, + KeyCode::KeyD => 0, + KeyCode::KeyE => 0, + KeyCode::KeyF => 0, + KeyCode::KeyG => 0, + KeyCode::KeyH => 0, + KeyCode::KeyI => 0, + KeyCode::KeyJ => 0, + KeyCode::KeyK => 0, + KeyCode::KeyL => 0, + KeyCode::KeyM => 0, + KeyCode::KeyN => 0, + KeyCode::KeyO => 0, + KeyCode::KeyP => 0, + KeyCode::KeyQ => 0, + KeyCode::KeyR => 0, + KeyCode::KeyS => 0, + KeyCode::KeyT => 0, + KeyCode::KeyU => 0, + KeyCode::KeyV => 0, + KeyCode::KeyW => 0, + KeyCode::KeyX => 0, + KeyCode::KeyY => 0, + KeyCode::KeyZ => 0, + KeyCode::Minus => 0, + KeyCode::Period => 0, + KeyCode::Quote => 0, + KeyCode::Semicolon => 0, + KeyCode::Slash => 0, + KeyCode::AltLeft => winuser::VK_LMENU, + KeyCode::AltRight => winuser::VK_RMENU, + KeyCode::Backspace => winuser::VK_BACK, + KeyCode::CapsLock => winuser::VK_CAPITAL, + KeyCode::ContextMenu => winuser::VK_APPS, + KeyCode::ControlLeft => winuser::VK_LCONTROL, + KeyCode::ControlRight => winuser::VK_RCONTROL, + KeyCode::Enter => winuser::VK_RETURN, + KeyCode::SuperLeft => winuser::VK_LWIN, + KeyCode::SuperRight => winuser::VK_RWIN, + KeyCode::ShiftLeft => winuser::VK_RSHIFT, + KeyCode::ShiftRight => winuser::VK_LSHIFT, + KeyCode::Space => winuser::VK_SPACE, + KeyCode::Tab => winuser::VK_TAB, + KeyCode::Convert => winuser::VK_CONVERT, + KeyCode::KanaMode => winuser::VK_KANA, + KeyCode::Lang1 if is_korean => winuser::VK_HANGUL, + KeyCode::Lang1 if is_japanese => winuser::VK_KANA, + KeyCode::Lang2 if is_korean => winuser::VK_HANJA, + KeyCode::Lang2 if is_japanese => 0, + KeyCode::Lang3 if is_japanese => winuser::VK_OEM_FINISH, + KeyCode::Lang4 if is_japanese => 0, + KeyCode::Lang5 if is_japanese => 0, + KeyCode::NonConvert => winuser::VK_NONCONVERT, + KeyCode::Delete => winuser::VK_DELETE, + KeyCode::End => winuser::VK_END, + KeyCode::Help => winuser::VK_HELP, + KeyCode::Home => winuser::VK_HOME, + KeyCode::Insert => winuser::VK_INSERT, + KeyCode::PageDown => winuser::VK_NEXT, + KeyCode::PageUp => winuser::VK_PRIOR, + KeyCode::ArrowDown => winuser::VK_DOWN, + KeyCode::ArrowLeft => winuser::VK_LEFT, + KeyCode::ArrowRight => winuser::VK_RIGHT, + KeyCode::ArrowUp => winuser::VK_UP, + KeyCode::NumLock => winuser::VK_NUMLOCK, + KeyCode::Numpad0 => winuser::VK_NUMPAD0, + KeyCode::Numpad1 => winuser::VK_NUMPAD1, + KeyCode::Numpad2 => winuser::VK_NUMPAD2, + KeyCode::Numpad3 => winuser::VK_NUMPAD3, + KeyCode::Numpad4 => winuser::VK_NUMPAD4, + KeyCode::Numpad5 => winuser::VK_NUMPAD5, + KeyCode::Numpad6 => winuser::VK_NUMPAD6, + KeyCode::Numpad7 => winuser::VK_NUMPAD7, + KeyCode::Numpad8 => winuser::VK_NUMPAD8, + KeyCode::Numpad9 => winuser::VK_NUMPAD9, + KeyCode::NumpadAdd => winuser::VK_ADD, + KeyCode::NumpadBackspace => winuser::VK_BACK, + KeyCode::NumpadClear => winuser::VK_CLEAR, + KeyCode::NumpadClearEntry => 0, + KeyCode::NumpadComma => winuser::VK_SEPARATOR, + KeyCode::NumpadDecimal => winuser::VK_DECIMAL, + KeyCode::NumpadDivide => winuser::VK_DIVIDE, + KeyCode::NumpadEnter => winuser::VK_RETURN, + KeyCode::NumpadEqual => 0, + KeyCode::NumpadHash => 0, + KeyCode::NumpadMemoryAdd => 0, + KeyCode::NumpadMemoryClear => 0, + KeyCode::NumpadMemoryRecall => 0, + KeyCode::NumpadMemoryStore => 0, + KeyCode::NumpadMemorySubtract => 0, + KeyCode::NumpadMultiply => winuser::VK_MULTIPLY, + KeyCode::NumpadParenLeft => 0, + KeyCode::NumpadParenRight => 0, + KeyCode::NumpadStar => 0, + KeyCode::NumpadSubtract => winuser::VK_SUBTRACT, + KeyCode::Escape => winuser::VK_ESCAPE, + KeyCode::Fn => 0, + KeyCode::FnLock => 0, + KeyCode::PrintScreen => winuser::VK_SNAPSHOT, + KeyCode::ScrollLock => winuser::VK_SCROLL, + KeyCode::Pause => winuser::VK_PAUSE, + KeyCode::BrowserBack => winuser::VK_BROWSER_BACK, + KeyCode::BrowserFavorites => winuser::VK_BROWSER_FAVORITES, + KeyCode::BrowserForward => winuser::VK_BROWSER_FORWARD, + KeyCode::BrowserHome => winuser::VK_BROWSER_HOME, + KeyCode::BrowserRefresh => winuser::VK_BROWSER_REFRESH, + KeyCode::BrowserSearch => winuser::VK_BROWSER_SEARCH, + KeyCode::BrowserStop => winuser::VK_BROWSER_STOP, + KeyCode::Eject => 0, + KeyCode::LaunchApp1 => winuser::VK_LAUNCH_APP1, + KeyCode::LaunchApp2 => winuser::VK_LAUNCH_APP2, + KeyCode::LaunchMail => winuser::VK_LAUNCH_MAIL, + KeyCode::MediaPlayPause => winuser::VK_MEDIA_PLAY_PAUSE, + KeyCode::MediaSelect => winuser::VK_LAUNCH_MEDIA_SELECT, + KeyCode::MediaStop => winuser::VK_MEDIA_STOP, + KeyCode::MediaTrackNext => winuser::VK_MEDIA_NEXT_TRACK, + KeyCode::MediaTrackPrevious => winuser::VK_MEDIA_PREV_TRACK, + KeyCode::Power => 0, + KeyCode::Sleep => 0, + KeyCode::AudioVolumeDown => winuser::VK_VOLUME_DOWN, + KeyCode::AudioVolumeMute => winuser::VK_VOLUME_MUTE, + KeyCode::AudioVolumeUp => winuser::VK_VOLUME_UP, + KeyCode::WakeUp => 0, + KeyCode::Hyper => 0, + KeyCode::Turbo => 0, + KeyCode::Abort => 0, + KeyCode::Resume => 0, + KeyCode::Suspend => 0, + KeyCode::Again => 0, + KeyCode::Copy => 0, + KeyCode::Cut => 0, + KeyCode::Find => 0, + KeyCode::Open => 0, + KeyCode::Paste => 0, + KeyCode::Props => 0, + KeyCode::Select => winuser::VK_SELECT, + KeyCode::Undo => 0, + KeyCode::Hiragana => 0, + KeyCode::Katakana => 0, + KeyCode::F1 => winuser::VK_F1, + KeyCode::F2 => winuser::VK_F2, + KeyCode::F3 => winuser::VK_F3, + KeyCode::F4 => winuser::VK_F4, + KeyCode::F5 => winuser::VK_F5, + KeyCode::F6 => winuser::VK_F6, + KeyCode::F7 => winuser::VK_F7, + KeyCode::F8 => winuser::VK_F8, + KeyCode::F9 => winuser::VK_F9, + KeyCode::F10 => winuser::VK_F10, + KeyCode::F11 => winuser::VK_F11, + KeyCode::F12 => winuser::VK_F12, + KeyCode::F13 => winuser::VK_F13, + KeyCode::F14 => winuser::VK_F14, + KeyCode::F15 => winuser::VK_F15, + KeyCode::F16 => winuser::VK_F16, + KeyCode::F17 => winuser::VK_F17, + KeyCode::F18 => winuser::VK_F18, + KeyCode::F19 => winuser::VK_F19, + KeyCode::F20 => winuser::VK_F20, + KeyCode::F21 => winuser::VK_F21, + KeyCode::F22 => winuser::VK_F22, + KeyCode::F23 => winuser::VK_F23, + KeyCode::F24 => winuser::VK_F24, + KeyCode::F25 => 0, + KeyCode::F26 => 0, + KeyCode::F27 => 0, + KeyCode::F28 => 0, + KeyCode::F29 => 0, + KeyCode::F30 => 0, + KeyCode::F31 => 0, + KeyCode::F32 => 0, + KeyCode::F33 => 0, + KeyCode::F34 => 0, + KeyCode::F35 => 0, + KeyCode::Unidentified(_) => 0, + _ => 0, + } +} + +/// This converts virtual keys to `Key`s. Only virtual keys which can be unambiguously converted to +/// a `Key`, with only the information passed in as arguments, are converted. +/// +/// In other words: this function does not need to "prepare" the current layout in order to do +/// the conversion, but as such it cannot convert certain keys, like language-specific character keys. +/// +/// The result includes all non-character keys defined within `Key` plus characters from numpad keys. +/// For example, backspace and tab are included. +fn vkey_to_non_char_key( + vkey: i32, + native_code: NativeKeyCode, + hkl: u64, + has_alt_graph: bool, +) -> Key<'static> { + // List of the Web key names and their corresponding platform-native key names: + // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values + + let primary_lang_id = PRIMARYLANGID(LOWORD(hkl as u32)); + let is_korean = primary_lang_id == LANG_KOREAN; + let is_japanese = primary_lang_id == LANG_JAPANESE; + + match vkey { + winuser::VK_LBUTTON => Key::Unidentified(NativeKeyCode::Unidentified), // Mouse + winuser::VK_RBUTTON => Key::Unidentified(NativeKeyCode::Unidentified), // Mouse + + // I don't think this can be represented with a Key + winuser::VK_CANCEL => Key::Unidentified(native_code), + + winuser::VK_MBUTTON => Key::Unidentified(NativeKeyCode::Unidentified), // Mouse + winuser::VK_XBUTTON1 => Key::Unidentified(NativeKeyCode::Unidentified), // Mouse + winuser::VK_XBUTTON2 => Key::Unidentified(NativeKeyCode::Unidentified), // Mouse + winuser::VK_BACK => Key::Backspace, + winuser::VK_TAB => Key::Tab, + winuser::VK_CLEAR => Key::Clear, + winuser::VK_RETURN => Key::Enter, + winuser::VK_SHIFT => Key::Shift, + winuser::VK_CONTROL => Key::Control, + winuser::VK_MENU => Key::Alt, + winuser::VK_PAUSE => Key::Pause, + winuser::VK_CAPITAL => Key::CapsLock, + + //winuser::VK_HANGEUL => Key::HangulMode, // Deprecated in favour of VK_HANGUL + + // VK_HANGUL and VK_KANA are defined as the same constant, therefore + // we use appropriate conditions to differentate between them + winuser::VK_HANGUL if is_korean => Key::HangulMode, + winuser::VK_KANA if is_japanese => Key::KanaMode, + + winuser::VK_JUNJA => Key::JunjaMode, + winuser::VK_FINAL => Key::FinalMode, + + // VK_HANJA and VK_KANJI are defined as the same constant, therefore + // we use appropriate conditions to differentate between them + winuser::VK_HANJA if is_korean => Key::HanjaMode, + winuser::VK_KANJI if is_japanese => Key::KanjiMode, + + winuser::VK_ESCAPE => Key::Escape, + winuser::VK_CONVERT => Key::Convert, + winuser::VK_NONCONVERT => Key::NonConvert, + winuser::VK_ACCEPT => Key::Accept, + winuser::VK_MODECHANGE => Key::ModeChange, + winuser::VK_SPACE => Key::Space, + winuser::VK_PRIOR => Key::PageUp, + winuser::VK_NEXT => Key::PageDown, + winuser::VK_END => Key::End, + winuser::VK_HOME => Key::Home, + winuser::VK_LEFT => Key::ArrowLeft, + winuser::VK_UP => Key::ArrowUp, + winuser::VK_RIGHT => Key::ArrowRight, + winuser::VK_DOWN => Key::ArrowDown, + winuser::VK_SELECT => Key::Select, + winuser::VK_PRINT => Key::Print, + winuser::VK_EXECUTE => Key::Execute, + winuser::VK_SNAPSHOT => Key::PrintScreen, + winuser::VK_INSERT => Key::Insert, + winuser::VK_DELETE => Key::Delete, + winuser::VK_HELP => Key::Help, + winuser::VK_LWIN => Key::Super, + winuser::VK_RWIN => Key::Super, + winuser::VK_APPS => Key::ContextMenu, + winuser::VK_SLEEP => Key::Standby, + + // Numpad keys produce characters + winuser::VK_NUMPAD0 => Key::Unidentified(native_code), + winuser::VK_NUMPAD1 => Key::Unidentified(native_code), + winuser::VK_NUMPAD2 => Key::Unidentified(native_code), + winuser::VK_NUMPAD3 => Key::Unidentified(native_code), + winuser::VK_NUMPAD4 => Key::Unidentified(native_code), + winuser::VK_NUMPAD5 => Key::Unidentified(native_code), + winuser::VK_NUMPAD6 => Key::Unidentified(native_code), + winuser::VK_NUMPAD7 => Key::Unidentified(native_code), + winuser::VK_NUMPAD8 => Key::Unidentified(native_code), + winuser::VK_NUMPAD9 => Key::Unidentified(native_code), + winuser::VK_MULTIPLY => Key::Unidentified(native_code), + winuser::VK_ADD => Key::Unidentified(native_code), + winuser::VK_SEPARATOR => Key::Unidentified(native_code), + winuser::VK_SUBTRACT => Key::Unidentified(native_code), + winuser::VK_DECIMAL => Key::Unidentified(native_code), + winuser::VK_DIVIDE => Key::Unidentified(native_code), + + winuser::VK_F1 => Key::F1, + winuser::VK_F2 => Key::F2, + winuser::VK_F3 => Key::F3, + winuser::VK_F4 => Key::F4, + winuser::VK_F5 => Key::F5, + winuser::VK_F6 => Key::F6, + winuser::VK_F7 => Key::F7, + winuser::VK_F8 => Key::F8, + winuser::VK_F9 => Key::F9, + winuser::VK_F10 => Key::F10, + winuser::VK_F11 => Key::F11, + winuser::VK_F12 => Key::F12, + winuser::VK_F13 => Key::F13, + winuser::VK_F14 => Key::F14, + winuser::VK_F15 => Key::F15, + winuser::VK_F16 => Key::F16, + winuser::VK_F17 => Key::F17, + winuser::VK_F18 => Key::F18, + winuser::VK_F19 => Key::F19, + winuser::VK_F20 => Key::F20, + winuser::VK_F21 => Key::F21, + winuser::VK_F22 => Key::F22, + winuser::VK_F23 => Key::F23, + winuser::VK_F24 => Key::F24, + winuser::VK_NAVIGATION_VIEW => Key::Unidentified(native_code), + winuser::VK_NAVIGATION_MENU => Key::Unidentified(native_code), + winuser::VK_NAVIGATION_UP => Key::Unidentified(native_code), + winuser::VK_NAVIGATION_DOWN => Key::Unidentified(native_code), + winuser::VK_NAVIGATION_LEFT => Key::Unidentified(native_code), + winuser::VK_NAVIGATION_RIGHT => Key::Unidentified(native_code), + winuser::VK_NAVIGATION_ACCEPT => Key::Unidentified(native_code), + winuser::VK_NAVIGATION_CANCEL => Key::Unidentified(native_code), + winuser::VK_NUMLOCK => Key::NumLock, + winuser::VK_SCROLL => Key::ScrollLock, + winuser::VK_OEM_NEC_EQUAL => Key::Unidentified(native_code), + //winuser::VK_OEM_FJ_JISHO => Key::Unidentified(native_code), // Conflicts with `VK_OEM_NEC_EQUAL` + winuser::VK_OEM_FJ_MASSHOU => Key::Unidentified(native_code), + winuser::VK_OEM_FJ_TOUROKU => Key::Unidentified(native_code), + winuser::VK_OEM_FJ_LOYA => Key::Unidentified(native_code), + winuser::VK_OEM_FJ_ROYA => Key::Unidentified(native_code), + winuser::VK_LSHIFT => Key::Shift, + winuser::VK_RSHIFT => Key::Shift, + winuser::VK_LCONTROL => Key::Control, + winuser::VK_RCONTROL => Key::Control, + winuser::VK_LMENU => Key::Alt, + winuser::VK_RMENU => { + if has_alt_graph { + Key::AltGraph + } else { + Key::Alt + } + } + winuser::VK_BROWSER_BACK => Key::BrowserBack, + winuser::VK_BROWSER_FORWARD => Key::BrowserForward, + winuser::VK_BROWSER_REFRESH => Key::BrowserRefresh, + winuser::VK_BROWSER_STOP => Key::BrowserStop, + winuser::VK_BROWSER_SEARCH => Key::BrowserSearch, + winuser::VK_BROWSER_FAVORITES => Key::BrowserFavorites, + winuser::VK_BROWSER_HOME => Key::BrowserHome, + winuser::VK_VOLUME_MUTE => Key::AudioVolumeMute, + winuser::VK_VOLUME_DOWN => Key::AudioVolumeDown, + winuser::VK_VOLUME_UP => Key::AudioVolumeUp, + winuser::VK_MEDIA_NEXT_TRACK => Key::MediaTrackNext, + winuser::VK_MEDIA_PREV_TRACK => Key::MediaTrackPrevious, + winuser::VK_MEDIA_STOP => Key::MediaStop, + winuser::VK_MEDIA_PLAY_PAUSE => Key::MediaPlayPause, + winuser::VK_LAUNCH_MAIL => Key::LaunchMail, + winuser::VK_LAUNCH_MEDIA_SELECT => Key::LaunchMediaPlayer, + winuser::VK_LAUNCH_APP1 => Key::LaunchApplication1, + winuser::VK_LAUNCH_APP2 => Key::LaunchApplication2, + + // This function only converts "non-printable" + winuser::VK_OEM_1 => Key::Unidentified(native_code), + winuser::VK_OEM_PLUS => Key::Unidentified(native_code), + winuser::VK_OEM_COMMA => Key::Unidentified(native_code), + winuser::VK_OEM_MINUS => Key::Unidentified(native_code), + winuser::VK_OEM_PERIOD => Key::Unidentified(native_code), + winuser::VK_OEM_2 => Key::Unidentified(native_code), + winuser::VK_OEM_3 => Key::Unidentified(native_code), + + winuser::VK_GAMEPAD_A => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_B => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_X => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_Y => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_RIGHT_SHOULDER => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_LEFT_SHOULDER => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_LEFT_TRIGGER => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_RIGHT_TRIGGER => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_DPAD_UP => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_DPAD_DOWN => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_DPAD_LEFT => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_DPAD_RIGHT => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_MENU => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_VIEW => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_LEFT_THUMBSTICK_BUTTON => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_RIGHT_THUMBSTICK_BUTTON => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_LEFT_THUMBSTICK_UP => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_LEFT_THUMBSTICK_DOWN => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_LEFT_THUMBSTICK_RIGHT => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_LEFT_THUMBSTICK_LEFT => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_RIGHT_THUMBSTICK_UP => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_RIGHT_THUMBSTICK_DOWN => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_RIGHT_THUMBSTICK_RIGHT => Key::Unidentified(native_code), + winuser::VK_GAMEPAD_RIGHT_THUMBSTICK_LEFT => Key::Unidentified(native_code), + + // This function only converts "non-printable" + winuser::VK_OEM_4 => Key::Unidentified(native_code), + winuser::VK_OEM_5 => Key::Unidentified(native_code), + winuser::VK_OEM_6 => Key::Unidentified(native_code), + winuser::VK_OEM_7 => Key::Unidentified(native_code), + winuser::VK_OEM_8 => Key::Unidentified(native_code), + winuser::VK_OEM_AX => Key::Unidentified(native_code), + winuser::VK_OEM_102 => Key::Unidentified(native_code), + + winuser::VK_ICO_HELP => Key::Unidentified(native_code), + winuser::VK_ICO_00 => Key::Unidentified(native_code), + + winuser::VK_PROCESSKEY => Key::Process, + + winuser::VK_ICO_CLEAR => Key::Unidentified(native_code), + winuser::VK_PACKET => Key::Unidentified(native_code), + winuser::VK_OEM_RESET => Key::Unidentified(native_code), + winuser::VK_OEM_JUMP => Key::Unidentified(native_code), + winuser::VK_OEM_PA1 => Key::Unidentified(native_code), + winuser::VK_OEM_PA2 => Key::Unidentified(native_code), + winuser::VK_OEM_PA3 => Key::Unidentified(native_code), + winuser::VK_OEM_WSCTRL => Key::Unidentified(native_code), + winuser::VK_OEM_CUSEL => Key::Unidentified(native_code), + + winuser::VK_OEM_ATTN => Key::Attn, + winuser::VK_OEM_FINISH => { + if is_japanese { + Key::Katakana + } else { + // This matches IE and Firefox behaviour according to + // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values + // At the time of writing, there is no `Key::Finish` variant as + // Finish is not mentionned at https://w3c.github.io/uievents-key/ + // Also see: https://github.com/pyfisch/keyboard-types/issues/9 + Key::Unidentified(native_code) + } + } + winuser::VK_OEM_COPY => Key::Copy, + winuser::VK_OEM_AUTO => Key::Hankaku, + winuser::VK_OEM_ENLW => Key::Zenkaku, + winuser::VK_OEM_BACKTAB => Key::Romaji, + winuser::VK_ATTN => Key::KanaMode, + winuser::VK_CRSEL => Key::CrSel, + winuser::VK_EXSEL => Key::ExSel, + winuser::VK_EREOF => Key::EraseEof, + winuser::VK_PLAY => Key::Play, + winuser::VK_ZOOM => Key::ZoomToggle, + winuser::VK_NONAME => Key::Unidentified(native_code), + winuser::VK_PA1 => Key::Unidentified(native_code), + winuser::VK_OEM_CLEAR => Key::Clear, + _ => Key::Unidentified(native_code), + } +} diff --git a/src/platform_impl/windows/minimal_ime.rs b/src/platform_impl/windows/minimal_ime.rs new file mode 100644 index 0000000000..cbf754eecc --- /dev/null +++ b/src/platform_impl/windows/minimal_ime.rs @@ -0,0 +1,93 @@ +use std::mem::MaybeUninit; + +use winapi::{ + shared::{ + minwindef::{LPARAM, WPARAM}, + windef::HWND, + }, + um::winuser, +}; + +use crate::platform_impl::platform::event_loop::ProcResult; + +pub fn is_msg_ime_related(msg_kind: u32) -> bool { + match msg_kind { + winuser::WM_IME_COMPOSITION + | winuser::WM_IME_COMPOSITIONFULL + | winuser::WM_IME_STARTCOMPOSITION + | winuser::WM_IME_ENDCOMPOSITION + | winuser::WM_IME_CHAR + | winuser::WM_CHAR + | winuser::WM_SYSCHAR => true, + _ => false, + } +} + +pub struct MinimalIme { + // True if we're currently receiving messages belonging to a finished IME session. + getting_ime_text: bool, + + utf16parts: Vec, +} +impl Default for MinimalIme { + fn default() -> Self { + MinimalIme { + getting_ime_text: false, + utf16parts: Vec::with_capacity(16), + } + } +} +impl MinimalIme { + pub(crate) fn process_message( + &mut self, + hwnd: HWND, + msg_kind: u32, + wparam: WPARAM, + _lparam: LPARAM, + result: &mut ProcResult, + ) -> Option { + match msg_kind { + winuser::WM_IME_ENDCOMPOSITION => { + self.getting_ime_text = true; + } + winuser::WM_CHAR | winuser::WM_SYSCHAR => { + if self.getting_ime_text { + *result = ProcResult::Value(0); + self.utf16parts.push(wparam as u16); + + let more_char_coming; + unsafe { + let mut next_msg = MaybeUninit::uninit(); + let has_message = winuser::PeekMessageW( + next_msg.as_mut_ptr(), + hwnd, + winuser::WM_KEYFIRST, + winuser::WM_KEYLAST, + winuser::PM_NOREMOVE, + ); + let has_message = has_message != 0; + if !has_message { + more_char_coming = false; + } else { + let next_msg = next_msg.assume_init().message; + if next_msg == winuser::WM_CHAR || next_msg == winuser::WM_SYSCHAR { + more_char_coming = true; + } else { + more_char_coming = false; + } + } + } + if !more_char_coming { + let result = String::from_utf16(&self.utf16parts).ok(); + self.utf16parts.clear(); + self.getting_ime_text = false; + return result; + } + } + } + _ => (), + } + + None + } +} diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 9215a92306..6feef4fafa 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -13,6 +13,7 @@ pub use self::icon::WinIcon as PlatformIcon; use crate::event::DeviceId as RootDeviceId; use crate::icon::Icon; +use crate::keyboard::Key; use crate::window::Theme; #[derive(Clone)] @@ -82,6 +83,12 @@ fn wrap_device_id(id: u32) -> RootDeviceId { pub type OsError = std::io::Error; +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct KeyEventExtra { + pub text_with_all_modifers: Option<&'static str>, + pub key_without_modifiers: Key<'static>, +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct WindowId(HWND); unsafe impl Send for WindowId {} @@ -100,9 +107,11 @@ mod util; mod dark_mode; mod dpi; mod drop_handler; -mod event; mod event_loop; mod icon; +mod keyboard; +mod keyboard_layout; +mod minimal_ime; mod monitor; mod raw_input; mod window; diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index f0ea7fbd04..893af39de2 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -1,5 +1,6 @@ #![cfg(target_os = "windows")] +use mem::MaybeUninit; use parking_lot::Mutex; use raw_window_handle::{RawWindowHandle, Win32Handle}; use std::{ @@ -652,6 +653,26 @@ impl Window { unsafe { force_window_active(window.0) }; } } + + #[inline] + pub fn reset_dead_keys(&self) { + // `ToUnicode` consumes the dead-key by default, so we are constructing a fake (but valid) + // key input which we can call `ToUnicode` with. + unsafe { + let vk = winuser::VK_SPACE as u32; + let scancode = winuser::MapVirtualKeyW(vk, winuser::MAPVK_VK_TO_VSC); + let kbd_state = [0; 256]; + let mut char_buff = [MaybeUninit::uninit(); 8]; + winuser::ToUnicode( + vk, + scancode, + kbd_state.as_ptr(), + char_buff[0].as_mut_ptr(), + char_buff.len() as i32, + 0, + ); + } + } } impl Drop for Window { diff --git a/src/platform_impl/windows/window_state.rs b/src/platform_impl/windows/window_state.rs index 9e41bd7925..bca61f05e0 100644 --- a/src/platform_impl/windows/window_state.rs +++ b/src/platform_impl/windows/window_state.rs @@ -1,8 +1,10 @@ use crate::{ dpi::{PhysicalPosition, Size}, - event::ModifiersState, icon::Icon, - platform_impl::platform::{event_loop, util}, + keyboard::ModifiersState, + platform_impl::platform::{ + event_loop, keyboard::KeyEventBuilder, minimal_ime::MinimalIme, util, + }, window::{CursorIcon, Fullscreen, Theme, WindowAttributes}, }; use parking_lot::MutexGuard; @@ -34,6 +36,10 @@ pub struct WindowState { pub current_theme: Theme, pub preferred_theme: Option, pub high_surrogate: Option, + + pub key_event_builder: KeyEventBuilder, + pub ime_handler: MinimalIme, + pub window_flags: WindowFlags, } @@ -122,6 +128,8 @@ impl WindowState { current_theme, preferred_theme, high_surrogate: None, + key_event_builder: KeyEventBuilder::default(), + ime_handler: MinimalIme::default(), window_flags: WindowFlags::empty(), } } diff --git a/src/window.rs b/src/window.rs index 9410421d57..2f53bb778c 100644 --- a/src/window.rs +++ b/src/window.rs @@ -447,6 +447,22 @@ impl Window { pub fn request_redraw(&self) { self.window.request_redraw() } + + /// Reset the dead key state of the keyboard. + /// + /// This is useful when a dead key is bound to trigger an action. Then + /// this function can be called to reset the dead key state so that + /// follow-up text input won't be affected by the dead key. + /// + /// ## Platform-specific + /// - **Web:** Does nothing + // --------------------------- + // Developers' Note: If this cannot be implemented on every desktop platform + // at least, then this function should be provided through a platform specific + // extension trait + pub fn reset_dead_keys(&self) { + self.window.reset_dead_keys(); + } } /// Position and size functions. diff --git a/tests/serde_objects.rs b/tests/serde_objects.rs index ad729dcd1b..b0333fa410 100644 --- a/tests/serde_objects.rs +++ b/tests/serde_objects.rs @@ -3,10 +3,8 @@ use serde::{Deserialize, Serialize}; use winit::{ dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}, - event::{ - ElementState, KeyboardInput, ModifiersState, MouseButton, MouseScrollDelta, TouchPhase, - VirtualKeyCode, - }, + event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase}, + keyboard::{Key, KeyCode, KeyLocation, ModifiersState}, window::CursorIcon, }; @@ -20,12 +18,13 @@ fn window_serde() { #[test] fn events_serde() { - needs_serde::(); needs_serde::(); needs_serde::(); needs_serde::(); needs_serde::(); - needs_serde::(); + needs_serde::>(); + needs_serde::(); + needs_serde::(); needs_serde::(); } From 4dfd6128035ab051bcfbd6205c8d30674720b221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Art=C3=BAr=20Kov=C3=A1cs?= Date: Sun, 9 May 2021 19:29:19 +0200 Subject: [PATCH 02/53] Fix the `drag_window` example --- examples/drag_window.rs | 11 +++++------ src/platform_impl/windows/event_loop.rs | 7 ++----- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/examples/drag_window.rs b/examples/drag_window.rs index a408c7c722..58920a0928 100644 --- a/examples/drag_window.rs +++ b/examples/drag_window.rs @@ -1,9 +1,8 @@ use simple_logger::SimpleLogger; use winit::{ - event::{ - ElementState, Event, KeyboardInput, MouseButton, StartCause, VirtualKeyCode, WindowEvent, - }, + event::{ElementState, Event, KeyEvent, MouseButton, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, + keyboard::Key, window::{Window, WindowBuilder, WindowId}, }; @@ -43,10 +42,10 @@ fn main() { name_windows(entered_id, switched, &window_1, &window_2) } WindowEvent::KeyboardInput { - input: - KeyboardInput { + event: + KeyEvent { state: ElementState::Released, - virtual_keycode: Some(VirtualKeyCode::X), + logical_key: Key::Character("x"), .. }, .. diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 2684017ad5..c15aaf5443 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -1103,7 +1103,7 @@ unsafe fn public_window_callback_inner( } // This is necessary for us to still get sent WM_SIZE. - result = ProcResult::DefWindowProc; + result = ProcResult::DefWindowProc; } winuser::WM_SIZE => { @@ -2149,10 +2149,7 @@ unsafe extern "system" fn thread_event_target_callback( result } -unsafe fn handle_raw_input( - userdata: &ThreadMsgTargetData, - data: RAWINPUT, -) { +unsafe fn handle_raw_input(userdata: &ThreadMsgTargetData, data: RAWINPUT) { use crate::event::{ DeviceEvent::{Button, Key, Motion, MouseMotion, MouseWheel}, ElementState::{Pressed, Released}, From d791053cd89304f34b8dc99d66f25fa86933493b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Fri, 19 Mar 2021 20:41:14 +0100 Subject: [PATCH 03/53] Get stuff to compile --- src/platform/unix.rs | 15 + src/platform_impl/linux/mod.rs | 11 + .../linux/wayland/seat/keyboard/handlers.rs | 35 +- .../linux/wayland/seat/keyboard/keymap.rs | 411 ++-- .../linux/wayland/seat/keyboard/mod.rs | 6 +- src/platform_impl/linux/wayland/seat/mod.rs | 2 +- .../linux/wayland/seat/pointer/data.rs | 3 +- .../linux/wayland/seat/pointer/mod.rs | 2 +- .../linux/wayland/seat/text_input/handlers.rs | 2 +- .../linux/x11/event_processor.rs | 57 +- src/platform_impl/linux/x11/events.rs | 2010 ++++++++--------- src/platform_impl/linux/x11/util/input.rs | 6 +- src/platform_impl/linux/x11/util/modifiers.rs | 25 +- 13 files changed, 1329 insertions(+), 1256 deletions(-) diff --git a/src/platform/unix.rs b/src/platform/unix.rs index ba600b134b..f1cb903906 100644 --- a/src/platform/unix.rs +++ b/src/platform/unix.rs @@ -11,8 +11,11 @@ use std::os::raw; use std::{ptr, sync::Arc}; use crate::{ + event::KeyEvent, event_loop::{EventLoop, EventLoopWindowTarget}, + keyboard::Key, monitor::MonitorHandle, + platform::modifier_supplement::KeyEventExtModifierSupplement, window::{Window, WindowBuilder}, }; @@ -462,3 +465,15 @@ impl MonitorHandleExtUnix for MonitorHandle { self.inner.native_identifier() } } + +impl KeyEventExtModifierSupplement for KeyEvent { + #[inline] + fn text_with_all_modifiers(&self) -> Option<&str> { + self.platform_specific.text_with_all_modifers + } + + #[inline] + fn key_without_modifiers(&self) -> Key<'static> { + self.platform_specific.key_without_modifiers + } +} diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 953fca1dd5..3dfc73cd6c 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -29,6 +29,7 @@ use crate::{ event::Event, event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW}, icon::Icon, + keyboard::Key, monitor::{MonitorHandle as RootMonitorHandle, VideoMode as RootVideoMode}, window::{CursorIcon, Fullscreen, UserAttentionType, WindowAttributes}, }; @@ -40,6 +41,12 @@ pub mod wayland; #[cfg(feature = "x11")] pub mod x11; +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct KeyEventExtra { + pub text_with_all_modifers: Option<&'static str>, + pub key_without_modifiers: Key<'static>, +} + /// Environment variable specifying which backend should be used on unix platform. /// /// Legal values are x11 and wayland. If this variable is set only the named backend @@ -428,6 +435,10 @@ impl Window { x11_or_wayland!(match self; Window(w) => w.set_ime_position(position)) } + pub fn reset_dead_keys(&self) { + todo!() + } + #[inline] pub fn focus_window(&self) { match self { diff --git a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs index 7c320973b8..d81e440cc5 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs @@ -4,7 +4,8 @@ use sctk::reexports::client::protocol::wl_keyboard::KeyState; use sctk::seat::keyboard::Event as KeyboardEvent; -use crate::event::{ElementState, KeyboardInput, ModifiersState, WindowEvent}; +use crate::event::{ElementState, KeyEvent, WindowEvent}; +use crate::keyboard::ModifiersState; use crate::platform_impl::wayland::event_loop::WinitState; use crate::platform_impl::wayland::{self, DeviceId}; @@ -68,19 +69,21 @@ pub(super) fn handle_keyboard( _ => unreachable!(), }; - let virtual_keycode = keymap::keysym_to_vkey(keysym); + // let virtual_keycode = keymap::keysym_to_vkey(keysym); event_sink.push_window_event( - #[allow(deprecated)] WindowEvent::KeyboardInput { device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland( DeviceId, )), - input: KeyboardInput { + event: KeyEvent { + physical_key: todo!(), + logical_key: todo!(), + text: todo!(), + location: todo!(), state, - scancode: rawkey, - virtual_keycode, - modifiers: *inner.modifiers_state.borrow(), + repeat: false, + platform_specific: todo!(), }, is_synthetic: false, }, @@ -94,7 +97,7 @@ pub(super) fn handle_keyboard( if let Some(txt) = utf8 { for ch in txt.chars() { - event_sink.push_window_event(WindowEvent::ReceivedCharacter(ch), window_id); + // event_sink.push_window_event(WindowEvent::ReceivedCharacter(ch), window_id); } } } @@ -109,19 +112,21 @@ pub(super) fn handle_keyboard( None => return, }; - let virtual_keycode = keymap::keysym_to_vkey(keysym); + // let virtual_keycode = keymap::keysym_to_vkey(keysym); event_sink.push_window_event( - #[allow(deprecated)] WindowEvent::KeyboardInput { device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland( DeviceId, )), - input: KeyboardInput { + event: KeyEvent { + physical_key: todo!(), + logical_key: todo!(), + text: todo!(), + location: todo!(), state: ElementState::Pressed, - scancode: rawkey, - virtual_keycode, - modifiers: *inner.modifiers_state.borrow(), + repeat: false, + platform_specific: todo!(), }, is_synthetic: false, }, @@ -130,7 +135,7 @@ pub(super) fn handle_keyboard( if let Some(txt) = utf8 { for ch in txt.chars() { - event_sink.push_window_event(WindowEvent::ReceivedCharacter(ch), window_id); + // event_sink.push_window_event(WindowEvent::ReceivedCharacter(ch), window_id); } } } diff --git a/src/platform_impl/linux/wayland/seat/keyboard/keymap.rs b/src/platform_impl/linux/wayland/seat/keyboard/keymap.rs index 991afff2c9..b674dd2945 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/keymap.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/keymap.rs @@ -1,192 +1,229 @@ -//! Convert Wayland keys to winit keys. +// //! Convert Wayland keys to winit keys. -use crate::event::VirtualKeyCode; +// use crate::keyboard::Key; -pub fn keysym_to_vkey(keysym: u32) -> Option { - use sctk::seat::keyboard::keysyms; - match keysym { - // Numbers. - keysyms::XKB_KEY_1 => Some(VirtualKeyCode::Key1), - keysyms::XKB_KEY_2 => Some(VirtualKeyCode::Key2), - keysyms::XKB_KEY_3 => Some(VirtualKeyCode::Key3), - keysyms::XKB_KEY_4 => Some(VirtualKeyCode::Key4), - keysyms::XKB_KEY_5 => Some(VirtualKeyCode::Key5), - keysyms::XKB_KEY_6 => Some(VirtualKeyCode::Key6), - keysyms::XKB_KEY_7 => Some(VirtualKeyCode::Key7), - keysyms::XKB_KEY_8 => Some(VirtualKeyCode::Key8), - keysyms::XKB_KEY_9 => Some(VirtualKeyCode::Key9), - keysyms::XKB_KEY_0 => Some(VirtualKeyCode::Key0), - // Letters. - keysyms::XKB_KEY_A | keysyms::XKB_KEY_a => Some(VirtualKeyCode::A), - keysyms::XKB_KEY_B | keysyms::XKB_KEY_b => Some(VirtualKeyCode::B), - keysyms::XKB_KEY_C | keysyms::XKB_KEY_c => Some(VirtualKeyCode::C), - keysyms::XKB_KEY_D | keysyms::XKB_KEY_d => Some(VirtualKeyCode::D), - keysyms::XKB_KEY_E | keysyms::XKB_KEY_e => Some(VirtualKeyCode::E), - keysyms::XKB_KEY_F | keysyms::XKB_KEY_f => Some(VirtualKeyCode::F), - keysyms::XKB_KEY_G | keysyms::XKB_KEY_g => Some(VirtualKeyCode::G), - keysyms::XKB_KEY_H | keysyms::XKB_KEY_h => Some(VirtualKeyCode::H), - keysyms::XKB_KEY_I | keysyms::XKB_KEY_i => Some(VirtualKeyCode::I), - keysyms::XKB_KEY_J | keysyms::XKB_KEY_j => Some(VirtualKeyCode::J), - keysyms::XKB_KEY_K | keysyms::XKB_KEY_k => Some(VirtualKeyCode::K), - keysyms::XKB_KEY_L | keysyms::XKB_KEY_l => Some(VirtualKeyCode::L), - keysyms::XKB_KEY_M | keysyms::XKB_KEY_m => Some(VirtualKeyCode::M), - keysyms::XKB_KEY_N | keysyms::XKB_KEY_n => Some(VirtualKeyCode::N), - keysyms::XKB_KEY_O | keysyms::XKB_KEY_o => Some(VirtualKeyCode::O), - keysyms::XKB_KEY_P | keysyms::XKB_KEY_p => Some(VirtualKeyCode::P), - keysyms::XKB_KEY_Q | keysyms::XKB_KEY_q => Some(VirtualKeyCode::Q), - keysyms::XKB_KEY_R | keysyms::XKB_KEY_r => Some(VirtualKeyCode::R), - keysyms::XKB_KEY_S | keysyms::XKB_KEY_s => Some(VirtualKeyCode::S), - keysyms::XKB_KEY_T | keysyms::XKB_KEY_t => Some(VirtualKeyCode::T), - keysyms::XKB_KEY_U | keysyms::XKB_KEY_u => Some(VirtualKeyCode::U), - keysyms::XKB_KEY_V | keysyms::XKB_KEY_v => Some(VirtualKeyCode::V), - keysyms::XKB_KEY_W | keysyms::XKB_KEY_w => Some(VirtualKeyCode::W), - keysyms::XKB_KEY_X | keysyms::XKB_KEY_x => Some(VirtualKeyCode::X), - keysyms::XKB_KEY_Y | keysyms::XKB_KEY_y => Some(VirtualKeyCode::Y), - keysyms::XKB_KEY_Z | keysyms::XKB_KEY_z => Some(VirtualKeyCode::Z), - // Escape. - keysyms::XKB_KEY_Escape => Some(VirtualKeyCode::Escape), - // Function keys. - keysyms::XKB_KEY_F1 => Some(VirtualKeyCode::F1), - keysyms::XKB_KEY_F2 => Some(VirtualKeyCode::F2), - keysyms::XKB_KEY_F3 => Some(VirtualKeyCode::F3), - keysyms::XKB_KEY_F4 => Some(VirtualKeyCode::F4), - keysyms::XKB_KEY_F5 => Some(VirtualKeyCode::F5), - keysyms::XKB_KEY_F6 => Some(VirtualKeyCode::F6), - keysyms::XKB_KEY_F7 => Some(VirtualKeyCode::F7), - keysyms::XKB_KEY_F8 => Some(VirtualKeyCode::F8), - keysyms::XKB_KEY_F9 => Some(VirtualKeyCode::F9), - keysyms::XKB_KEY_F10 => Some(VirtualKeyCode::F10), - keysyms::XKB_KEY_F11 => Some(VirtualKeyCode::F11), - keysyms::XKB_KEY_F12 => Some(VirtualKeyCode::F12), - keysyms::XKB_KEY_F13 => Some(VirtualKeyCode::F13), - keysyms::XKB_KEY_F14 => Some(VirtualKeyCode::F14), - keysyms::XKB_KEY_F15 => Some(VirtualKeyCode::F15), - keysyms::XKB_KEY_F16 => Some(VirtualKeyCode::F16), - keysyms::XKB_KEY_F17 => Some(VirtualKeyCode::F17), - keysyms::XKB_KEY_F18 => Some(VirtualKeyCode::F18), - keysyms::XKB_KEY_F19 => Some(VirtualKeyCode::F19), - keysyms::XKB_KEY_F20 => Some(VirtualKeyCode::F20), - keysyms::XKB_KEY_F21 => Some(VirtualKeyCode::F21), - keysyms::XKB_KEY_F22 => Some(VirtualKeyCode::F22), - keysyms::XKB_KEY_F23 => Some(VirtualKeyCode::F23), - keysyms::XKB_KEY_F24 => Some(VirtualKeyCode::F24), - // Flow control. - keysyms::XKB_KEY_Print => Some(VirtualKeyCode::Snapshot), - keysyms::XKB_KEY_Scroll_Lock => Some(VirtualKeyCode::Scroll), - keysyms::XKB_KEY_Pause => Some(VirtualKeyCode::Pause), - keysyms::XKB_KEY_Insert => Some(VirtualKeyCode::Insert), - keysyms::XKB_KEY_Home => Some(VirtualKeyCode::Home), - keysyms::XKB_KEY_Delete => Some(VirtualKeyCode::Delete), - keysyms::XKB_KEY_End => Some(VirtualKeyCode::End), - keysyms::XKB_KEY_Page_Down => Some(VirtualKeyCode::PageDown), - keysyms::XKB_KEY_Page_Up => Some(VirtualKeyCode::PageUp), - // Arrows. - keysyms::XKB_KEY_Left => Some(VirtualKeyCode::Left), - keysyms::XKB_KEY_Up => Some(VirtualKeyCode::Up), - keysyms::XKB_KEY_Right => Some(VirtualKeyCode::Right), - keysyms::XKB_KEY_Down => Some(VirtualKeyCode::Down), +// pub fn keysym_to_vkey(keysym: u32) -> Option> { +// use sctk::seat::keyboard::keysyms; +// match keysym { +// // Numbers. +// // keysyms::XKB_KEY_1 => Some(Key::Character("1")), +// // keysyms::XKB_KEY_2 => Some(Key::Character("2")), +// // keysyms::XKB_KEY_3 => Some(Key::Character("3")), +// // keysyms::XKB_KEY_4 => Some(Key::Character("4")), +// // keysyms::XKB_KEY_5 => Some(Key::Character("5")), +// // keysyms::XKB_KEY_6 => Some(Key::Character("6")), +// // keysyms::XKB_KEY_7 => Some(Key::Character("7")), +// // keysyms::XKB_KEY_8 => Some(Key::Character("8")), +// // keysyms::XKB_KEY_9 => Some(Key::Character("9")), +// // keysyms::XKB_KEY_0 => Some(Key::Character("0")), +// // Letters. +// // keysyms::XKB_KEY_A => Some(Key::Character("A")), +// // keysyms::XKB_KEY_a => Some(Key::Character("a")), +// // keysyms::XKB_KEY_B => Some(Key::Character("B")), +// // keysyms::XKB_KEY_b => Some(Key::Character("b")), +// // keysyms::XKB_KEY_C => Some(Key::Character("C")), +// // keysyms::XKB_KEY_c => Some(Key::Character("c")), +// // keysyms::XKB_KEY_D => Some(Key::Character("D")), +// // keysyms::XKB_KEY_d => Some(Key::Character("d")), +// // keysyms::XKB_KEY_E => Some(Key::Character("E")), +// // keysyms::XKB_KEY_e => Some(Key::Character("e")), +// // keysyms::XKB_KEY_F => Some(Key::Character("F")), +// // keysyms::XKB_KEY_f => Some(Key::Character("f")), +// // keysyms::XKB_KEY_G => Some(Key::Character("G")), +// // keysyms::XKB_KEY_g => Some(Key::Character("g")), +// // keysyms::XKB_KEY_H => Some(Key::Character("H")), +// // keysyms::XKB_KEY_h => Some(Key::Character("h")), +// // keysyms::XKB_KEY_I => Some(Key::Character("I")), +// // keysyms::XKB_KEY_i => Some(Key::Character("i")), +// // keysyms::XKB_KEY_J => Some(Key::Character("J")), +// // keysyms::XKB_KEY_j => Some(Key::Character("j")), +// // keysyms::XKB_KEY_K => Some(Key::Character("K")), +// // keysyms::XKB_KEY_k => Some(Key::Character("k")), +// // keysyms::XKB_KEY_L => Some(Key::Character("L")), +// // keysyms::XKB_KEY_l => Some(Key::Character("l")), +// // keysyms::XKB_KEY_M => Some(Key::Character("M")), +// // keysyms::XKB_KEY_m => Some(Key::Character("m")), +// // keysyms::XKB_KEY_N => Some(Key::Character("N")), +// // keysyms::XKB_KEY_n => Some(Key::Character("n")), +// // keysyms::XKB_KEY_O => Some(Key::Character("O")), +// // keysyms::XKB_KEY_o => Some(Key::Character("o")), +// // keysyms::XKB_KEY_P => Some(Key::Character("P")), +// // keysyms::XKB_KEY_p => Some(Key::Character("p")), +// // keysyms::XKB_KEY_Q => Some(Key::Character("Q")), +// // keysyms::XKB_KEY_q => Some(Key::Character("q")), +// // keysyms::XKB_KEY_R => Some(Key::Character("R")), +// // keysyms::XKB_KEY_r => Some(Key::Character("r")), +// // keysyms::XKB_KEY_S => Some(Key::Character("S")), +// // keysyms::XKB_KEY_s => Some(Key::Character("s")), +// // keysyms::XKB_KEY_T => Some(Key::Character("T")), +// // keysyms::XKB_KEY_t => Some(Key::Character("t")), +// // keysyms::XKB_KEY_U => Some(Key::Character("U")), +// // keysyms::XKB_KEY_u => Some(Key::Character("u")), +// // keysyms::XKB_KEY_V => Some(Key::Character("V")), +// // keysyms::XKB_KEY_v => Some(Key::Character("v")), +// // keysyms::XKB_KEY_W => Some(Key::Character("W")), +// // keysyms::XKB_KEY_w => Some(Key::Character("w")), +// // keysyms::XKB_KEY_X => Some(Key::Character("X")), +// // keysyms::XKB_KEY_x => Some(Key::Character("x")), +// // keysyms::XKB_KEY_Y => Some(Key::Character("Y")), +// // keysyms::XKB_KEY_y => Some(Key::Character("y")), +// // keysyms::XKB_KEY_Z => Some(Key::Character("Z")), +// // keysyms::XKB_KEY_z => Some(Key::Character("z")), +// // Escape. +// keysyms::XKB_KEY_Escape => Some(Key::Escape), +// // Function keys. +// keysyms::XKB_KEY_F1 => Some(Key::F1), +// keysyms::XKB_KEY_F2 => Some(Key::F2), +// keysyms::XKB_KEY_F3 => Some(Key::F3), +// keysyms::XKB_KEY_F4 => Some(Key::F4), +// keysyms::XKB_KEY_F5 => Some(Key::F5), +// keysyms::XKB_KEY_F6 => Some(Key::F6), +// keysyms::XKB_KEY_F7 => Some(Key::F7), +// keysyms::XKB_KEY_F8 => Some(Key::F8), +// keysyms::XKB_KEY_F9 => Some(Key::F9), +// keysyms::XKB_KEY_F10 => Some(Key::F10), +// keysyms::XKB_KEY_F11 => Some(Key::F11), +// keysyms::XKB_KEY_F12 => Some(Key::F12), +// keysyms::XKB_KEY_F13 => Some(Key::F13), +// keysyms::XKB_KEY_F14 => Some(Key::F14), +// keysyms::XKB_KEY_F15 => Some(Key::F15), +// keysyms::XKB_KEY_F16 => Some(Key::F16), +// keysyms::XKB_KEY_F17 => Some(Key::F17), +// keysyms::XKB_KEY_F18 => Some(Key::F18), +// keysyms::XKB_KEY_F19 => Some(Key::F19), +// keysyms::XKB_KEY_F20 => Some(Key::F20), +// keysyms::XKB_KEY_F21 => Some(Key::F21), +// keysyms::XKB_KEY_F22 => Some(Key::F22), +// keysyms::XKB_KEY_F23 => Some(Key::F23), +// keysyms::XKB_KEY_F24 => Some(Key::F24), +// keysyms::XKB_KEY_F25 => Some(Key::F25), +// keysyms::XKB_KEY_F26 => Some(Key::F26), +// keysyms::XKB_KEY_F27 => Some(Key::F27), +// keysyms::XKB_KEY_F28 => Some(Key::F28), +// keysyms::XKB_KEY_F29 => Some(Key::F29), +// keysyms::XKB_KEY_F30 => Some(Key::F30), +// keysyms::XKB_KEY_F31 => Some(Key::F31), +// keysyms::XKB_KEY_F32 => Some(Key::F32), +// keysyms::XKB_KEY_F33 => Some(Key::F33), +// keysyms::XKB_KEY_F34 => Some(Key::F34), +// keysyms::XKB_KEY_F35 => Some(Key::F35), +// // Flow control. +// keysyms::XKB_KEY_Print => Some(Key::PrintScreen), +// keysyms::XKB_KEY_Scroll_Lock => Some(Key::ScrollLock), +// keysyms::XKB_KEY_Pause => Some(Key::Pause), +// keysyms::XKB_KEY_Insert => Some(Key::Insert), +// keysyms::XKB_KEY_Home => Some(Key::Home), +// keysyms::XKB_KEY_Delete => Some(Key::Delete), +// keysyms::XKB_KEY_End => Some(Key::End), +// keysyms::XKB_KEY_Page_Down => Some(Key::PageDown), +// keysyms::XKB_KEY_Page_Up => Some(Key::PageUp), +// // Arrows. +// keysyms::XKB_KEY_Left => Some(Key::Left), +// keysyms::XKB_KEY_Up => Some(Key::Up), +// keysyms::XKB_KEY_Right => Some(Key::Right), +// keysyms::XKB_KEY_Down => Some(Key::Down), - keysyms::XKB_KEY_BackSpace => Some(VirtualKeyCode::Back), - keysyms::XKB_KEY_Return => Some(VirtualKeyCode::Return), - keysyms::XKB_KEY_space => Some(VirtualKeyCode::Space), +// keysyms::XKB_KEY_BackSpace => Some(Key::Back), +// keysyms::XKB_KEY_Return => Some(Key::Return), +// keysyms::XKB_KEY_space => Some(Key::Space), - keysyms::XKB_KEY_Multi_key => Some(VirtualKeyCode::Compose), - keysyms::XKB_KEY_caret => Some(VirtualKeyCode::Caret), +// keysyms::XKB_KEY_Multi_key => Some(Key::Compose), +// keysyms::XKB_KEY_caret => Some(Key::Caret), - // Keypad. - keysyms::XKB_KEY_Num_Lock => Some(VirtualKeyCode::Numlock), - keysyms::XKB_KEY_KP_0 => Some(VirtualKeyCode::Numpad0), - keysyms::XKB_KEY_KP_1 => Some(VirtualKeyCode::Numpad1), - keysyms::XKB_KEY_KP_2 => Some(VirtualKeyCode::Numpad2), - keysyms::XKB_KEY_KP_3 => Some(VirtualKeyCode::Numpad3), - keysyms::XKB_KEY_KP_4 => Some(VirtualKeyCode::Numpad4), - keysyms::XKB_KEY_KP_5 => Some(VirtualKeyCode::Numpad5), - keysyms::XKB_KEY_KP_6 => Some(VirtualKeyCode::Numpad6), - keysyms::XKB_KEY_KP_7 => Some(VirtualKeyCode::Numpad7), - keysyms::XKB_KEY_KP_8 => Some(VirtualKeyCode::Numpad8), - keysyms::XKB_KEY_KP_9 => Some(VirtualKeyCode::Numpad9), - // Misc. - // => Some(VirtualKeyCode::AbntC1), - // => Some(VirtualKeyCode::AbntC2), - keysyms::XKB_KEY_plus => Some(VirtualKeyCode::Plus), - keysyms::XKB_KEY_apostrophe => Some(VirtualKeyCode::Apostrophe), - // => Some(VirtualKeyCode::Apps), - keysyms::XKB_KEY_at => Some(VirtualKeyCode::At), - // => Some(VirtualKeyCode::Ax), - keysyms::XKB_KEY_backslash => Some(VirtualKeyCode::Backslash), - keysyms::XKB_KEY_XF86Calculator => Some(VirtualKeyCode::Calculator), - // => Some(VirtualKeyCode::Capital), - keysyms::XKB_KEY_colon => Some(VirtualKeyCode::Colon), - keysyms::XKB_KEY_comma => Some(VirtualKeyCode::Comma), - // => Some(VirtualKeyCode::Convert), - keysyms::XKB_KEY_equal => Some(VirtualKeyCode::Equals), - keysyms::XKB_KEY_grave => Some(VirtualKeyCode::Grave), - // => Some(VirtualKeyCode::Kana), - keysyms::XKB_KEY_Kanji => Some(VirtualKeyCode::Kanji), - keysyms::XKB_KEY_Alt_L => Some(VirtualKeyCode::LAlt), - keysyms::XKB_KEY_bracketleft => Some(VirtualKeyCode::LBracket), - keysyms::XKB_KEY_Control_L => Some(VirtualKeyCode::LControl), - keysyms::XKB_KEY_Shift_L => Some(VirtualKeyCode::LShift), - keysyms::XKB_KEY_Super_L => Some(VirtualKeyCode::LWin), - keysyms::XKB_KEY_XF86Mail => Some(VirtualKeyCode::Mail), - // => Some(VirtualKeyCode::MediaSelect), - // => Some(VirtualKeyCode::MediaStop), - keysyms::XKB_KEY_minus => Some(VirtualKeyCode::Minus), - keysyms::XKB_KEY_asterisk => Some(VirtualKeyCode::Asterisk), - keysyms::XKB_KEY_XF86AudioMute => Some(VirtualKeyCode::Mute), - // => Some(VirtualKeyCode::MyComputer), - keysyms::XKB_KEY_XF86AudioNext => Some(VirtualKeyCode::NextTrack), - // => Some(VirtualKeyCode::NoConvert), - keysyms::XKB_KEY_KP_Separator => Some(VirtualKeyCode::NumpadComma), - keysyms::XKB_KEY_KP_Enter => Some(VirtualKeyCode::NumpadEnter), - keysyms::XKB_KEY_KP_Equal => Some(VirtualKeyCode::NumpadEquals), - keysyms::XKB_KEY_KP_Add => Some(VirtualKeyCode::NumpadAdd), - keysyms::XKB_KEY_KP_Subtract => Some(VirtualKeyCode::NumpadSubtract), - keysyms::XKB_KEY_KP_Multiply => Some(VirtualKeyCode::NumpadMultiply), - keysyms::XKB_KEY_KP_Divide => Some(VirtualKeyCode::NumpadDivide), - keysyms::XKB_KEY_KP_Decimal => Some(VirtualKeyCode::NumpadDecimal), - keysyms::XKB_KEY_KP_Page_Up => Some(VirtualKeyCode::PageUp), - keysyms::XKB_KEY_KP_Page_Down => Some(VirtualKeyCode::PageDown), - keysyms::XKB_KEY_KP_Home => Some(VirtualKeyCode::Home), - keysyms::XKB_KEY_KP_End => Some(VirtualKeyCode::End), - keysyms::XKB_KEY_KP_Left => Some(VirtualKeyCode::Left), - keysyms::XKB_KEY_KP_Up => Some(VirtualKeyCode::Up), - keysyms::XKB_KEY_KP_Right => Some(VirtualKeyCode::Right), - keysyms::XKB_KEY_KP_Down => Some(VirtualKeyCode::Down), - // => Some(VirtualKeyCode::OEM102), - keysyms::XKB_KEY_period => Some(VirtualKeyCode::Period), - // => Some(VirtualKeyCode::Playpause), - keysyms::XKB_KEY_XF86PowerOff => Some(VirtualKeyCode::Power), - keysyms::XKB_KEY_XF86AudioPrev => Some(VirtualKeyCode::PrevTrack), - keysyms::XKB_KEY_Alt_R => Some(VirtualKeyCode::RAlt), - keysyms::XKB_KEY_bracketright => Some(VirtualKeyCode::RBracket), - keysyms::XKB_KEY_Control_R => Some(VirtualKeyCode::RControl), - keysyms::XKB_KEY_Shift_R => Some(VirtualKeyCode::RShift), - keysyms::XKB_KEY_Super_R => Some(VirtualKeyCode::RWin), - keysyms::XKB_KEY_semicolon => Some(VirtualKeyCode::Semicolon), - keysyms::XKB_KEY_slash => Some(VirtualKeyCode::Slash), - keysyms::XKB_KEY_XF86Sleep => Some(VirtualKeyCode::Sleep), - // => Some(VirtualKeyCode::Stop), - // => Some(VirtualKeyCode::Sysrq), - keysyms::XKB_KEY_Tab => Some(VirtualKeyCode::Tab), - keysyms::XKB_KEY_ISO_Left_Tab => Some(VirtualKeyCode::Tab), - keysyms::XKB_KEY_underscore => Some(VirtualKeyCode::Underline), - // => Some(VirtualKeyCode::Unlabeled), - keysyms::XKB_KEY_XF86AudioLowerVolume => Some(VirtualKeyCode::VolumeDown), - keysyms::XKB_KEY_XF86AudioRaiseVolume => Some(VirtualKeyCode::VolumeUp), - // => Some(VirtualKeyCode::Wake), - // => Some(VirtualKeyCode::Webback), - // => Some(VirtualKeyCode::WebFavorites), - // => Some(VirtualKeyCode::WebForward), - // => Some(VirtualKeyCode::WebHome), - // => Some(VirtualKeyCode::WebRefresh), - // => Some(VirtualKeyCode::WebSearch), - // => Some(VirtualKeyCode::WebStop), - keysyms::XKB_KEY_yen => Some(VirtualKeyCode::Yen), - keysyms::XKB_KEY_XF86Copy => Some(VirtualKeyCode::Copy), - keysyms::XKB_KEY_XF86Paste => Some(VirtualKeyCode::Paste), - keysyms::XKB_KEY_XF86Cut => Some(VirtualKeyCode::Cut), - // Fallback. - _ => None, - } -} +// // Keypad. +// keysyms::XKB_KEY_Num_Lock => Some(Key::Numlock), +// keysyms::XKB_KEY_KP_0 => Some(Key::Numpad0), +// keysyms::XKB_KEY_KP_1 => Some(Key::Numpad1), +// keysyms::XKB_KEY_KP_2 => Some(Key::Numpad2), +// keysyms::XKB_KEY_KP_3 => Some(Key::Numpad3), +// keysyms::XKB_KEY_KP_4 => Some(Key::Numpad4), +// keysyms::XKB_KEY_KP_5 => Some(Key::Numpad5), +// keysyms::XKB_KEY_KP_6 => Some(Key::Numpad6), +// keysyms::XKB_KEY_KP_7 => Some(Key::Numpad7), +// keysyms::XKB_KEY_KP_8 => Some(Key::Numpad8), +// keysyms::XKB_KEY_KP_9 => Some(Key::Numpad9), +// // Misc. +// // => Some(Key::AbntC1), +// // => Some(Key::AbntC2), +// keysyms::XKB_KEY_plus => Some(Key::Plus), +// keysyms::XKB_KEY_apostrophe => Some(Key::Apostrophe), +// // => Some(Key::Apps), +// keysyms::XKB_KEY_at => Some(Key::At), +// // => Some(Key::Ax), +// keysyms::XKB_KEY_backslash => Some(Key::Backslash), +// keysyms::XKB_KEY_XF86Calculator => Some(Key::Calculator), +// // => Some(Key::Capital), +// keysyms::XKB_KEY_colon => Some(Key::Colon), +// keysyms::XKB_KEY_comma => Some(Key::Comma), +// // => Some(Key::Convert), +// keysyms::XKB_KEY_equal => Some(Key::Equals), +// keysyms::XKB_KEY_grave => Some(Key::Grave), +// // => Some(Key::Kana), +// keysyms::XKB_KEY_Kanji => Some(Key::Kanji), +// keysyms::XKB_KEY_Alt_L => Some(Key::LAlt), +// keysyms::XKB_KEY_bracketleft => Some(Key::LBracket), +// keysyms::XKB_KEY_Control_L => Some(Key::LControl), +// keysyms::XKB_KEY_Shift_L => Some(Key::LShift), +// keysyms::XKB_KEY_Super_L => Some(Key::LWin), +// keysyms::XKB_KEY_XF86Mail => Some(Key::Mail), +// // => Some(Key::MediaSelect), +// // => Some(Key::MediaStop), +// keysyms::XKB_KEY_minus => Some(Key::Minus), +// keysyms::XKB_KEY_asterisk => Some(Key::Asterisk), +// keysyms::XKB_KEY_XF86AudioMute => Some(Key::Mute), +// // => Some(Key::MyComputer), +// keysyms::XKB_KEY_XF86AudioNext => Some(Key::NextTrack), +// // => Some(Key::NoConvert), +// keysyms::XKB_KEY_KP_Separator => Some(Key::NumpadComma), +// keysyms::XKB_KEY_KP_Enter => Some(Key::NumpadEnter), +// keysyms::XKB_KEY_KP_Equal => Some(Key::NumpadEquals), +// keysyms::XKB_KEY_KP_Add => Some(Key::NumpadAdd), +// keysyms::XKB_KEY_KP_Subtract => Some(Key::NumpadSubtract), +// keysyms::XKB_KEY_KP_Multiply => Some(Key::NumpadMultiply), +// keysyms::XKB_KEY_KP_Divide => Some(Key::NumpadDivide), +// keysyms::XKB_KEY_KP_Decimal => Some(Key::NumpadDecimal), +// keysyms::XKB_KEY_KP_Page_Up => Some(Key::PageUp), +// keysyms::XKB_KEY_KP_Page_Down => Some(Key::PageDown), +// keysyms::XKB_KEY_KP_Home => Some(Key::Home), +// keysyms::XKB_KEY_KP_End => Some(Key::End), +// keysyms::XKB_KEY_KP_Left => Some(Key::Left), +// keysyms::XKB_KEY_KP_Up => Some(Key::Up), +// keysyms::XKB_KEY_KP_Right => Some(Key::Right), +// keysyms::XKB_KEY_KP_Down => Some(Key::Down), +// // => Some(Key::OEM102), +// keysyms::XKB_KEY_period => Some(Key::Period), +// // => Some(Key::Playpause), +// keysyms::XKB_KEY_XF86PowerOff => Some(Key::Power), +// keysyms::XKB_KEY_XF86AudioPrev => Some(Key::PrevTrack), +// keysyms::XKB_KEY_Alt_R => Some(Key::RAlt), +// keysyms::XKB_KEY_bracketright => Some(Key::RBracket), +// keysyms::XKB_KEY_Control_R => Some(Key::RControl), +// keysyms::XKB_KEY_Shift_R => Some(Key::RShift), +// keysyms::XKB_KEY_Super_R => Some(Key::RWin), +// keysyms::XKB_KEY_semicolon => Some(Key::Semicolon), +// keysyms::XKB_KEY_slash => Some(Key::Slash), +// keysyms::XKB_KEY_XF86Sleep => Some(Key::Sleep), +// // => Some(Key::Stop), +// // => Some(Key::Sysrq), +// keysyms::XKB_KEY_Tab => Some(Key::Tab), +// keysyms::XKB_KEY_ISO_Left_Tab => Some(Key::Tab), +// keysyms::XKB_KEY_underscore => Some(Key::Underline), +// // => Some(Key::Unlabeled), +// keysyms::XKB_KEY_XF86AudioLowerVolume => Some(Key::VolumeDown), +// keysyms::XKB_KEY_XF86AudioRaiseVolume => Some(Key::VolumeUp), +// // => Some(Key::Wake), +// // => Some(Key::Webback), +// // => Some(Key::WebFavorites), +// // => Some(Key::WebForward), +// // => Some(Key::WebHome), +// // => Some(Key::WebRefresh), +// // => Some(Key::WebSearch), +// // => Some(Key::WebStop), +// keysyms::XKB_KEY_yen => Some(Key::Yen), +// keysyms::XKB_KEY_XF86Copy => Some(Key::Copy), +// keysyms::XKB_KEY_XF86Paste => Some(Key::Paste), +// keysyms::XKB_KEY_XF86Cut => Some(Key::Cut), +// // Fallback. +// _ => None, +// } +// } diff --git a/src/platform_impl/linux/wayland/seat/keyboard/mod.rs b/src/platform_impl/linux/wayland/seat/keyboard/mod.rs index c6e0ad456e..fb7973f452 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/mod.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/mod.rs @@ -11,7 +11,7 @@ use sctk::reexports::calloop::{LoopHandle, RegistrationToken}; use sctk::seat::keyboard; -use crate::event::ModifiersState; +use crate::keyboard::ModifiersState; use crate::platform_impl::wayland::event_loop::WinitState; use crate::platform_impl::wayland::WindowId; @@ -97,9 +97,9 @@ impl From for ModifiersState { fn from(mods: keyboard::ModifiersState) -> ModifiersState { let mut wl_mods = ModifiersState::empty(); wl_mods.set(ModifiersState::SHIFT, mods.shift); - wl_mods.set(ModifiersState::CTRL, mods.ctrl); + wl_mods.set(ModifiersState::CONTROL, mods.ctrl); wl_mods.set(ModifiersState::ALT, mods.alt); - wl_mods.set(ModifiersState::LOGO, mods.logo); + wl_mods.set(ModifiersState::SUPER, mods.logo); wl_mods } } diff --git a/src/platform_impl/linux/wayland/seat/mod.rs b/src/platform_impl/linux/wayland/seat/mod.rs index 2d7b7533d0..cf344005f7 100644 --- a/src/platform_impl/linux/wayland/seat/mod.rs +++ b/src/platform_impl/linux/wayland/seat/mod.rs @@ -17,7 +17,7 @@ use sctk::seat::{SeatData, SeatListener}; use super::env::WinitEnv; use super::event_loop::WinitState; -use crate::event::ModifiersState; +use crate::keyboard::ModifiersState; mod keyboard; pub mod pointer; diff --git a/src/platform_impl/linux/wayland/seat/pointer/data.rs b/src/platform_impl/linux/wayland/seat/pointer/data.rs index 1da60d3526..a502a86e4c 100644 --- a/src/platform_impl/linux/wayland/seat/pointer/data.rs +++ b/src/platform_impl/linux/wayland/seat/pointer/data.rs @@ -8,7 +8,8 @@ use sctk::reexports::client::Attached; use sctk::reexports::protocols::unstable::pointer_constraints::v1::client::zwp_pointer_constraints_v1::{ZwpPointerConstraintsV1}; use sctk::reexports::protocols::unstable::pointer_constraints::v1::client::zwp_confined_pointer_v1::ZwpConfinedPointerV1; -use crate::event::{ModifiersState, TouchPhase}; +use crate::event::TouchPhase; +use crate::keyboard::ModifiersState; /// A data being used by pointer handlers. pub(super) struct PointerData { diff --git a/src/platform_impl/linux/wayland/seat/pointer/mod.rs b/src/platform_impl/linux/wayland/seat/pointer/mod.rs index c6726224c0..9f896078bd 100644 --- a/src/platform_impl/linux/wayland/seat/pointer/mod.rs +++ b/src/platform_impl/linux/wayland/seat/pointer/mod.rs @@ -15,7 +15,7 @@ use sctk::reexports::protocols::unstable::pointer_constraints::v1::client::zwp_c use sctk::seat::pointer::{ThemeManager, ThemedPointer}; use sctk::window::{FallbackFrame, Window}; -use crate::event::ModifiersState; +use crate::keyboard::ModifiersState; use crate::platform_impl::wayland::event_loop::WinitState; use crate::window::CursorIcon; diff --git a/src/platform_impl/linux/wayland/seat/text_input/handlers.rs b/src/platform_impl/linux/wayland/seat/text_input/handlers.rs index 4ba13d6715..26d56a3cb6 100644 --- a/src/platform_impl/linux/wayland/seat/text_input/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/text_input/handlers.rs @@ -70,7 +70,7 @@ pub(super) fn handle_text_input( }; for ch in text.chars() { - event_sink.push_window_event(WindowEvent::ReceivedCharacter(ch), window_id); + // event_sink.push_window_event(WindowEvent::ReceivedCharacter(ch), window_id); } } _ => (), diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 17f9436f58..22474abaa1 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -14,10 +14,9 @@ use util::modifiers::{ModifierKeyState, ModifierKeymap}; use crate::{ dpi::{PhysicalPosition, PhysicalSize}, - event::{ - DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, TouchPhase, WindowEvent, - }, + event::{DeviceEvent, ElementState, Event, KeyEvent, RawKeyEvent, TouchPhase, WindowEvent}, event_loop::EventLoopWindowTarget as RootELW, + keyboard::ModifiersState, }; /// The X11 documentation states: "Keycodes lie in the inclusive range [8,255]". @@ -570,7 +569,7 @@ impl EventProcessor { if keycode != 0 { let scancode = keycode - KEYCODE_OFFSET as u32; let keysym = wt.xconn.lookup_keysym(xkev); - let virtual_keycode = events::keysym_to_element(keysym as c_uint); + // let virtual_keycode = events::keysym_to_element(keysym as c_uint); update_modifiers!( ModifiersState::from_x11_mask(xkev.state), @@ -579,16 +578,18 @@ impl EventProcessor { let modifiers = self.device_mod_state.modifiers(); - #[allow(deprecated)] callback(Event::WindowEvent { window_id, event: WindowEvent::KeyboardInput { device_id, - input: KeyboardInput { + event: KeyEvent { + physical_key: todo!(), + logical_key: todo!(), + text: todo!(), + location: todo!(), state, - scancode, - virtual_keycode, - modifiers, + repeat: todo!(), + platform_specific: todo!(), }, is_synthetic: false, }, @@ -603,11 +604,11 @@ impl EventProcessor { }; for chr in written.chars() { - let event = Event::WindowEvent { - window_id, - event: WindowEvent::ReceivedCharacter(chr), - }; - callback(event); + // let event = Event::WindowEvent { + // window_id, + // event: WindowEvent::ReceivedCharacter(chr), + // }; + // callback(event); } } } @@ -1095,17 +1096,15 @@ impl EventProcessor { return; } let keysym = wt.xconn.keycode_to_keysym(keycode as ffi::KeyCode); - let virtual_keycode = events::keysym_to_element(keysym as c_uint); + // let virtual_keycode = events::keysym_to_element(keysym as c_uint); let modifiers = self.device_mod_state.modifiers(); - #[allow(deprecated)] callback(Event::DeviceEvent { device_id, - event: DeviceEvent::Key(KeyboardInput { - scancode: scancode as u32, - virtual_keycode, - state, - modifiers, + event: DeviceEvent::Key(RawKeyEvent { + physical_key: todo!(), + state: todo!(), + repeat: todo!(), }), }); @@ -1247,7 +1246,7 @@ impl EventProcessor { { let scancode = (keycode - KEYCODE_OFFSET) as u32; let keysym = wt.xconn.keycode_to_keysym(keycode); - let virtual_keycode = events::keysym_to_element(keysym as c_uint); + // let virtual_keycode = events::keysym_to_element(keysym as c_uint); if let Some(modifier) = mod_keymap.get_modifier(keycode as ffi::KeyCode) { device_mod_state.key_event( @@ -1257,16 +1256,18 @@ impl EventProcessor { ); } - #[allow(deprecated)] callback(Event::WindowEvent { window_id, event: WindowEvent::KeyboardInput { device_id, - input: KeyboardInput { - scancode, - state, - virtual_keycode, - modifiers, + event: KeyEvent { + physical_key: todo!(), + logical_key: todo!(), + text: todo!(), + location: todo!(), + state: todo!(), + repeat: todo!(), + platform_specific: todo!(), }, is_synthetic: true, }, diff --git a/src/platform_impl/linux/x11/events.rs b/src/platform_impl/linux/x11/events.rs index 1c34b0d0cb..e721ab5922 100644 --- a/src/platform_impl/linux/x11/events.rs +++ b/src/platform_impl/linux/x11/events.rs @@ -1,1008 +1,1008 @@ use super::ffi; -use crate::event::VirtualKeyCode; +use crate::keyboard::KeyCode; use libc; -pub fn keysym_to_element(keysym: libc::c_uint) -> Option { - Some(match keysym { - ffi::XK_BackSpace => VirtualKeyCode::Back, - ffi::XK_Tab => VirtualKeyCode::Tab, - //ffi::XK_Linefeed => VirtualKeyCode::Linefeed, - //ffi::XK_Clear => VirtualKeyCode::Clear, - ffi::XK_Return => VirtualKeyCode::Return, - ffi::XK_Pause => VirtualKeyCode::Pause, - //ffi::XK_Scroll_Lock => VirtualKeyCode::Scroll_lock, - //ffi::XK_Sys_Req => VirtualKeyCode::Sys_req, - ffi::XK_Escape => VirtualKeyCode::Escape, - ffi::XK_Delete => VirtualKeyCode::Delete, - ffi::XK_Multi_key => VirtualKeyCode::Compose, - //ffi::XK_Kanji => VirtualKeyCode::Kanji, - //ffi::XK_Muhenkan => VirtualKeyCode::Muhenkan, - //ffi::XK_Henkan_Mode => VirtualKeyCode::Henkan_mode, - //ffi::XK_Henkan => VirtualKeyCode::Henkan, - //ffi::XK_Romaji => VirtualKeyCode::Romaji, - //ffi::XK_Hiragana => VirtualKeyCode::Hiragana, - //ffi::XK_Katakana => VirtualKeyCode::Katakana, - //ffi::XK_Hiragana_Katakana => VirtualKeyCode::Hiragana_katakana, - //ffi::XK_Zenkaku => VirtualKeyCode::Zenkaku, - //ffi::XK_Hankaku => VirtualKeyCode::Hankaku, - //ffi::XK_Zenkaku_Hankaku => VirtualKeyCode::Zenkaku_hankaku, - //ffi::XK_Touroku => VirtualKeyCode::Touroku, - //ffi::XK_Massyo => VirtualKeyCode::Massyo, - //ffi::XK_Kana_Lock => VirtualKeyCode::Kana_lock, - //ffi::XK_Kana_Shift => VirtualKeyCode::Kana_shift, - //ffi::XK_Eisu_Shift => VirtualKeyCode::Eisu_shift, - //ffi::XK_Eisu_toggle => VirtualKeyCode::Eisu_toggle, - ffi::XK_Home => VirtualKeyCode::Home, - ffi::XK_Left => VirtualKeyCode::Left, - ffi::XK_Up => VirtualKeyCode::Up, - ffi::XK_Right => VirtualKeyCode::Right, - ffi::XK_Down => VirtualKeyCode::Down, - //ffi::XK_Prior => VirtualKeyCode::Prior, - ffi::XK_Page_Up => VirtualKeyCode::PageUp, - //ffi::XK_Next => VirtualKeyCode::Next, - ffi::XK_Page_Down => VirtualKeyCode::PageDown, - ffi::XK_End => VirtualKeyCode::End, - //ffi::XK_Begin => VirtualKeyCode::Begin, - //ffi::XK_Win_L => VirtualKeyCode::Win_l, - //ffi::XK_Win_R => VirtualKeyCode::Win_r, - //ffi::XK_App => VirtualKeyCode::App, - //ffi::XK_Select => VirtualKeyCode::Select, - //ffi::XK_Print => VirtualKeyCode::Print, - //ffi::XK_Execute => VirtualKeyCode::Execute, - ffi::XK_Insert => VirtualKeyCode::Insert, - //ffi::XK_Undo => VirtualKeyCode::Undo, - //ffi::XK_Redo => VirtualKeyCode::Redo, - //ffi::XK_Menu => VirtualKeyCode::Menu, - //ffi::XK_Find => VirtualKeyCode::Find, - //ffi::XK_Cancel => VirtualKeyCode::Cancel, - //ffi::XK_Help => VirtualKeyCode::Help, - //ffi::XK_Break => VirtualKeyCode::Break, - //ffi::XK_Mode_switch => VirtualKeyCode::Mode_switch, - //ffi::XK_script_switch => VirtualKeyCode::Script_switch, - ffi::XK_Num_Lock => VirtualKeyCode::Numlock, - //ffi::XK_KP_Space => VirtualKeyCode::Kp_space, - //ffi::XK_KP_Tab => VirtualKeyCode::Kp_tab, - ffi::XK_KP_Enter => VirtualKeyCode::NumpadEnter, - //ffi::XK_KP_F1 => VirtualKeyCode::Kp_f1, - //ffi::XK_KP_F2 => VirtualKeyCode::Kp_f2, - //ffi::XK_KP_F3 => VirtualKeyCode::Kp_f3, - //ffi::XK_KP_F4 => VirtualKeyCode::Kp_f4, - ffi::XK_KP_Home => VirtualKeyCode::Home, - ffi::XK_KP_Left => VirtualKeyCode::Left, - ffi::XK_KP_Up => VirtualKeyCode::Up, - ffi::XK_KP_Right => VirtualKeyCode::Right, - ffi::XK_KP_Down => VirtualKeyCode::Down, - //ffi::XK_KP_Prior => VirtualKeyCode::Kp_prior, - ffi::XK_KP_Page_Up => VirtualKeyCode::PageUp, - //ffi::XK_KP_Next => VirtualKeyCode::Kp_next, - ffi::XK_KP_Page_Down => VirtualKeyCode::PageDown, - ffi::XK_KP_End => VirtualKeyCode::End, - //ffi::XK_KP_Begin => VirtualKeyCode::Kp_begin, - ffi::XK_KP_Insert => VirtualKeyCode::Insert, - ffi::XK_KP_Delete => VirtualKeyCode::Delete, - ffi::XK_KP_Equal => VirtualKeyCode::NumpadEquals, - ffi::XK_KP_Multiply => VirtualKeyCode::NumpadMultiply, - ffi::XK_KP_Add => VirtualKeyCode::NumpadAdd, - ffi::XK_KP_Separator => VirtualKeyCode::NumpadComma, - ffi::XK_KP_Subtract => VirtualKeyCode::NumpadSubtract, - ffi::XK_KP_Decimal => VirtualKeyCode::NumpadDecimal, - ffi::XK_KP_Divide => VirtualKeyCode::NumpadDivide, - ffi::XK_KP_0 => VirtualKeyCode::Numpad0, - ffi::XK_KP_1 => VirtualKeyCode::Numpad1, - ffi::XK_KP_2 => VirtualKeyCode::Numpad2, - ffi::XK_KP_3 => VirtualKeyCode::Numpad3, - ffi::XK_KP_4 => VirtualKeyCode::Numpad4, - ffi::XK_KP_5 => VirtualKeyCode::Numpad5, - ffi::XK_KP_6 => VirtualKeyCode::Numpad6, - ffi::XK_KP_7 => VirtualKeyCode::Numpad7, - ffi::XK_KP_8 => VirtualKeyCode::Numpad8, - ffi::XK_KP_9 => VirtualKeyCode::Numpad9, - ffi::XK_F1 => VirtualKeyCode::F1, - ffi::XK_F2 => VirtualKeyCode::F2, - ffi::XK_F3 => VirtualKeyCode::F3, - ffi::XK_F4 => VirtualKeyCode::F4, - ffi::XK_F5 => VirtualKeyCode::F5, - ffi::XK_F6 => VirtualKeyCode::F6, - ffi::XK_F7 => VirtualKeyCode::F7, - ffi::XK_F8 => VirtualKeyCode::F8, - ffi::XK_F9 => VirtualKeyCode::F9, - ffi::XK_F10 => VirtualKeyCode::F10, - ffi::XK_F11 => VirtualKeyCode::F11, - //ffi::XK_L1 => VirtualKeyCode::L1, - ffi::XK_F12 => VirtualKeyCode::F12, - //ffi::XK_L2 => VirtualKeyCode::L2, - ffi::XK_F13 => VirtualKeyCode::F13, - //ffi::XK_L3 => VirtualKeyCode::L3, - ffi::XK_F14 => VirtualKeyCode::F14, - //ffi::XK_L4 => VirtualKeyCode::L4, - ffi::XK_F15 => VirtualKeyCode::F15, - //ffi::XK_L5 => VirtualKeyCode::L5, - ffi::XK_F16 => VirtualKeyCode::F16, - //ffi::XK_L6 => VirtualKeyCode::L6, - ffi::XK_F17 => VirtualKeyCode::F17, - //ffi::XK_L7 => VirtualKeyCode::L7, - ffi::XK_F18 => VirtualKeyCode::F18, - //ffi::XK_L8 => VirtualKeyCode::L8, - ffi::XK_F19 => VirtualKeyCode::F19, - //ffi::XK_L9 => VirtualKeyCode::L9, - ffi::XK_F20 => VirtualKeyCode::F20, - //ffi::XK_L10 => VirtualKeyCode::L10, - ffi::XK_F21 => VirtualKeyCode::F21, - //ffi::XK_R1 => VirtualKeyCode::R1, - ffi::XK_F22 => VirtualKeyCode::F22, - //ffi::XK_R2 => VirtualKeyCode::R2, - ffi::XK_F23 => VirtualKeyCode::F23, - //ffi::XK_R3 => VirtualKeyCode::R3, - ffi::XK_F24 => VirtualKeyCode::F24, - //ffi::XK_R4 => VirtualKeyCode::R4, - //ffi::XK_F25 => VirtualKeyCode::F25, - //ffi::XK_R5 => VirtualKeyCode::R5, - //ffi::XK_F26 => VirtualKeyCode::F26, - //ffi::XK_R6 => VirtualKeyCode::R6, - //ffi::XK_F27 => VirtualKeyCode::F27, - //ffi::XK_R7 => VirtualKeyCode::R7, - //ffi::XK_F28 => VirtualKeyCode::F28, - //ffi::XK_R8 => VirtualKeyCode::R8, - //ffi::XK_F29 => VirtualKeyCode::F29, - //ffi::XK_R9 => VirtualKeyCode::R9, - //ffi::XK_F30 => VirtualKeyCode::F30, - //ffi::XK_R10 => VirtualKeyCode::R10, - //ffi::XK_F31 => VirtualKeyCode::F31, - //ffi::XK_R11 => VirtualKeyCode::R11, - //ffi::XK_F32 => VirtualKeyCode::F32, - //ffi::XK_R12 => VirtualKeyCode::R12, - //ffi::XK_F33 => VirtualKeyCode::F33, - //ffi::XK_R13 => VirtualKeyCode::R13, - //ffi::XK_F34 => VirtualKeyCode::F34, - //ffi::XK_R14 => VirtualKeyCode::R14, - //ffi::XK_F35 => VirtualKeyCode::F35, - //ffi::XK_R15 => VirtualKeyCode::R15, - ffi::XK_Shift_L => VirtualKeyCode::LShift, - ffi::XK_Shift_R => VirtualKeyCode::RShift, - ffi::XK_Control_L => VirtualKeyCode::LControl, - ffi::XK_Control_R => VirtualKeyCode::RControl, - //ffi::XK_Caps_Lock => VirtualKeyCode::Caps_lock, - //ffi::XK_Shift_Lock => VirtualKeyCode::Shift_lock, - //ffi::XK_Meta_L => VirtualKeyCode::Meta_l, - //ffi::XK_Meta_R => VirtualKeyCode::Meta_r, - ffi::XK_Alt_L => VirtualKeyCode::LAlt, - ffi::XK_Alt_R => VirtualKeyCode::RAlt, - //ffi::XK_Super_L => VirtualKeyCode::Super_l, - //ffi::XK_Super_R => VirtualKeyCode::Super_r, - //ffi::XK_Hyper_L => VirtualKeyCode::Hyper_l, - //ffi::XK_Hyper_R => VirtualKeyCode::Hyper_r, - ffi::XK_ISO_Left_Tab => VirtualKeyCode::Tab, - ffi::XK_space => VirtualKeyCode::Space, - //ffi::XK_exclam => VirtualKeyCode::Exclam, - //ffi::XK_quotedbl => VirtualKeyCode::Quotedbl, - //ffi::XK_numbersign => VirtualKeyCode::Numbersign, - //ffi::XK_dollar => VirtualKeyCode::Dollar, - //ffi::XK_percent => VirtualKeyCode::Percent, - //ffi::XK_ampersand => VirtualKeyCode::Ampersand, - ffi::XK_apostrophe => VirtualKeyCode::Apostrophe, - //ffi::XK_quoteright => VirtualKeyCode::Quoteright, - //ffi::XK_parenleft => VirtualKeyCode::Parenleft, - //ffi::XK_parenright => VirtualKeyCode::Parenright, - ffi::XK_asterisk => VirtualKeyCode::Asterisk, - ffi::XK_plus => VirtualKeyCode::Plus, - ffi::XK_comma => VirtualKeyCode::Comma, - ffi::XK_minus => VirtualKeyCode::Minus, - ffi::XK_period => VirtualKeyCode::Period, - ffi::XK_slash => VirtualKeyCode::Slash, - ffi::XK_0 => VirtualKeyCode::Key0, - ffi::XK_1 => VirtualKeyCode::Key1, - ffi::XK_2 => VirtualKeyCode::Key2, - ffi::XK_3 => VirtualKeyCode::Key3, - ffi::XK_4 => VirtualKeyCode::Key4, - ffi::XK_5 => VirtualKeyCode::Key5, - ffi::XK_6 => VirtualKeyCode::Key6, - ffi::XK_7 => VirtualKeyCode::Key7, - ffi::XK_8 => VirtualKeyCode::Key8, - ffi::XK_9 => VirtualKeyCode::Key9, - ffi::XK_colon => VirtualKeyCode::Colon, - ffi::XK_semicolon => VirtualKeyCode::Semicolon, - //ffi::XK_less => VirtualKeyCode::Less, - ffi::XK_equal => VirtualKeyCode::Equals, - //ffi::XK_greater => VirtualKeyCode::Greater, - //ffi::XK_question => VirtualKeyCode::Question, - ffi::XK_at => VirtualKeyCode::At, - ffi::XK_A => VirtualKeyCode::A, - ffi::XK_B => VirtualKeyCode::B, - ffi::XK_C => VirtualKeyCode::C, - ffi::XK_D => VirtualKeyCode::D, - ffi::XK_E => VirtualKeyCode::E, - ffi::XK_F => VirtualKeyCode::F, - ffi::XK_G => VirtualKeyCode::G, - ffi::XK_H => VirtualKeyCode::H, - ffi::XK_I => VirtualKeyCode::I, - ffi::XK_J => VirtualKeyCode::J, - ffi::XK_K => VirtualKeyCode::K, - ffi::XK_L => VirtualKeyCode::L, - ffi::XK_M => VirtualKeyCode::M, - ffi::XK_N => VirtualKeyCode::N, - ffi::XK_O => VirtualKeyCode::O, - ffi::XK_P => VirtualKeyCode::P, - ffi::XK_Q => VirtualKeyCode::Q, - ffi::XK_R => VirtualKeyCode::R, - ffi::XK_S => VirtualKeyCode::S, - ffi::XK_T => VirtualKeyCode::T, - ffi::XK_U => VirtualKeyCode::U, - ffi::XK_V => VirtualKeyCode::V, - ffi::XK_W => VirtualKeyCode::W, - ffi::XK_X => VirtualKeyCode::X, - ffi::XK_Y => VirtualKeyCode::Y, - ffi::XK_Z => VirtualKeyCode::Z, - ffi::XK_bracketleft => VirtualKeyCode::LBracket, - ffi::XK_backslash => VirtualKeyCode::Backslash, - ffi::XK_bracketright => VirtualKeyCode::RBracket, - //ffi::XK_asciicircum => VirtualKeyCode::Asciicircum, - //ffi::XK_underscore => VirtualKeyCode::Underscore, - ffi::XK_grave => VirtualKeyCode::Grave, - //ffi::XK_quoteleft => VirtualKeyCode::Quoteleft, - ffi::XK_a => VirtualKeyCode::A, - ffi::XK_b => VirtualKeyCode::B, - ffi::XK_c => VirtualKeyCode::C, - ffi::XK_d => VirtualKeyCode::D, - ffi::XK_e => VirtualKeyCode::E, - ffi::XK_f => VirtualKeyCode::F, - ffi::XK_g => VirtualKeyCode::G, - ffi::XK_h => VirtualKeyCode::H, - ffi::XK_i => VirtualKeyCode::I, - ffi::XK_j => VirtualKeyCode::J, - ffi::XK_k => VirtualKeyCode::K, - ffi::XK_l => VirtualKeyCode::L, - ffi::XK_m => VirtualKeyCode::M, - ffi::XK_n => VirtualKeyCode::N, - ffi::XK_o => VirtualKeyCode::O, - ffi::XK_p => VirtualKeyCode::P, - ffi::XK_q => VirtualKeyCode::Q, - ffi::XK_r => VirtualKeyCode::R, - ffi::XK_s => VirtualKeyCode::S, - ffi::XK_t => VirtualKeyCode::T, - ffi::XK_u => VirtualKeyCode::U, - ffi::XK_v => VirtualKeyCode::V, - ffi::XK_w => VirtualKeyCode::W, - ffi::XK_x => VirtualKeyCode::X, - ffi::XK_y => VirtualKeyCode::Y, - ffi::XK_z => VirtualKeyCode::Z, - //ffi::XK_braceleft => VirtualKeyCode::Braceleft, - //ffi::XK_bar => VirtualKeyCode::Bar, - //ffi::XK_braceright => VirtualKeyCode::Braceright, - //ffi::XK_asciitilde => VirtualKeyCode::Asciitilde, - //ffi::XK_nobreakspace => VirtualKeyCode::Nobreakspace, - //ffi::XK_exclamdown => VirtualKeyCode::Exclamdown, - //ffi::XK_cent => VirtualKeyCode::Cent, - //ffi::XK_sterling => VirtualKeyCode::Sterling, - //ffi::XK_currency => VirtualKeyCode::Currency, - //ffi::XK_yen => VirtualKeyCode::Yen, - //ffi::XK_brokenbar => VirtualKeyCode::Brokenbar, - //ffi::XK_section => VirtualKeyCode::Section, - //ffi::XK_diaeresis => VirtualKeyCode::Diaeresis, - //ffi::XK_copyright => VirtualKeyCode::Copyright, - //ffi::XK_ordfeminine => VirtualKeyCode::Ordfeminine, - //ffi::XK_guillemotleft => VirtualKeyCode::Guillemotleft, - //ffi::XK_notsign => VirtualKeyCode::Notsign, - //ffi::XK_hyphen => VirtualKeyCode::Hyphen, - //ffi::XK_registered => VirtualKeyCode::Registered, - //ffi::XK_macron => VirtualKeyCode::Macron, - //ffi::XK_degree => VirtualKeyCode::Degree, - //ffi::XK_plusminus => VirtualKeyCode::Plusminus, - //ffi::XK_twosuperior => VirtualKeyCode::Twosuperior, - //ffi::XK_threesuperior => VirtualKeyCode::Threesuperior, - //ffi::XK_acute => VirtualKeyCode::Acute, - //ffi::XK_mu => VirtualKeyCode::Mu, - //ffi::XK_paragraph => VirtualKeyCode::Paragraph, - //ffi::XK_periodcentered => VirtualKeyCode::Periodcentered, - //ffi::XK_cedilla => VirtualKeyCode::Cedilla, - //ffi::XK_onesuperior => VirtualKeyCode::Onesuperior, - //ffi::XK_masculine => VirtualKeyCode::Masculine, - //ffi::XK_guillemotright => VirtualKeyCode::Guillemotright, - //ffi::XK_onequarter => VirtualKeyCode::Onequarter, - //ffi::XK_onehalf => VirtualKeyCode::Onehalf, - //ffi::XK_threequarters => VirtualKeyCode::Threequarters, - //ffi::XK_questiondown => VirtualKeyCode::Questiondown, - //ffi::XK_Agrave => VirtualKeyCode::Agrave, - //ffi::XK_Aacute => VirtualKeyCode::Aacute, - //ffi::XK_Acircumflex => VirtualKeyCode::Acircumflex, - //ffi::XK_Atilde => VirtualKeyCode::Atilde, - //ffi::XK_Adiaeresis => VirtualKeyCode::Adiaeresis, - //ffi::XK_Aring => VirtualKeyCode::Aring, - //ffi::XK_AE => VirtualKeyCode::Ae, - //ffi::XK_Ccedilla => VirtualKeyCode::Ccedilla, - //ffi::XK_Egrave => VirtualKeyCode::Egrave, - //ffi::XK_Eacute => VirtualKeyCode::Eacute, - //ffi::XK_Ecircumflex => VirtualKeyCode::Ecircumflex, - //ffi::XK_Ediaeresis => VirtualKeyCode::Ediaeresis, - //ffi::XK_Igrave => VirtualKeyCode::Igrave, - //ffi::XK_Iacute => VirtualKeyCode::Iacute, - //ffi::XK_Icircumflex => VirtualKeyCode::Icircumflex, - //ffi::XK_Idiaeresis => VirtualKeyCode::Idiaeresis, - //ffi::XK_ETH => VirtualKeyCode::Eth, - //ffi::XK_Eth => VirtualKeyCode::Eth, - //ffi::XK_Ntilde => VirtualKeyCode::Ntilde, - //ffi::XK_Ograve => VirtualKeyCode::Ograve, - //ffi::XK_Oacute => VirtualKeyCode::Oacute, - //ffi::XK_Ocircumflex => VirtualKeyCode::Ocircumflex, - //ffi::XK_Otilde => VirtualKeyCode::Otilde, - //ffi::XK_Odiaeresis => VirtualKeyCode::Odiaeresis, - //ffi::XK_multiply => VirtualKeyCode::Multiply, - //ffi::XK_Ooblique => VirtualKeyCode::Ooblique, - //ffi::XK_Ugrave => VirtualKeyCode::Ugrave, - //ffi::XK_Uacute => VirtualKeyCode::Uacute, - //ffi::XK_Ucircumflex => VirtualKeyCode::Ucircumflex, - //ffi::XK_Udiaeresis => VirtualKeyCode::Udiaeresis, - //ffi::XK_Yacute => VirtualKeyCode::Yacute, - //ffi::XK_THORN => VirtualKeyCode::Thorn, - //ffi::XK_Thorn => VirtualKeyCode::Thorn, - //ffi::XK_ssharp => VirtualKeyCode::Ssharp, - //ffi::XK_agrave => VirtualKeyCode::Agrave, - //ffi::XK_aacute => VirtualKeyCode::Aacute, - //ffi::XK_acircumflex => VirtualKeyCode::Acircumflex, - //ffi::XK_atilde => VirtualKeyCode::Atilde, - //ffi::XK_adiaeresis => VirtualKeyCode::Adiaeresis, - //ffi::XK_aring => VirtualKeyCode::Aring, - //ffi::XK_ae => VirtualKeyCode::Ae, - //ffi::XK_ccedilla => VirtualKeyCode::Ccedilla, - //ffi::XK_egrave => VirtualKeyCode::Egrave, - //ffi::XK_eacute => VirtualKeyCode::Eacute, - //ffi::XK_ecircumflex => VirtualKeyCode::Ecircumflex, - //ffi::XK_ediaeresis => VirtualKeyCode::Ediaeresis, - //ffi::XK_igrave => VirtualKeyCode::Igrave, - //ffi::XK_iacute => VirtualKeyCode::Iacute, - //ffi::XK_icircumflex => VirtualKeyCode::Icircumflex, - //ffi::XK_idiaeresis => VirtualKeyCode::Idiaeresis, - //ffi::XK_eth => VirtualKeyCode::Eth, - //ffi::XK_ntilde => VirtualKeyCode::Ntilde, - //ffi::XK_ograve => VirtualKeyCode::Ograve, - //ffi::XK_oacute => VirtualKeyCode::Oacute, - //ffi::XK_ocircumflex => VirtualKeyCode::Ocircumflex, - //ffi::XK_otilde => VirtualKeyCode::Otilde, - //ffi::XK_odiaeresis => VirtualKeyCode::Odiaeresis, - //ffi::XK_division => VirtualKeyCode::Division, - //ffi::XK_oslash => VirtualKeyCode::Oslash, - //ffi::XK_ugrave => VirtualKeyCode::Ugrave, - //ffi::XK_uacute => VirtualKeyCode::Uacute, - //ffi::XK_ucircumflex => VirtualKeyCode::Ucircumflex, - //ffi::XK_udiaeresis => VirtualKeyCode::Udiaeresis, - //ffi::XK_yacute => VirtualKeyCode::Yacute, - //ffi::XK_thorn => VirtualKeyCode::Thorn, - //ffi::XK_ydiaeresis => VirtualKeyCode::Ydiaeresis, - //ffi::XK_Aogonek => VirtualKeyCode::Aogonek, - //ffi::XK_breve => VirtualKeyCode::Breve, - //ffi::XK_Lstroke => VirtualKeyCode::Lstroke, - //ffi::XK_Lcaron => VirtualKeyCode::Lcaron, - //ffi::XK_Sacute => VirtualKeyCode::Sacute, - //ffi::XK_Scaron => VirtualKeyCode::Scaron, - //ffi::XK_Scedilla => VirtualKeyCode::Scedilla, - //ffi::XK_Tcaron => VirtualKeyCode::Tcaron, - //ffi::XK_Zacute => VirtualKeyCode::Zacute, - //ffi::XK_Zcaron => VirtualKeyCode::Zcaron, - //ffi::XK_Zabovedot => VirtualKeyCode::Zabovedot, - //ffi::XK_aogonek => VirtualKeyCode::Aogonek, - //ffi::XK_ogonek => VirtualKeyCode::Ogonek, - //ffi::XK_lstroke => VirtualKeyCode::Lstroke, - //ffi::XK_lcaron => VirtualKeyCode::Lcaron, - //ffi::XK_sacute => VirtualKeyCode::Sacute, - //ffi::XK_caron => VirtualKeyCode::Caron, - //ffi::XK_scaron => VirtualKeyCode::Scaron, - //ffi::XK_scedilla => VirtualKeyCode::Scedilla, - //ffi::XK_tcaron => VirtualKeyCode::Tcaron, - //ffi::XK_zacute => VirtualKeyCode::Zacute, - //ffi::XK_doubleacute => VirtualKeyCode::Doubleacute, - //ffi::XK_zcaron => VirtualKeyCode::Zcaron, - //ffi::XK_zabovedot => VirtualKeyCode::Zabovedot, - //ffi::XK_Racute => VirtualKeyCode::Racute, - //ffi::XK_Abreve => VirtualKeyCode::Abreve, - //ffi::XK_Lacute => VirtualKeyCode::Lacute, - //ffi::XK_Cacute => VirtualKeyCode::Cacute, - //ffi::XK_Ccaron => VirtualKeyCode::Ccaron, - //ffi::XK_Eogonek => VirtualKeyCode::Eogonek, - //ffi::XK_Ecaron => VirtualKeyCode::Ecaron, - //ffi::XK_Dcaron => VirtualKeyCode::Dcaron, - //ffi::XK_Dstroke => VirtualKeyCode::Dstroke, - //ffi::XK_Nacute => VirtualKeyCode::Nacute, - //ffi::XK_Ncaron => VirtualKeyCode::Ncaron, - //ffi::XK_Odoubleacute => VirtualKeyCode::Odoubleacute, - //ffi::XK_Rcaron => VirtualKeyCode::Rcaron, - //ffi::XK_Uring => VirtualKeyCode::Uring, - //ffi::XK_Udoubleacute => VirtualKeyCode::Udoubleacute, - //ffi::XK_Tcedilla => VirtualKeyCode::Tcedilla, - //ffi::XK_racute => VirtualKeyCode::Racute, - //ffi::XK_abreve => VirtualKeyCode::Abreve, - //ffi::XK_lacute => VirtualKeyCode::Lacute, - //ffi::XK_cacute => VirtualKeyCode::Cacute, - //ffi::XK_ccaron => VirtualKeyCode::Ccaron, - //ffi::XK_eogonek => VirtualKeyCode::Eogonek, - //ffi::XK_ecaron => VirtualKeyCode::Ecaron, - //ffi::XK_dcaron => VirtualKeyCode::Dcaron, - //ffi::XK_dstroke => VirtualKeyCode::Dstroke, - //ffi::XK_nacute => VirtualKeyCode::Nacute, - //ffi::XK_ncaron => VirtualKeyCode::Ncaron, - //ffi::XK_odoubleacute => VirtualKeyCode::Odoubleacute, - //ffi::XK_udoubleacute => VirtualKeyCode::Udoubleacute, - //ffi::XK_rcaron => VirtualKeyCode::Rcaron, - //ffi::XK_uring => VirtualKeyCode::Uring, - //ffi::XK_tcedilla => VirtualKeyCode::Tcedilla, - //ffi::XK_abovedot => VirtualKeyCode::Abovedot, - //ffi::XK_Hstroke => VirtualKeyCode::Hstroke, - //ffi::XK_Hcircumflex => VirtualKeyCode::Hcircumflex, - //ffi::XK_Iabovedot => VirtualKeyCode::Iabovedot, - //ffi::XK_Gbreve => VirtualKeyCode::Gbreve, - //ffi::XK_Jcircumflex => VirtualKeyCode::Jcircumflex, - //ffi::XK_hstroke => VirtualKeyCode::Hstroke, - //ffi::XK_hcircumflex => VirtualKeyCode::Hcircumflex, - //ffi::XK_idotless => VirtualKeyCode::Idotless, - //ffi::XK_gbreve => VirtualKeyCode::Gbreve, - //ffi::XK_jcircumflex => VirtualKeyCode::Jcircumflex, - //ffi::XK_Cabovedot => VirtualKeyCode::Cabovedot, - //ffi::XK_Ccircumflex => VirtualKeyCode::Ccircumflex, - //ffi::XK_Gabovedot => VirtualKeyCode::Gabovedot, - //ffi::XK_Gcircumflex => VirtualKeyCode::Gcircumflex, - //ffi::XK_Ubreve => VirtualKeyCode::Ubreve, - //ffi::XK_Scircumflex => VirtualKeyCode::Scircumflex, - //ffi::XK_cabovedot => VirtualKeyCode::Cabovedot, - //ffi::XK_ccircumflex => VirtualKeyCode::Ccircumflex, - //ffi::XK_gabovedot => VirtualKeyCode::Gabovedot, - //ffi::XK_gcircumflex => VirtualKeyCode::Gcircumflex, - //ffi::XK_ubreve => VirtualKeyCode::Ubreve, - //ffi::XK_scircumflex => VirtualKeyCode::Scircumflex, - //ffi::XK_kra => VirtualKeyCode::Kra, - //ffi::XK_kappa => VirtualKeyCode::Kappa, - //ffi::XK_Rcedilla => VirtualKeyCode::Rcedilla, - //ffi::XK_Itilde => VirtualKeyCode::Itilde, - //ffi::XK_Lcedilla => VirtualKeyCode::Lcedilla, - //ffi::XK_Emacron => VirtualKeyCode::Emacron, - //ffi::XK_Gcedilla => VirtualKeyCode::Gcedilla, - //ffi::XK_Tslash => VirtualKeyCode::Tslash, - //ffi::XK_rcedilla => VirtualKeyCode::Rcedilla, - //ffi::XK_itilde => VirtualKeyCode::Itilde, - //ffi::XK_lcedilla => VirtualKeyCode::Lcedilla, - //ffi::XK_emacron => VirtualKeyCode::Emacron, - //ffi::XK_gcedilla => VirtualKeyCode::Gcedilla, - //ffi::XK_tslash => VirtualKeyCode::Tslash, - //ffi::XK_ENG => VirtualKeyCode::Eng, - //ffi::XK_eng => VirtualKeyCode::Eng, - //ffi::XK_Amacron => VirtualKeyCode::Amacron, - //ffi::XK_Iogonek => VirtualKeyCode::Iogonek, - //ffi::XK_Eabovedot => VirtualKeyCode::Eabovedot, - //ffi::XK_Imacron => VirtualKeyCode::Imacron, - //ffi::XK_Ncedilla => VirtualKeyCode::Ncedilla, - //ffi::XK_Omacron => VirtualKeyCode::Omacron, - //ffi::XK_Kcedilla => VirtualKeyCode::Kcedilla, - //ffi::XK_Uogonek => VirtualKeyCode::Uogonek, - //ffi::XK_Utilde => VirtualKeyCode::Utilde, - //ffi::XK_Umacron => VirtualKeyCode::Umacron, - //ffi::XK_amacron => VirtualKeyCode::Amacron, - //ffi::XK_iogonek => VirtualKeyCode::Iogonek, - //ffi::XK_eabovedot => VirtualKeyCode::Eabovedot, - //ffi::XK_imacron => VirtualKeyCode::Imacron, - //ffi::XK_ncedilla => VirtualKeyCode::Ncedilla, - //ffi::XK_omacron => VirtualKeyCode::Omacron, - //ffi::XK_kcedilla => VirtualKeyCode::Kcedilla, - //ffi::XK_uogonek => VirtualKeyCode::Uogonek, - //ffi::XK_utilde => VirtualKeyCode::Utilde, - //ffi::XK_umacron => VirtualKeyCode::Umacron, - //ffi::XK_overline => VirtualKeyCode::Overline, - //ffi::XK_kana_fullstop => VirtualKeyCode::Kana_fullstop, - //ffi::XK_kana_openingbracket => VirtualKeyCode::Kana_openingbracket, - //ffi::XK_kana_closingbracket => VirtualKeyCode::Kana_closingbracket, - //ffi::XK_kana_comma => VirtualKeyCode::Kana_comma, - //ffi::XK_kana_conjunctive => VirtualKeyCode::Kana_conjunctive, - //ffi::XK_kana_middledot => VirtualKeyCode::Kana_middledot, - //ffi::XK_kana_WO => VirtualKeyCode::Kana_wo, - //ffi::XK_kana_a => VirtualKeyCode::Kana_a, - //ffi::XK_kana_i => VirtualKeyCode::Kana_i, - //ffi::XK_kana_u => VirtualKeyCode::Kana_u, - //ffi::XK_kana_e => VirtualKeyCode::Kana_e, - //ffi::XK_kana_o => VirtualKeyCode::Kana_o, - //ffi::XK_kana_ya => VirtualKeyCode::Kana_ya, - //ffi::XK_kana_yu => VirtualKeyCode::Kana_yu, - //ffi::XK_kana_yo => VirtualKeyCode::Kana_yo, - //ffi::XK_kana_tsu => VirtualKeyCode::Kana_tsu, - //ffi::XK_kana_tu => VirtualKeyCode::Kana_tu, - //ffi::XK_prolongedsound => VirtualKeyCode::Prolongedsound, - //ffi::XK_kana_A => VirtualKeyCode::Kana_a, - //ffi::XK_kana_I => VirtualKeyCode::Kana_i, - //ffi::XK_kana_U => VirtualKeyCode::Kana_u, - //ffi::XK_kana_E => VirtualKeyCode::Kana_e, - //ffi::XK_kana_O => VirtualKeyCode::Kana_o, - //ffi::XK_kana_KA => VirtualKeyCode::Kana_ka, - //ffi::XK_kana_KI => VirtualKeyCode::Kana_ki, - //ffi::XK_kana_KU => VirtualKeyCode::Kana_ku, - //ffi::XK_kana_KE => VirtualKeyCode::Kana_ke, - //ffi::XK_kana_KO => VirtualKeyCode::Kana_ko, - //ffi::XK_kana_SA => VirtualKeyCode::Kana_sa, - //ffi::XK_kana_SHI => VirtualKeyCode::Kana_shi, - //ffi::XK_kana_SU => VirtualKeyCode::Kana_su, - //ffi::XK_kana_SE => VirtualKeyCode::Kana_se, - //ffi::XK_kana_SO => VirtualKeyCode::Kana_so, - //ffi::XK_kana_TA => VirtualKeyCode::Kana_ta, - //ffi::XK_kana_CHI => VirtualKeyCode::Kana_chi, - //ffi::XK_kana_TI => VirtualKeyCode::Kana_ti, - //ffi::XK_kana_TSU => VirtualKeyCode::Kana_tsu, - //ffi::XK_kana_TU => VirtualKeyCode::Kana_tu, - //ffi::XK_kana_TE => VirtualKeyCode::Kana_te, - //ffi::XK_kana_TO => VirtualKeyCode::Kana_to, - //ffi::XK_kana_NA => VirtualKeyCode::Kana_na, - //ffi::XK_kana_NI => VirtualKeyCode::Kana_ni, - //ffi::XK_kana_NU => VirtualKeyCode::Kana_nu, - //ffi::XK_kana_NE => VirtualKeyCode::Kana_ne, - //ffi::XK_kana_NO => VirtualKeyCode::Kana_no, - //ffi::XK_kana_HA => VirtualKeyCode::Kana_ha, - //ffi::XK_kana_HI => VirtualKeyCode::Kana_hi, - //ffi::XK_kana_FU => VirtualKeyCode::Kana_fu, - //ffi::XK_kana_HU => VirtualKeyCode::Kana_hu, - //ffi::XK_kana_HE => VirtualKeyCode::Kana_he, - //ffi::XK_kana_HO => VirtualKeyCode::Kana_ho, - //ffi::XK_kana_MA => VirtualKeyCode::Kana_ma, - //ffi::XK_kana_MI => VirtualKeyCode::Kana_mi, - //ffi::XK_kana_MU => VirtualKeyCode::Kana_mu, - //ffi::XK_kana_ME => VirtualKeyCode::Kana_me, - //ffi::XK_kana_MO => VirtualKeyCode::Kana_mo, - //ffi::XK_kana_YA => VirtualKeyCode::Kana_ya, - //ffi::XK_kana_YU => VirtualKeyCode::Kana_yu, - //ffi::XK_kana_YO => VirtualKeyCode::Kana_yo, - //ffi::XK_kana_RA => VirtualKeyCode::Kana_ra, - //ffi::XK_kana_RI => VirtualKeyCode::Kana_ri, - //ffi::XK_kana_RU => VirtualKeyCode::Kana_ru, - //ffi::XK_kana_RE => VirtualKeyCode::Kana_re, - //ffi::XK_kana_RO => VirtualKeyCode::Kana_ro, - //ffi::XK_kana_WA => VirtualKeyCode::Kana_wa, - //ffi::XK_kana_N => VirtualKeyCode::Kana_n, - //ffi::XK_voicedsound => VirtualKeyCode::Voicedsound, - //ffi::XK_semivoicedsound => VirtualKeyCode::Semivoicedsound, - //ffi::XK_kana_switch => VirtualKeyCode::Kana_switch, - //ffi::XK_Arabic_comma => VirtualKeyCode::Arabic_comma, - //ffi::XK_Arabic_semicolon => VirtualKeyCode::Arabic_semicolon, - //ffi::XK_Arabic_question_mark => VirtualKeyCode::Arabic_question_mark, - //ffi::XK_Arabic_hamza => VirtualKeyCode::Arabic_hamza, - //ffi::XK_Arabic_maddaonalef => VirtualKeyCode::Arabic_maddaonalef, - //ffi::XK_Arabic_hamzaonalef => VirtualKeyCode::Arabic_hamzaonalef, - //ffi::XK_Arabic_hamzaonwaw => VirtualKeyCode::Arabic_hamzaonwaw, - //ffi::XK_Arabic_hamzaunderalef => VirtualKeyCode::Arabic_hamzaunderalef, - //ffi::XK_Arabic_hamzaonyeh => VirtualKeyCode::Arabic_hamzaonyeh, - //ffi::XK_Arabic_alef => VirtualKeyCode::Arabic_alef, - //ffi::XK_Arabic_beh => VirtualKeyCode::Arabic_beh, - //ffi::XK_Arabic_tehmarbuta => VirtualKeyCode::Arabic_tehmarbuta, - //ffi::XK_Arabic_teh => VirtualKeyCode::Arabic_teh, - //ffi::XK_Arabic_theh => VirtualKeyCode::Arabic_theh, - //ffi::XK_Arabic_jeem => VirtualKeyCode::Arabic_jeem, - //ffi::XK_Arabic_hah => VirtualKeyCode::Arabic_hah, - //ffi::XK_Arabic_khah => VirtualKeyCode::Arabic_khah, - //ffi::XK_Arabic_dal => VirtualKeyCode::Arabic_dal, - //ffi::XK_Arabic_thal => VirtualKeyCode::Arabic_thal, - //ffi::XK_Arabic_ra => VirtualKeyCode::Arabic_ra, - //ffi::XK_Arabic_zain => VirtualKeyCode::Arabic_zain, - //ffi::XK_Arabic_seen => VirtualKeyCode::Arabic_seen, - //ffi::XK_Arabic_sheen => VirtualKeyCode::Arabic_sheen, - //ffi::XK_Arabic_sad => VirtualKeyCode::Arabic_sad, - //ffi::XK_Arabic_dad => VirtualKeyCode::Arabic_dad, - //ffi::XK_Arabic_tah => VirtualKeyCode::Arabic_tah, - //ffi::XK_Arabic_zah => VirtualKeyCode::Arabic_zah, - //ffi::XK_Arabic_ain => VirtualKeyCode::Arabic_ain, - //ffi::XK_Arabic_ghain => VirtualKeyCode::Arabic_ghain, - //ffi::XK_Arabic_tatweel => VirtualKeyCode::Arabic_tatweel, - //ffi::XK_Arabic_feh => VirtualKeyCode::Arabic_feh, - //ffi::XK_Arabic_qaf => VirtualKeyCode::Arabic_qaf, - //ffi::XK_Arabic_kaf => VirtualKeyCode::Arabic_kaf, - //ffi::XK_Arabic_lam => VirtualKeyCode::Arabic_lam, - //ffi::XK_Arabic_meem => VirtualKeyCode::Arabic_meem, - //ffi::XK_Arabic_noon => VirtualKeyCode::Arabic_noon, - //ffi::XK_Arabic_ha => VirtualKeyCode::Arabic_ha, - //ffi::XK_Arabic_heh => VirtualKeyCode::Arabic_heh, - //ffi::XK_Arabic_waw => VirtualKeyCode::Arabic_waw, - //ffi::XK_Arabic_alefmaksura => VirtualKeyCode::Arabic_alefmaksura, - //ffi::XK_Arabic_yeh => VirtualKeyCode::Arabic_yeh, - //ffi::XK_Arabic_fathatan => VirtualKeyCode::Arabic_fathatan, - //ffi::XK_Arabic_dammatan => VirtualKeyCode::Arabic_dammatan, - //ffi::XK_Arabic_kasratan => VirtualKeyCode::Arabic_kasratan, - //ffi::XK_Arabic_fatha => VirtualKeyCode::Arabic_fatha, - //ffi::XK_Arabic_damma => VirtualKeyCode::Arabic_damma, - //ffi::XK_Arabic_kasra => VirtualKeyCode::Arabic_kasra, - //ffi::XK_Arabic_shadda => VirtualKeyCode::Arabic_shadda, - //ffi::XK_Arabic_sukun => VirtualKeyCode::Arabic_sukun, - //ffi::XK_Arabic_switch => VirtualKeyCode::Arabic_switch, - //ffi::XK_Serbian_dje => VirtualKeyCode::Serbian_dje, - //ffi::XK_Macedonia_gje => VirtualKeyCode::Macedonia_gje, - //ffi::XK_Cyrillic_io => VirtualKeyCode::Cyrillic_io, - //ffi::XK_Ukrainian_ie => VirtualKeyCode::Ukrainian_ie, - //ffi::XK_Ukranian_je => VirtualKeyCode::Ukranian_je, - //ffi::XK_Macedonia_dse => VirtualKeyCode::Macedonia_dse, - //ffi::XK_Ukrainian_i => VirtualKeyCode::Ukrainian_i, - //ffi::XK_Ukranian_i => VirtualKeyCode::Ukranian_i, - //ffi::XK_Ukrainian_yi => VirtualKeyCode::Ukrainian_yi, - //ffi::XK_Ukranian_yi => VirtualKeyCode::Ukranian_yi, - //ffi::XK_Cyrillic_je => VirtualKeyCode::Cyrillic_je, - //ffi::XK_Serbian_je => VirtualKeyCode::Serbian_je, - //ffi::XK_Cyrillic_lje => VirtualKeyCode::Cyrillic_lje, - //ffi::XK_Serbian_lje => VirtualKeyCode::Serbian_lje, - //ffi::XK_Cyrillic_nje => VirtualKeyCode::Cyrillic_nje, - //ffi::XK_Serbian_nje => VirtualKeyCode::Serbian_nje, - //ffi::XK_Serbian_tshe => VirtualKeyCode::Serbian_tshe, - //ffi::XK_Macedonia_kje => VirtualKeyCode::Macedonia_kje, - //ffi::XK_Byelorussian_shortu => VirtualKeyCode::Byelorussian_shortu, - //ffi::XK_Cyrillic_dzhe => VirtualKeyCode::Cyrillic_dzhe, - //ffi::XK_Serbian_dze => VirtualKeyCode::Serbian_dze, - //ffi::XK_numerosign => VirtualKeyCode::Numerosign, - //ffi::XK_Serbian_DJE => VirtualKeyCode::Serbian_dje, - //ffi::XK_Macedonia_GJE => VirtualKeyCode::Macedonia_gje, - //ffi::XK_Cyrillic_IO => VirtualKeyCode::Cyrillic_io, - //ffi::XK_Ukrainian_IE => VirtualKeyCode::Ukrainian_ie, - //ffi::XK_Ukranian_JE => VirtualKeyCode::Ukranian_je, - //ffi::XK_Macedonia_DSE => VirtualKeyCode::Macedonia_dse, - //ffi::XK_Ukrainian_I => VirtualKeyCode::Ukrainian_i, - //ffi::XK_Ukranian_I => VirtualKeyCode::Ukranian_i, - //ffi::XK_Ukrainian_YI => VirtualKeyCode::Ukrainian_yi, - //ffi::XK_Ukranian_YI => VirtualKeyCode::Ukranian_yi, - //ffi::XK_Cyrillic_JE => VirtualKeyCode::Cyrillic_je, - //ffi::XK_Serbian_JE => VirtualKeyCode::Serbian_je, - //ffi::XK_Cyrillic_LJE => VirtualKeyCode::Cyrillic_lje, - //ffi::XK_Serbian_LJE => VirtualKeyCode::Serbian_lje, - //ffi::XK_Cyrillic_NJE => VirtualKeyCode::Cyrillic_nje, - //ffi::XK_Serbian_NJE => VirtualKeyCode::Serbian_nje, - //ffi::XK_Serbian_TSHE => VirtualKeyCode::Serbian_tshe, - //ffi::XK_Macedonia_KJE => VirtualKeyCode::Macedonia_kje, - //ffi::XK_Byelorussian_SHORTU => VirtualKeyCode::Byelorussian_shortu, - //ffi::XK_Cyrillic_DZHE => VirtualKeyCode::Cyrillic_dzhe, - //ffi::XK_Serbian_DZE => VirtualKeyCode::Serbian_dze, - //ffi::XK_Cyrillic_yu => VirtualKeyCode::Cyrillic_yu, - //ffi::XK_Cyrillic_a => VirtualKeyCode::Cyrillic_a, - //ffi::XK_Cyrillic_be => VirtualKeyCode::Cyrillic_be, - //ffi::XK_Cyrillic_tse => VirtualKeyCode::Cyrillic_tse, - //ffi::XK_Cyrillic_de => VirtualKeyCode::Cyrillic_de, - //ffi::XK_Cyrillic_ie => VirtualKeyCode::Cyrillic_ie, - //ffi::XK_Cyrillic_ef => VirtualKeyCode::Cyrillic_ef, - //ffi::XK_Cyrillic_ghe => VirtualKeyCode::Cyrillic_ghe, - //ffi::XK_Cyrillic_ha => VirtualKeyCode::Cyrillic_ha, - //ffi::XK_Cyrillic_i => VirtualKeyCode::Cyrillic_i, - //ffi::XK_Cyrillic_shorti => VirtualKeyCode::Cyrillic_shorti, - //ffi::XK_Cyrillic_ka => VirtualKeyCode::Cyrillic_ka, - //ffi::XK_Cyrillic_el => VirtualKeyCode::Cyrillic_el, - //ffi::XK_Cyrillic_em => VirtualKeyCode::Cyrillic_em, - //ffi::XK_Cyrillic_en => VirtualKeyCode::Cyrillic_en, - //ffi::XK_Cyrillic_o => VirtualKeyCode::Cyrillic_o, - //ffi::XK_Cyrillic_pe => VirtualKeyCode::Cyrillic_pe, - //ffi::XK_Cyrillic_ya => VirtualKeyCode::Cyrillic_ya, - //ffi::XK_Cyrillic_er => VirtualKeyCode::Cyrillic_er, - //ffi::XK_Cyrillic_es => VirtualKeyCode::Cyrillic_es, - //ffi::XK_Cyrillic_te => VirtualKeyCode::Cyrillic_te, - //ffi::XK_Cyrillic_u => VirtualKeyCode::Cyrillic_u, - //ffi::XK_Cyrillic_zhe => VirtualKeyCode::Cyrillic_zhe, - //ffi::XK_Cyrillic_ve => VirtualKeyCode::Cyrillic_ve, - //ffi::XK_Cyrillic_softsign => VirtualKeyCode::Cyrillic_softsign, - //ffi::XK_Cyrillic_yeru => VirtualKeyCode::Cyrillic_yeru, - //ffi::XK_Cyrillic_ze => VirtualKeyCode::Cyrillic_ze, - //ffi::XK_Cyrillic_sha => VirtualKeyCode::Cyrillic_sha, - //ffi::XK_Cyrillic_e => VirtualKeyCode::Cyrillic_e, - //ffi::XK_Cyrillic_shcha => VirtualKeyCode::Cyrillic_shcha, - //ffi::XK_Cyrillic_che => VirtualKeyCode::Cyrillic_che, - //ffi::XK_Cyrillic_hardsign => VirtualKeyCode::Cyrillic_hardsign, - //ffi::XK_Cyrillic_YU => VirtualKeyCode::Cyrillic_yu, - //ffi::XK_Cyrillic_A => VirtualKeyCode::Cyrillic_a, - //ffi::XK_Cyrillic_BE => VirtualKeyCode::Cyrillic_be, - //ffi::XK_Cyrillic_TSE => VirtualKeyCode::Cyrillic_tse, - //ffi::XK_Cyrillic_DE => VirtualKeyCode::Cyrillic_de, - //ffi::XK_Cyrillic_IE => VirtualKeyCode::Cyrillic_ie, - //ffi::XK_Cyrillic_EF => VirtualKeyCode::Cyrillic_ef, - //ffi::XK_Cyrillic_GHE => VirtualKeyCode::Cyrillic_ghe, - //ffi::XK_Cyrillic_HA => VirtualKeyCode::Cyrillic_ha, - //ffi::XK_Cyrillic_I => VirtualKeyCode::Cyrillic_i, - //ffi::XK_Cyrillic_SHORTI => VirtualKeyCode::Cyrillic_shorti, - //ffi::XK_Cyrillic_KA => VirtualKeyCode::Cyrillic_ka, - //ffi::XK_Cyrillic_EL => VirtualKeyCode::Cyrillic_el, - //ffi::XK_Cyrillic_EM => VirtualKeyCode::Cyrillic_em, - //ffi::XK_Cyrillic_EN => VirtualKeyCode::Cyrillic_en, - //ffi::XK_Cyrillic_O => VirtualKeyCode::Cyrillic_o, - //ffi::XK_Cyrillic_PE => VirtualKeyCode::Cyrillic_pe, - //ffi::XK_Cyrillic_YA => VirtualKeyCode::Cyrillic_ya, - //ffi::XK_Cyrillic_ER => VirtualKeyCode::Cyrillic_er, - //ffi::XK_Cyrillic_ES => VirtualKeyCode::Cyrillic_es, - //ffi::XK_Cyrillic_TE => VirtualKeyCode::Cyrillic_te, - //ffi::XK_Cyrillic_U => VirtualKeyCode::Cyrillic_u, - //ffi::XK_Cyrillic_ZHE => VirtualKeyCode::Cyrillic_zhe, - //ffi::XK_Cyrillic_VE => VirtualKeyCode::Cyrillic_ve, - //ffi::XK_Cyrillic_SOFTSIGN => VirtualKeyCode::Cyrillic_softsign, - //ffi::XK_Cyrillic_YERU => VirtualKeyCode::Cyrillic_yeru, - //ffi::XK_Cyrillic_ZE => VirtualKeyCode::Cyrillic_ze, - //ffi::XK_Cyrillic_SHA => VirtualKeyCode::Cyrillic_sha, - //ffi::XK_Cyrillic_E => VirtualKeyCode::Cyrillic_e, - //ffi::XK_Cyrillic_SHCHA => VirtualKeyCode::Cyrillic_shcha, - //ffi::XK_Cyrillic_CHE => VirtualKeyCode::Cyrillic_che, - //ffi::XK_Cyrillic_HARDSIGN => VirtualKeyCode::Cyrillic_hardsign, - //ffi::XK_Greek_ALPHAaccent => VirtualKeyCode::Greek_alphaaccent, - //ffi::XK_Greek_EPSILONaccent => VirtualKeyCode::Greek_epsilonaccent, - //ffi::XK_Greek_ETAaccent => VirtualKeyCode::Greek_etaaccent, - //ffi::XK_Greek_IOTAaccent => VirtualKeyCode::Greek_iotaaccent, - //ffi::XK_Greek_IOTAdiaeresis => VirtualKeyCode::Greek_iotadiaeresis, - //ffi::XK_Greek_OMICRONaccent => VirtualKeyCode::Greek_omicronaccent, - //ffi::XK_Greek_UPSILONaccent => VirtualKeyCode::Greek_upsilonaccent, - //ffi::XK_Greek_UPSILONdieresis => VirtualKeyCode::Greek_upsilondieresis, - //ffi::XK_Greek_OMEGAaccent => VirtualKeyCode::Greek_omegaaccent, - //ffi::XK_Greek_accentdieresis => VirtualKeyCode::Greek_accentdieresis, - //ffi::XK_Greek_horizbar => VirtualKeyCode::Greek_horizbar, - //ffi::XK_Greek_alphaaccent => VirtualKeyCode::Greek_alphaaccent, - //ffi::XK_Greek_epsilonaccent => VirtualKeyCode::Greek_epsilonaccent, - //ffi::XK_Greek_etaaccent => VirtualKeyCode::Greek_etaaccent, - //ffi::XK_Greek_iotaaccent => VirtualKeyCode::Greek_iotaaccent, - //ffi::XK_Greek_iotadieresis => VirtualKeyCode::Greek_iotadieresis, - //ffi::XK_Greek_iotaaccentdieresis => VirtualKeyCode::Greek_iotaaccentdieresis, - //ffi::XK_Greek_omicronaccent => VirtualKeyCode::Greek_omicronaccent, - //ffi::XK_Greek_upsilonaccent => VirtualKeyCode::Greek_upsilonaccent, - //ffi::XK_Greek_upsilondieresis => VirtualKeyCode::Greek_upsilondieresis, - //ffi::XK_Greek_upsilonaccentdieresis => VirtualKeyCode::Greek_upsilonaccentdieresis, - //ffi::XK_Greek_omegaaccent => VirtualKeyCode::Greek_omegaaccent, - //ffi::XK_Greek_ALPHA => VirtualKeyCode::Greek_alpha, - //ffi::XK_Greek_BETA => VirtualKeyCode::Greek_beta, - //ffi::XK_Greek_GAMMA => VirtualKeyCode::Greek_gamma, - //ffi::XK_Greek_DELTA => VirtualKeyCode::Greek_delta, - //ffi::XK_Greek_EPSILON => VirtualKeyCode::Greek_epsilon, - //ffi::XK_Greek_ZETA => VirtualKeyCode::Greek_zeta, - //ffi::XK_Greek_ETA => VirtualKeyCode::Greek_eta, - //ffi::XK_Greek_THETA => VirtualKeyCode::Greek_theta, - //ffi::XK_Greek_IOTA => VirtualKeyCode::Greek_iota, - //ffi::XK_Greek_KAPPA => VirtualKeyCode::Greek_kappa, - //ffi::XK_Greek_LAMDA => VirtualKeyCode::Greek_lamda, - //ffi::XK_Greek_LAMBDA => VirtualKeyCode::Greek_lambda, - //ffi::XK_Greek_MU => VirtualKeyCode::Greek_mu, - //ffi::XK_Greek_NU => VirtualKeyCode::Greek_nu, - //ffi::XK_Greek_XI => VirtualKeyCode::Greek_xi, - //ffi::XK_Greek_OMICRON => VirtualKeyCode::Greek_omicron, - //ffi::XK_Greek_PI => VirtualKeyCode::Greek_pi, - //ffi::XK_Greek_RHO => VirtualKeyCode::Greek_rho, - //ffi::XK_Greek_SIGMA => VirtualKeyCode::Greek_sigma, - //ffi::XK_Greek_TAU => VirtualKeyCode::Greek_tau, - //ffi::XK_Greek_UPSILON => VirtualKeyCode::Greek_upsilon, - //ffi::XK_Greek_PHI => VirtualKeyCode::Greek_phi, - //ffi::XK_Greek_CHI => VirtualKeyCode::Greek_chi, - //ffi::XK_Greek_PSI => VirtualKeyCode::Greek_psi, - //ffi::XK_Greek_OMEGA => VirtualKeyCode::Greek_omega, - //ffi::XK_Greek_alpha => VirtualKeyCode::Greek_alpha, - //ffi::XK_Greek_beta => VirtualKeyCode::Greek_beta, - //ffi::XK_Greek_gamma => VirtualKeyCode::Greek_gamma, - //ffi::XK_Greek_delta => VirtualKeyCode::Greek_delta, - //ffi::XK_Greek_epsilon => VirtualKeyCode::Greek_epsilon, - //ffi::XK_Greek_zeta => VirtualKeyCode::Greek_zeta, - //ffi::XK_Greek_eta => VirtualKeyCode::Greek_eta, - //ffi::XK_Greek_theta => VirtualKeyCode::Greek_theta, - //ffi::XK_Greek_iota => VirtualKeyCode::Greek_iota, - //ffi::XK_Greek_kappa => VirtualKeyCode::Greek_kappa, - //ffi::XK_Greek_lamda => VirtualKeyCode::Greek_lamda, - //ffi::XK_Greek_lambda => VirtualKeyCode::Greek_lambda, - //ffi::XK_Greek_mu => VirtualKeyCode::Greek_mu, - //ffi::XK_Greek_nu => VirtualKeyCode::Greek_nu, - //ffi::XK_Greek_xi => VirtualKeyCode::Greek_xi, - //ffi::XK_Greek_omicron => VirtualKeyCode::Greek_omicron, - //ffi::XK_Greek_pi => VirtualKeyCode::Greek_pi, - //ffi::XK_Greek_rho => VirtualKeyCode::Greek_rho, - //ffi::XK_Greek_sigma => VirtualKeyCode::Greek_sigma, - //ffi::XK_Greek_finalsmallsigma => VirtualKeyCode::Greek_finalsmallsigma, - //ffi::XK_Greek_tau => VirtualKeyCode::Greek_tau, - //ffi::XK_Greek_upsilon => VirtualKeyCode::Greek_upsilon, - //ffi::XK_Greek_phi => VirtualKeyCode::Greek_phi, - //ffi::XK_Greek_chi => VirtualKeyCode::Greek_chi, - //ffi::XK_Greek_psi => VirtualKeyCode::Greek_psi, - //ffi::XK_Greek_omega => VirtualKeyCode::Greek_omega, - //ffi::XK_Greek_switch => VirtualKeyCode::Greek_switch, - //ffi::XK_leftradical => VirtualKeyCode::Leftradical, - //ffi::XK_topleftradical => VirtualKeyCode::Topleftradical, - //ffi::XK_horizconnector => VirtualKeyCode::Horizconnector, - //ffi::XK_topintegral => VirtualKeyCode::Topintegral, - //ffi::XK_botintegral => VirtualKeyCode::Botintegral, - //ffi::XK_vertconnector => VirtualKeyCode::Vertconnector, - //ffi::XK_topleftsqbracket => VirtualKeyCode::Topleftsqbracket, - //ffi::XK_botleftsqbracket => VirtualKeyCode::Botleftsqbracket, - //ffi::XK_toprightsqbracket => VirtualKeyCode::Toprightsqbracket, - //ffi::XK_botrightsqbracket => VirtualKeyCode::Botrightsqbracket, - //ffi::XK_topleftparens => VirtualKeyCode::Topleftparens, - //ffi::XK_botleftparens => VirtualKeyCode::Botleftparens, - //ffi::XK_toprightparens => VirtualKeyCode::Toprightparens, - //ffi::XK_botrightparens => VirtualKeyCode::Botrightparens, - //ffi::XK_leftmiddlecurlybrace => VirtualKeyCode::Leftmiddlecurlybrace, - //ffi::XK_rightmiddlecurlybrace => VirtualKeyCode::Rightmiddlecurlybrace, - //ffi::XK_topleftsummation => VirtualKeyCode::Topleftsummation, - //ffi::XK_botleftsummation => VirtualKeyCode::Botleftsummation, - //ffi::XK_topvertsummationconnector => VirtualKeyCode::Topvertsummationconnector, - //ffi::XK_botvertsummationconnector => VirtualKeyCode::Botvertsummationconnector, - //ffi::XK_toprightsummation => VirtualKeyCode::Toprightsummation, - //ffi::XK_botrightsummation => VirtualKeyCode::Botrightsummation, - //ffi::XK_rightmiddlesummation => VirtualKeyCode::Rightmiddlesummation, - //ffi::XK_lessthanequal => VirtualKeyCode::Lessthanequal, - //ffi::XK_notequal => VirtualKeyCode::Notequal, - //ffi::XK_greaterthanequal => VirtualKeyCode::Greaterthanequal, - //ffi::XK_integral => VirtualKeyCode::Integral, - //ffi::XK_therefore => VirtualKeyCode::Therefore, - //ffi::XK_variation => VirtualKeyCode::Variation, - //ffi::XK_infinity => VirtualKeyCode::Infinity, - //ffi::XK_nabla => VirtualKeyCode::Nabla, - //ffi::XK_approximate => VirtualKeyCode::Approximate, - //ffi::XK_similarequal => VirtualKeyCode::Similarequal, - //ffi::XK_ifonlyif => VirtualKeyCode::Ifonlyif, - //ffi::XK_implies => VirtualKeyCode::Implies, - //ffi::XK_identical => VirtualKeyCode::Identical, - //ffi::XK_radical => VirtualKeyCode::Radical, - //ffi::XK_includedin => VirtualKeyCode::Includedin, - //ffi::XK_includes => VirtualKeyCode::Includes, - //ffi::XK_intersection => VirtualKeyCode::Intersection, - //ffi::XK_union => VirtualKeyCode::Union, - //ffi::XK_logicaland => VirtualKeyCode::Logicaland, - //ffi::XK_logicalor => VirtualKeyCode::Logicalor, - //ffi::XK_partialderivative => VirtualKeyCode::Partialderivative, - //ffi::XK_function => VirtualKeyCode::Function, - //ffi::XK_leftarrow => VirtualKeyCode::Leftarrow, - //ffi::XK_uparrow => VirtualKeyCode::Uparrow, - //ffi::XK_rightarrow => VirtualKeyCode::Rightarrow, - //ffi::XK_downarrow => VirtualKeyCode::Downarrow, - //ffi::XK_blank => VirtualKeyCode::Blank, - //ffi::XK_soliddiamond => VirtualKeyCode::Soliddiamond, - //ffi::XK_checkerboard => VirtualKeyCode::Checkerboard, - //ffi::XK_ht => VirtualKeyCode::Ht, - //ffi::XK_ff => VirtualKeyCode::Ff, - //ffi::XK_cr => VirtualKeyCode::Cr, - //ffi::XK_lf => VirtualKeyCode::Lf, - //ffi::XK_nl => VirtualKeyCode::Nl, - //ffi::XK_vt => VirtualKeyCode::Vt, - //ffi::XK_lowrightcorner => VirtualKeyCode::Lowrightcorner, - //ffi::XK_uprightcorner => VirtualKeyCode::Uprightcorner, - //ffi::XK_upleftcorner => VirtualKeyCode::Upleftcorner, - //ffi::XK_lowleftcorner => VirtualKeyCode::Lowleftcorner, - //ffi::XK_crossinglines => VirtualKeyCode::Crossinglines, - //ffi::XK_horizlinescan1 => VirtualKeyCode::Horizlinescan1, - //ffi::XK_horizlinescan3 => VirtualKeyCode::Horizlinescan3, - //ffi::XK_horizlinescan5 => VirtualKeyCode::Horizlinescan5, - //ffi::XK_horizlinescan7 => VirtualKeyCode::Horizlinescan7, - //ffi::XK_horizlinescan9 => VirtualKeyCode::Horizlinescan9, - //ffi::XK_leftt => VirtualKeyCode::Leftt, - //ffi::XK_rightt => VirtualKeyCode::Rightt, - //ffi::XK_bott => VirtualKeyCode::Bott, - //ffi::XK_topt => VirtualKeyCode::Topt, - //ffi::XK_vertbar => VirtualKeyCode::Vertbar, - //ffi::XK_emspace => VirtualKeyCode::Emspace, - //ffi::XK_enspace => VirtualKeyCode::Enspace, - //ffi::XK_em3space => VirtualKeyCode::Em3space, - //ffi::XK_em4space => VirtualKeyCode::Em4space, - //ffi::XK_digitspace => VirtualKeyCode::Digitspace, - //ffi::XK_punctspace => VirtualKeyCode::Punctspace, - //ffi::XK_thinspace => VirtualKeyCode::Thinspace, - //ffi::XK_hairspace => VirtualKeyCode::Hairspace, - //ffi::XK_emdash => VirtualKeyCode::Emdash, - //ffi::XK_endash => VirtualKeyCode::Endash, - //ffi::XK_signifblank => VirtualKeyCode::Signifblank, - //ffi::XK_ellipsis => VirtualKeyCode::Ellipsis, - //ffi::XK_doubbaselinedot => VirtualKeyCode::Doubbaselinedot, - //ffi::XK_onethird => VirtualKeyCode::Onethird, - //ffi::XK_twothirds => VirtualKeyCode::Twothirds, - //ffi::XK_onefifth => VirtualKeyCode::Onefifth, - //ffi::XK_twofifths => VirtualKeyCode::Twofifths, - //ffi::XK_threefifths => VirtualKeyCode::Threefifths, - //ffi::XK_fourfifths => VirtualKeyCode::Fourfifths, - //ffi::XK_onesixth => VirtualKeyCode::Onesixth, - //ffi::XK_fivesixths => VirtualKeyCode::Fivesixths, - //ffi::XK_careof => VirtualKeyCode::Careof, - //ffi::XK_figdash => VirtualKeyCode::Figdash, - //ffi::XK_leftanglebracket => VirtualKeyCode::Leftanglebracket, - //ffi::XK_decimalpoint => VirtualKeyCode::Decimalpoint, - //ffi::XK_rightanglebracket => VirtualKeyCode::Rightanglebracket, - //ffi::XK_marker => VirtualKeyCode::Marker, - //ffi::XK_oneeighth => VirtualKeyCode::Oneeighth, - //ffi::XK_threeeighths => VirtualKeyCode::Threeeighths, - //ffi::XK_fiveeighths => VirtualKeyCode::Fiveeighths, - //ffi::XK_seveneighths => VirtualKeyCode::Seveneighths, - //ffi::XK_trademark => VirtualKeyCode::Trademark, - //ffi::XK_signaturemark => VirtualKeyCode::Signaturemark, - //ffi::XK_trademarkincircle => VirtualKeyCode::Trademarkincircle, - //ffi::XK_leftopentriangle => VirtualKeyCode::Leftopentriangle, - //ffi::XK_rightopentriangle => VirtualKeyCode::Rightopentriangle, - //ffi::XK_emopencircle => VirtualKeyCode::Emopencircle, - //ffi::XK_emopenrectangle => VirtualKeyCode::Emopenrectangle, - //ffi::XK_leftsinglequotemark => VirtualKeyCode::Leftsinglequotemark, - //ffi::XK_rightsinglequotemark => VirtualKeyCode::Rightsinglequotemark, - //ffi::XK_leftdoublequotemark => VirtualKeyCode::Leftdoublequotemark, - //ffi::XK_rightdoublequotemark => VirtualKeyCode::Rightdoublequotemark, - //ffi::XK_prescription => VirtualKeyCode::Prescription, - //ffi::XK_minutes => VirtualKeyCode::Minutes, - //ffi::XK_seconds => VirtualKeyCode::Seconds, - //ffi::XK_latincross => VirtualKeyCode::Latincross, - //ffi::XK_hexagram => VirtualKeyCode::Hexagram, - //ffi::XK_filledrectbullet => VirtualKeyCode::Filledrectbullet, - //ffi::XK_filledlefttribullet => VirtualKeyCode::Filledlefttribullet, - //ffi::XK_filledrighttribullet => VirtualKeyCode::Filledrighttribullet, - //ffi::XK_emfilledcircle => VirtualKeyCode::Emfilledcircle, - //ffi::XK_emfilledrect => VirtualKeyCode::Emfilledrect, - //ffi::XK_enopencircbullet => VirtualKeyCode::Enopencircbullet, - //ffi::XK_enopensquarebullet => VirtualKeyCode::Enopensquarebullet, - //ffi::XK_openrectbullet => VirtualKeyCode::Openrectbullet, - //ffi::XK_opentribulletup => VirtualKeyCode::Opentribulletup, - //ffi::XK_opentribulletdown => VirtualKeyCode::Opentribulletdown, - //ffi::XK_openstar => VirtualKeyCode::Openstar, - //ffi::XK_enfilledcircbullet => VirtualKeyCode::Enfilledcircbullet, - //ffi::XK_enfilledsqbullet => VirtualKeyCode::Enfilledsqbullet, - //ffi::XK_filledtribulletup => VirtualKeyCode::Filledtribulletup, - //ffi::XK_filledtribulletdown => VirtualKeyCode::Filledtribulletdown, - //ffi::XK_leftpointer => VirtualKeyCode::Leftpointer, - //ffi::XK_rightpointer => VirtualKeyCode::Rightpointer, - //ffi::XK_club => VirtualKeyCode::Club, - //ffi::XK_diamond => VirtualKeyCode::Diamond, - //ffi::XK_heart => VirtualKeyCode::Heart, - //ffi::XK_maltesecross => VirtualKeyCode::Maltesecross, - //ffi::XK_dagger => VirtualKeyCode::Dagger, - //ffi::XK_doubledagger => VirtualKeyCode::Doubledagger, - //ffi::XK_checkmark => VirtualKeyCode::Checkmark, - //ffi::XK_ballotcross => VirtualKeyCode::Ballotcross, - //ffi::XK_musicalsharp => VirtualKeyCode::Musicalsharp, - //ffi::XK_musicalflat => VirtualKeyCode::Musicalflat, - //ffi::XK_malesymbol => VirtualKeyCode::Malesymbol, - //ffi::XK_femalesymbol => VirtualKeyCode::Femalesymbol, - //ffi::XK_telephone => VirtualKeyCode::Telephone, - //ffi::XK_telephonerecorder => VirtualKeyCode::Telephonerecorder, - //ffi::XK_phonographcopyright => VirtualKeyCode::Phonographcopyright, - //ffi::XK_caret => VirtualKeyCode::Caret, - //ffi::XK_singlelowquotemark => VirtualKeyCode::Singlelowquotemark, - //ffi::XK_doublelowquotemark => VirtualKeyCode::Doublelowquotemark, - //ffi::XK_cursor => VirtualKeyCode::Cursor, - //ffi::XK_leftcaret => VirtualKeyCode::Leftcaret, - //ffi::XK_rightcaret => VirtualKeyCode::Rightcaret, - //ffi::XK_downcaret => VirtualKeyCode::Downcaret, - //ffi::XK_upcaret => VirtualKeyCode::Upcaret, - //ffi::XK_overbar => VirtualKeyCode::Overbar, - //ffi::XK_downtack => VirtualKeyCode::Downtack, - //ffi::XK_upshoe => VirtualKeyCode::Upshoe, - //ffi::XK_downstile => VirtualKeyCode::Downstile, - //ffi::XK_underbar => VirtualKeyCode::Underbar, - //ffi::XK_jot => VirtualKeyCode::Jot, - //ffi::XK_quad => VirtualKeyCode::Quad, - //ffi::XK_uptack => VirtualKeyCode::Uptack, - //ffi::XK_circle => VirtualKeyCode::Circle, - //ffi::XK_upstile => VirtualKeyCode::Upstile, - //ffi::XK_downshoe => VirtualKeyCode::Downshoe, - //ffi::XK_rightshoe => VirtualKeyCode::Rightshoe, - //ffi::XK_leftshoe => VirtualKeyCode::Leftshoe, - //ffi::XK_lefttack => VirtualKeyCode::Lefttack, - //ffi::XK_righttack => VirtualKeyCode::Righttack, - //ffi::XK_hebrew_doublelowline => VirtualKeyCode::Hebrew_doublelowline, - //ffi::XK_hebrew_aleph => VirtualKeyCode::Hebrew_aleph, - //ffi::XK_hebrew_bet => VirtualKeyCode::Hebrew_bet, - //ffi::XK_hebrew_beth => VirtualKeyCode::Hebrew_beth, - //ffi::XK_hebrew_gimel => VirtualKeyCode::Hebrew_gimel, - //ffi::XK_hebrew_gimmel => VirtualKeyCode::Hebrew_gimmel, - //ffi::XK_hebrew_dalet => VirtualKeyCode::Hebrew_dalet, - //ffi::XK_hebrew_daleth => VirtualKeyCode::Hebrew_daleth, - //ffi::XK_hebrew_he => VirtualKeyCode::Hebrew_he, - //ffi::XK_hebrew_waw => VirtualKeyCode::Hebrew_waw, - //ffi::XK_hebrew_zain => VirtualKeyCode::Hebrew_zain, - //ffi::XK_hebrew_zayin => VirtualKeyCode::Hebrew_zayin, - //ffi::XK_hebrew_chet => VirtualKeyCode::Hebrew_chet, - //ffi::XK_hebrew_het => VirtualKeyCode::Hebrew_het, - //ffi::XK_hebrew_tet => VirtualKeyCode::Hebrew_tet, - //ffi::XK_hebrew_teth => VirtualKeyCode::Hebrew_teth, - //ffi::XK_hebrew_yod => VirtualKeyCode::Hebrew_yod, - //ffi::XK_hebrew_finalkaph => VirtualKeyCode::Hebrew_finalkaph, - //ffi::XK_hebrew_kaph => VirtualKeyCode::Hebrew_kaph, - //ffi::XK_hebrew_lamed => VirtualKeyCode::Hebrew_lamed, - //ffi::XK_hebrew_finalmem => VirtualKeyCode::Hebrew_finalmem, - //ffi::XK_hebrew_mem => VirtualKeyCode::Hebrew_mem, - //ffi::XK_hebrew_finalnun => VirtualKeyCode::Hebrew_finalnun, - //ffi::XK_hebrew_nun => VirtualKeyCode::Hebrew_nun, - //ffi::XK_hebrew_samech => VirtualKeyCode::Hebrew_samech, - //ffi::XK_hebrew_samekh => VirtualKeyCode::Hebrew_samekh, - //ffi::XK_hebrew_ayin => VirtualKeyCode::Hebrew_ayin, - //ffi::XK_hebrew_finalpe => VirtualKeyCode::Hebrew_finalpe, - //ffi::XK_hebrew_pe => VirtualKeyCode::Hebrew_pe, - //ffi::XK_hebrew_finalzade => VirtualKeyCode::Hebrew_finalzade, - //ffi::XK_hebrew_finalzadi => VirtualKeyCode::Hebrew_finalzadi, - //ffi::XK_hebrew_zade => VirtualKeyCode::Hebrew_zade, - //ffi::XK_hebrew_zadi => VirtualKeyCode::Hebrew_zadi, - //ffi::XK_hebrew_qoph => VirtualKeyCode::Hebrew_qoph, - //ffi::XK_hebrew_kuf => VirtualKeyCode::Hebrew_kuf, - //ffi::XK_hebrew_resh => VirtualKeyCode::Hebrew_resh, - //ffi::XK_hebrew_shin => VirtualKeyCode::Hebrew_shin, - //ffi::XK_hebrew_taw => VirtualKeyCode::Hebrew_taw, - //ffi::XK_hebrew_taf => VirtualKeyCode::Hebrew_taf, - //ffi::XK_Hebrew_switch => VirtualKeyCode::Hebrew_switch, - ffi::XF86XK_Back => VirtualKeyCode::NavigateBackward, - ffi::XF86XK_Forward => VirtualKeyCode::NavigateForward, - ffi::XF86XK_Copy => VirtualKeyCode::Copy, - ffi::XF86XK_Paste => VirtualKeyCode::Paste, - ffi::XF86XK_Cut => VirtualKeyCode::Cut, - _ => return None, - }) -} +// pub fn keysym_to_element(keysym: libc::c_uint) -> Option { +// Some(match keysym { +// ffi::XK_BackSpace => VirtualKeyCode::Back, +// ffi::XK_Tab => VirtualKeyCode::Tab, +// //ffi::XK_Linefeed => VirtualKeyCode::Linefeed, +// //ffi::XK_Clear => VirtualKeyCode::Clear, +// ffi::XK_Return => VirtualKeyCode::Return, +// //ffi::XK_Pause => VirtualKeyCode::Pause, +// //ffi::XK_Scroll_Lock => VirtualKeyCode::Scroll_lock, +// //ffi::XK_Sys_Req => VirtualKeyCode::Sys_req, +// ffi::XK_Escape => VirtualKeyCode::Escape, +// ffi::XK_Delete => VirtualKeyCode::Delete, +// ffi::XK_Multi_key => VirtualKeyCode::Compose, +// //ffi::XK_Kanji => VirtualKeyCode::Kanji, +// //ffi::XK_Muhenkan => VirtualKeyCode::Muhenkan, +// //ffi::XK_Henkan_Mode => VirtualKeyCode::Henkan_mode, +// //ffi::XK_Henkan => VirtualKeyCode::Henkan, +// //ffi::XK_Romaji => VirtualKeyCode::Romaji, +// //ffi::XK_Hiragana => VirtualKeyCode::Hiragana, +// //ffi::XK_Katakana => VirtualKeyCode::Katakana, +// //ffi::XK_Hiragana_Katakana => VirtualKeyCode::Hiragana_katakana, +// //ffi::XK_Zenkaku => VirtualKeyCode::Zenkaku, +// //ffi::XK_Hankaku => VirtualKeyCode::Hankaku, +// //ffi::XK_Zenkaku_Hankaku => VirtualKeyCode::Zenkaku_hankaku, +// //ffi::XK_Touroku => VirtualKeyCode::Touroku, +// //ffi::XK_Massyo => VirtualKeyCode::Massyo, +// //ffi::XK_Kana_Lock => VirtualKeyCode::Kana_lock, +// //ffi::XK_Kana_Shift => VirtualKeyCode::Kana_shift, +// //ffi::XK_Eisu_Shift => VirtualKeyCode::Eisu_shift, +// //ffi::XK_Eisu_toggle => VirtualKeyCode::Eisu_toggle, +// ffi::XK_Home => VirtualKeyCode::Home, +// ffi::XK_Left => VirtualKeyCode::Left, +// ffi::XK_Up => VirtualKeyCode::Up, +// ffi::XK_Right => VirtualKeyCode::Right, +// ffi::XK_Down => VirtualKeyCode::Down, +// //ffi::XK_Prior => VirtualKeyCode::Prior, +// ffi::XK_Page_Up => VirtualKeyCode::PageUp, +// //ffi::XK_Next => VirtualKeyCode::Next, +// ffi::XK_Page_Down => VirtualKeyCode::PageDown, +// ffi::XK_End => VirtualKeyCode::End, +// //ffi::XK_Begin => VirtualKeyCode::Begin, +// //ffi::XK_Win_L => VirtualKeyCode::Win_l, +// //ffi::XK_Win_R => VirtualKeyCode::Win_r, +// //ffi::XK_App => VirtualKeyCode::App, +// //ffi::XK_Select => VirtualKeyCode::Select, +// //ffi::XK_Print => VirtualKeyCode::Print, +// //ffi::XK_Execute => VirtualKeyCode::Execute, +// ffi::XK_Insert => VirtualKeyCode::Insert, +// //ffi::XK_Undo => VirtualKeyCode::Undo, +// //ffi::XK_Redo => VirtualKeyCode::Redo, +// //ffi::XK_Menu => VirtualKeyCode::Menu, +// //ffi::XK_Find => VirtualKeyCode::Find, +// //ffi::XK_Cancel => VirtualKeyCode::Cancel, +// //ffi::XK_Help => VirtualKeyCode::Help, +// //ffi::XK_Break => VirtualKeyCode::Break, +// //ffi::XK_Mode_switch => VirtualKeyCode::Mode_switch, +// //ffi::XK_script_switch => VirtualKeyCode::Script_switch, +// //ffi::XK_Num_Lock => VirtualKeyCode::Num_lock, +// //ffi::XK_KP_Space => VirtualKeyCode::Kp_space, +// //ffi::XK_KP_Tab => VirtualKeyCode::Kp_tab, +// //ffi::XK_KP_Enter => VirtualKeyCode::Kp_enter, +// //ffi::XK_KP_F1 => VirtualKeyCode::Kp_f1, +// //ffi::XK_KP_F2 => VirtualKeyCode::Kp_f2, +// //ffi::XK_KP_F3 => VirtualKeyCode::Kp_f3, +// //ffi::XK_KP_F4 => VirtualKeyCode::Kp_f4, +// ffi::XK_KP_Home => VirtualKeyCode::Home, +// ffi::XK_KP_Left => VirtualKeyCode::Left, +// ffi::XK_KP_Up => VirtualKeyCode::Up, +// ffi::XK_KP_Right => VirtualKeyCode::Right, +// ffi::XK_KP_Down => VirtualKeyCode::Down, +// //ffi::XK_KP_Prior => VirtualKeyCode::Kp_prior, +// ffi::XK_KP_Page_Up => VirtualKeyCode::PageUp, +// //ffi::XK_KP_Next => VirtualKeyCode::Kp_next, +// ffi::XK_KP_Page_Down => VirtualKeyCode::PageDown, +// ffi::XK_KP_End => VirtualKeyCode::End, +// //ffi::XK_KP_Begin => VirtualKeyCode::Kp_begin, +// ffi::XK_KP_Insert => VirtualKeyCode::Insert, +// ffi::XK_KP_Delete => VirtualKeyCode::Delete, +// ffi::XK_KP_Equal => VirtualKeyCode::NumpadEquals, +// ffi::XK_KP_Multiply => VirtualKeyCode::NumpadMultiply, +// ffi::XK_KP_Add => VirtualKeyCode::NumpadAdd, +// //ffi::XK_KP_Separator => VirtualKeyCode::Kp_separator, +// ffi::XK_KP_Subtract => VirtualKeyCode::NumpadSubtract, +// ffi::XK_KP_Decimal => VirtualKeyCode::NumpadDecimal, +// ffi::XK_KP_Divide => VirtualKeyCode::NumpadDivide, +// ffi::XK_KP_0 => VirtualKeyCode::Numpad0, +// ffi::XK_KP_1 => VirtualKeyCode::Numpad1, +// ffi::XK_KP_2 => VirtualKeyCode::Numpad2, +// ffi::XK_KP_3 => VirtualKeyCode::Numpad3, +// ffi::XK_KP_4 => VirtualKeyCode::Numpad4, +// ffi::XK_KP_5 => VirtualKeyCode::Numpad5, +// ffi::XK_KP_6 => VirtualKeyCode::Numpad6, +// ffi::XK_KP_7 => VirtualKeyCode::Numpad7, +// ffi::XK_KP_8 => VirtualKeyCode::Numpad8, +// ffi::XK_KP_9 => VirtualKeyCode::Numpad9, +// ffi::XK_F1 => VirtualKeyCode::F1, +// ffi::XK_F2 => VirtualKeyCode::F2, +// ffi::XK_F3 => VirtualKeyCode::F3, +// ffi::XK_F4 => VirtualKeyCode::F4, +// ffi::XK_F5 => VirtualKeyCode::F5, +// ffi::XK_F6 => VirtualKeyCode::F6, +// ffi::XK_F7 => VirtualKeyCode::F7, +// ffi::XK_F8 => VirtualKeyCode::F8, +// ffi::XK_F9 => VirtualKeyCode::F9, +// ffi::XK_F10 => VirtualKeyCode::F10, +// ffi::XK_F11 => VirtualKeyCode::F11, +// //ffi::XK_L1 => VirtualKeyCode::L1, +// ffi::XK_F12 => VirtualKeyCode::F12, +// //ffi::XK_L2 => VirtualKeyCode::L2, +// ffi::XK_F13 => VirtualKeyCode::F13, +// //ffi::XK_L3 => VirtualKeyCode::L3, +// ffi::XK_F14 => VirtualKeyCode::F14, +// //ffi::XK_L4 => VirtualKeyCode::L4, +// ffi::XK_F15 => VirtualKeyCode::F15, +// //ffi::XK_L5 => VirtualKeyCode::L5, +// ffi::XK_F16 => VirtualKeyCode::F16, +// //ffi::XK_L6 => VirtualKeyCode::L6, +// ffi::XK_F17 => VirtualKeyCode::F17, +// //ffi::XK_L7 => VirtualKeyCode::L7, +// ffi::XK_F18 => VirtualKeyCode::F18, +// //ffi::XK_L8 => VirtualKeyCode::L8, +// ffi::XK_F19 => VirtualKeyCode::F19, +// //ffi::XK_L9 => VirtualKeyCode::L9, +// ffi::XK_F20 => VirtualKeyCode::F20, +// //ffi::XK_L10 => VirtualKeyCode::L10, +// ffi::XK_F21 => VirtualKeyCode::F21, +// //ffi::XK_R1 => VirtualKeyCode::R1, +// ffi::XK_F22 => VirtualKeyCode::F22, +// //ffi::XK_R2 => VirtualKeyCode::R2, +// ffi::XK_F23 => VirtualKeyCode::F23, +// //ffi::XK_R3 => VirtualKeyCode::R3, +// ffi::XK_F24 => VirtualKeyCode::F24, +// //ffi::XK_R4 => VirtualKeyCode::R4, +// //ffi::XK_F25 => VirtualKeyCode::F25, +// //ffi::XK_R5 => VirtualKeyCode::R5, +// //ffi::XK_F26 => VirtualKeyCode::F26, +// //ffi::XK_R6 => VirtualKeyCode::R6, +// //ffi::XK_F27 => VirtualKeyCode::F27, +// //ffi::XK_R7 => VirtualKeyCode::R7, +// //ffi::XK_F28 => VirtualKeyCode::F28, +// //ffi::XK_R8 => VirtualKeyCode::R8, +// //ffi::XK_F29 => VirtualKeyCode::F29, +// //ffi::XK_R9 => VirtualKeyCode::R9, +// //ffi::XK_F30 => VirtualKeyCode::F30, +// //ffi::XK_R10 => VirtualKeyCode::R10, +// //ffi::XK_F31 => VirtualKeyCode::F31, +// //ffi::XK_R11 => VirtualKeyCode::R11, +// //ffi::XK_F32 => VirtualKeyCode::F32, +// //ffi::XK_R12 => VirtualKeyCode::R12, +// //ffi::XK_F33 => VirtualKeyCode::F33, +// //ffi::XK_R13 => VirtualKeyCode::R13, +// //ffi::XK_F34 => VirtualKeyCode::F34, +// //ffi::XK_R14 => VirtualKeyCode::R14, +// //ffi::XK_F35 => VirtualKeyCode::F35, +// //ffi::XK_R15 => VirtualKeyCode::R15, +// ffi::XK_Shift_L => VirtualKeyCode::LShift, +// ffi::XK_Shift_R => VirtualKeyCode::RShift, +// ffi::XK_Control_L => VirtualKeyCode::LControl, +// ffi::XK_Control_R => VirtualKeyCode::RControl, +// //ffi::XK_Caps_Lock => VirtualKeyCode::Caps_lock, +// //ffi::XK_Shift_Lock => VirtualKeyCode::Shift_lock, +// //ffi::XK_Meta_L => VirtualKeyCode::Meta_l, +// //ffi::XK_Meta_R => VirtualKeyCode::Meta_r, +// ffi::XK_Alt_L => VirtualKeyCode::LAlt, +// ffi::XK_Alt_R => VirtualKeyCode::RAlt, +// //ffi::XK_Super_L => VirtualKeyCode::Super_l, +// //ffi::XK_Super_R => VirtualKeyCode::Super_r, +// //ffi::XK_Hyper_L => VirtualKeyCode::Hyper_l, +// //ffi::XK_Hyper_R => VirtualKeyCode::Hyper_r, +// ffi::XK_ISO_Left_Tab => VirtualKeyCode::Tab, +// ffi::XK_space => VirtualKeyCode::Space, +// //ffi::XK_exclam => VirtualKeyCode::Exclam, +// //ffi::XK_quotedbl => VirtualKeyCode::Quotedbl, +// //ffi::XK_numbersign => VirtualKeyCode::Numbersign, +// //ffi::XK_dollar => VirtualKeyCode::Dollar, +// //ffi::XK_percent => VirtualKeyCode::Percent, +// //ffi::XK_ampersand => VirtualKeyCode::Ampersand, +// ffi::XK_apostrophe => VirtualKeyCode::Apostrophe, +// //ffi::XK_quoteright => VirtualKeyCode::Quoteright, +// //ffi::XK_parenleft => VirtualKeyCode::Parenleft, +// //ffi::XK_parenright => VirtualKeyCode::Parenright, +// ffi::XK_asterisk => VirtualKeyCode::Asterisk, +// ffi::XK_plus => VirtualKeyCode::Plus, +// ffi::XK_comma => VirtualKeyCode::Comma, +// ffi::XK_minus => VirtualKeyCode::Minus, +// ffi::XK_period => VirtualKeyCode::Period, +// ffi::XK_slash => VirtualKeyCode::Slash, +// ffi::XK_0 => VirtualKeyCode::Key0, +// ffi::XK_1 => VirtualKeyCode::Key1, +// ffi::XK_2 => VirtualKeyCode::Key2, +// ffi::XK_3 => VirtualKeyCode::Key3, +// ffi::XK_4 => VirtualKeyCode::Key4, +// ffi::XK_5 => VirtualKeyCode::Key5, +// ffi::XK_6 => VirtualKeyCode::Key6, +// ffi::XK_7 => VirtualKeyCode::Key7, +// ffi::XK_8 => VirtualKeyCode::Key8, +// ffi::XK_9 => VirtualKeyCode::Key9, +// ffi::XK_colon => VirtualKeyCode::Colon, +// ffi::XK_semicolon => VirtualKeyCode::Semicolon, +// //ffi::XK_less => VirtualKeyCode::Less, +// ffi::XK_equal => VirtualKeyCode::Equals, +// //ffi::XK_greater => VirtualKeyCode::Greater, +// //ffi::XK_question => VirtualKeyCode::Question, +// ffi::XK_at => VirtualKeyCode::At, +// ffi::XK_A => VirtualKeyCode::A, +// ffi::XK_B => VirtualKeyCode::B, +// ffi::XK_C => VirtualKeyCode::C, +// ffi::XK_D => VirtualKeyCode::D, +// ffi::XK_E => VirtualKeyCode::E, +// ffi::XK_F => VirtualKeyCode::F, +// ffi::XK_G => VirtualKeyCode::G, +// ffi::XK_H => VirtualKeyCode::H, +// ffi::XK_I => VirtualKeyCode::I, +// ffi::XK_J => VirtualKeyCode::J, +// ffi::XK_K => VirtualKeyCode::K, +// ffi::XK_L => VirtualKeyCode::L, +// ffi::XK_M => VirtualKeyCode::M, +// ffi::XK_N => VirtualKeyCode::N, +// ffi::XK_O => VirtualKeyCode::O, +// ffi::XK_P => VirtualKeyCode::P, +// ffi::XK_Q => VirtualKeyCode::Q, +// ffi::XK_R => VirtualKeyCode::R, +// ffi::XK_S => VirtualKeyCode::S, +// ffi::XK_T => VirtualKeyCode::T, +// ffi::XK_U => VirtualKeyCode::U, +// ffi::XK_V => VirtualKeyCode::V, +// ffi::XK_W => VirtualKeyCode::W, +// ffi::XK_X => VirtualKeyCode::X, +// ffi::XK_Y => VirtualKeyCode::Y, +// ffi::XK_Z => VirtualKeyCode::Z, +// ffi::XK_bracketleft => VirtualKeyCode::LBracket, +// ffi::XK_backslash => VirtualKeyCode::Backslash, +// ffi::XK_bracketright => VirtualKeyCode::RBracket, +// //ffi::XK_asciicircum => VirtualKeyCode::Asciicircum, +// //ffi::XK_underscore => VirtualKeyCode::Underscore, +// ffi::XK_grave => VirtualKeyCode::Grave, +// //ffi::XK_quoteleft => VirtualKeyCode::Quoteleft, +// ffi::XK_a => VirtualKeyCode::A, +// ffi::XK_b => VirtualKeyCode::B, +// ffi::XK_c => VirtualKeyCode::C, +// ffi::XK_d => VirtualKeyCode::D, +// ffi::XK_e => VirtualKeyCode::E, +// ffi::XK_f => VirtualKeyCode::F, +// ffi::XK_g => VirtualKeyCode::G, +// ffi::XK_h => VirtualKeyCode::H, +// ffi::XK_i => VirtualKeyCode::I, +// ffi::XK_j => VirtualKeyCode::J, +// ffi::XK_k => VirtualKeyCode::K, +// ffi::XK_l => VirtualKeyCode::L, +// ffi::XK_m => VirtualKeyCode::M, +// ffi::XK_n => VirtualKeyCode::N, +// ffi::XK_o => VirtualKeyCode::O, +// ffi::XK_p => VirtualKeyCode::P, +// ffi::XK_q => VirtualKeyCode::Q, +// ffi::XK_r => VirtualKeyCode::R, +// ffi::XK_s => VirtualKeyCode::S, +// ffi::XK_t => VirtualKeyCode::T, +// ffi::XK_u => VirtualKeyCode::U, +// ffi::XK_v => VirtualKeyCode::V, +// ffi::XK_w => VirtualKeyCode::W, +// ffi::XK_x => VirtualKeyCode::X, +// ffi::XK_y => VirtualKeyCode::Y, +// ffi::XK_z => VirtualKeyCode::Z, +// //ffi::XK_braceleft => VirtualKeyCode::Braceleft, +// //ffi::XK_bar => VirtualKeyCode::Bar, +// //ffi::XK_braceright => VirtualKeyCode::Braceright, +// //ffi::XK_asciitilde => VirtualKeyCode::Asciitilde, +// //ffi::XK_nobreakspace => VirtualKeyCode::Nobreakspace, +// //ffi::XK_exclamdown => VirtualKeyCode::Exclamdown, +// //ffi::XK_cent => VirtualKeyCode::Cent, +// //ffi::XK_sterling => VirtualKeyCode::Sterling, +// //ffi::XK_currency => VirtualKeyCode::Currency, +// //ffi::XK_yen => VirtualKeyCode::Yen, +// //ffi::XK_brokenbar => VirtualKeyCode::Brokenbar, +// //ffi::XK_section => VirtualKeyCode::Section, +// //ffi::XK_diaeresis => VirtualKeyCode::Diaeresis, +// //ffi::XK_copyright => VirtualKeyCode::Copyright, +// //ffi::XK_ordfeminine => VirtualKeyCode::Ordfeminine, +// //ffi::XK_guillemotleft => VirtualKeyCode::Guillemotleft, +// //ffi::XK_notsign => VirtualKeyCode::Notsign, +// //ffi::XK_hyphen => VirtualKeyCode::Hyphen, +// //ffi::XK_registered => VirtualKeyCode::Registered, +// //ffi::XK_macron => VirtualKeyCode::Macron, +// //ffi::XK_degree => VirtualKeyCode::Degree, +// //ffi::XK_plusminus => VirtualKeyCode::Plusminus, +// //ffi::XK_twosuperior => VirtualKeyCode::Twosuperior, +// //ffi::XK_threesuperior => VirtualKeyCode::Threesuperior, +// //ffi::XK_acute => VirtualKeyCode::Acute, +// //ffi::XK_mu => VirtualKeyCode::Mu, +// //ffi::XK_paragraph => VirtualKeyCode::Paragraph, +// //ffi::XK_periodcentered => VirtualKeyCode::Periodcentered, +// //ffi::XK_cedilla => VirtualKeyCode::Cedilla, +// //ffi::XK_onesuperior => VirtualKeyCode::Onesuperior, +// //ffi::XK_masculine => VirtualKeyCode::Masculine, +// //ffi::XK_guillemotright => VirtualKeyCode::Guillemotright, +// //ffi::XK_onequarter => VirtualKeyCode::Onequarter, +// //ffi::XK_onehalf => VirtualKeyCode::Onehalf, +// //ffi::XK_threequarters => VirtualKeyCode::Threequarters, +// //ffi::XK_questiondown => VirtualKeyCode::Questiondown, +// //ffi::XK_Agrave => VirtualKeyCode::Agrave, +// //ffi::XK_Aacute => VirtualKeyCode::Aacute, +// //ffi::XK_Acircumflex => VirtualKeyCode::Acircumflex, +// //ffi::XK_Atilde => VirtualKeyCode::Atilde, +// //ffi::XK_Adiaeresis => VirtualKeyCode::Adiaeresis, +// //ffi::XK_Aring => VirtualKeyCode::Aring, +// //ffi::XK_AE => VirtualKeyCode::Ae, +// //ffi::XK_Ccedilla => VirtualKeyCode::Ccedilla, +// //ffi::XK_Egrave => VirtualKeyCode::Egrave, +// //ffi::XK_Eacute => VirtualKeyCode::Eacute, +// //ffi::XK_Ecircumflex => VirtualKeyCode::Ecircumflex, +// //ffi::XK_Ediaeresis => VirtualKeyCode::Ediaeresis, +// //ffi::XK_Igrave => VirtualKeyCode::Igrave, +// //ffi::XK_Iacute => VirtualKeyCode::Iacute, +// //ffi::XK_Icircumflex => VirtualKeyCode::Icircumflex, +// //ffi::XK_Idiaeresis => VirtualKeyCode::Idiaeresis, +// //ffi::XK_ETH => VirtualKeyCode::Eth, +// //ffi::XK_Eth => VirtualKeyCode::Eth, +// //ffi::XK_Ntilde => VirtualKeyCode::Ntilde, +// //ffi::XK_Ograve => VirtualKeyCode::Ograve, +// //ffi::XK_Oacute => VirtualKeyCode::Oacute, +// //ffi::XK_Ocircumflex => VirtualKeyCode::Ocircumflex, +// //ffi::XK_Otilde => VirtualKeyCode::Otilde, +// //ffi::XK_Odiaeresis => VirtualKeyCode::Odiaeresis, +// //ffi::XK_multiply => VirtualKeyCode::Multiply, +// //ffi::XK_Ooblique => VirtualKeyCode::Ooblique, +// //ffi::XK_Ugrave => VirtualKeyCode::Ugrave, +// //ffi::XK_Uacute => VirtualKeyCode::Uacute, +// //ffi::XK_Ucircumflex => VirtualKeyCode::Ucircumflex, +// //ffi::XK_Udiaeresis => VirtualKeyCode::Udiaeresis, +// //ffi::XK_Yacute => VirtualKeyCode::Yacute, +// //ffi::XK_THORN => VirtualKeyCode::Thorn, +// //ffi::XK_Thorn => VirtualKeyCode::Thorn, +// //ffi::XK_ssharp => VirtualKeyCode::Ssharp, +// //ffi::XK_agrave => VirtualKeyCode::Agrave, +// //ffi::XK_aacute => VirtualKeyCode::Aacute, +// //ffi::XK_acircumflex => VirtualKeyCode::Acircumflex, +// //ffi::XK_atilde => VirtualKeyCode::Atilde, +// //ffi::XK_adiaeresis => VirtualKeyCode::Adiaeresis, +// //ffi::XK_aring => VirtualKeyCode::Aring, +// //ffi::XK_ae => VirtualKeyCode::Ae, +// //ffi::XK_ccedilla => VirtualKeyCode::Ccedilla, +// //ffi::XK_egrave => VirtualKeyCode::Egrave, +// //ffi::XK_eacute => VirtualKeyCode::Eacute, +// //ffi::XK_ecircumflex => VirtualKeyCode::Ecircumflex, +// //ffi::XK_ediaeresis => VirtualKeyCode::Ediaeresis, +// //ffi::XK_igrave => VirtualKeyCode::Igrave, +// //ffi::XK_iacute => VirtualKeyCode::Iacute, +// //ffi::XK_icircumflex => VirtualKeyCode::Icircumflex, +// //ffi::XK_idiaeresis => VirtualKeyCode::Idiaeresis, +// //ffi::XK_eth => VirtualKeyCode::Eth, +// //ffi::XK_ntilde => VirtualKeyCode::Ntilde, +// //ffi::XK_ograve => VirtualKeyCode::Ograve, +// //ffi::XK_oacute => VirtualKeyCode::Oacute, +// //ffi::XK_ocircumflex => VirtualKeyCode::Ocircumflex, +// //ffi::XK_otilde => VirtualKeyCode::Otilde, +// //ffi::XK_odiaeresis => VirtualKeyCode::Odiaeresis, +// //ffi::XK_division => VirtualKeyCode::Division, +// //ffi::XK_oslash => VirtualKeyCode::Oslash, +// //ffi::XK_ugrave => VirtualKeyCode::Ugrave, +// //ffi::XK_uacute => VirtualKeyCode::Uacute, +// //ffi::XK_ucircumflex => VirtualKeyCode::Ucircumflex, +// //ffi::XK_udiaeresis => VirtualKeyCode::Udiaeresis, +// //ffi::XK_yacute => VirtualKeyCode::Yacute, +// //ffi::XK_thorn => VirtualKeyCode::Thorn, +// //ffi::XK_ydiaeresis => VirtualKeyCode::Ydiaeresis, +// //ffi::XK_Aogonek => VirtualKeyCode::Aogonek, +// //ffi::XK_breve => VirtualKeyCode::Breve, +// //ffi::XK_Lstroke => VirtualKeyCode::Lstroke, +// //ffi::XK_Lcaron => VirtualKeyCode::Lcaron, +// //ffi::XK_Sacute => VirtualKeyCode::Sacute, +// //ffi::XK_Scaron => VirtualKeyCode::Scaron, +// //ffi::XK_Scedilla => VirtualKeyCode::Scedilla, +// //ffi::XK_Tcaron => VirtualKeyCode::Tcaron, +// //ffi::XK_Zacute => VirtualKeyCode::Zacute, +// //ffi::XK_Zcaron => VirtualKeyCode::Zcaron, +// //ffi::XK_Zabovedot => VirtualKeyCode::Zabovedot, +// //ffi::XK_aogonek => VirtualKeyCode::Aogonek, +// //ffi::XK_ogonek => VirtualKeyCode::Ogonek, +// //ffi::XK_lstroke => VirtualKeyCode::Lstroke, +// //ffi::XK_lcaron => VirtualKeyCode::Lcaron, +// //ffi::XK_sacute => VirtualKeyCode::Sacute, +// //ffi::XK_caron => VirtualKeyCode::Caron, +// //ffi::XK_scaron => VirtualKeyCode::Scaron, +// //ffi::XK_scedilla => VirtualKeyCode::Scedilla, +// //ffi::XK_tcaron => VirtualKeyCode::Tcaron, +// //ffi::XK_zacute => VirtualKeyCode::Zacute, +// //ffi::XK_doubleacute => VirtualKeyCode::Doubleacute, +// //ffi::XK_zcaron => VirtualKeyCode::Zcaron, +// //ffi::XK_zabovedot => VirtualKeyCode::Zabovedot, +// //ffi::XK_Racute => VirtualKeyCode::Racute, +// //ffi::XK_Abreve => VirtualKeyCode::Abreve, +// //ffi::XK_Lacute => VirtualKeyCode::Lacute, +// //ffi::XK_Cacute => VirtualKeyCode::Cacute, +// //ffi::XK_Ccaron => VirtualKeyCode::Ccaron, +// //ffi::XK_Eogonek => VirtualKeyCode::Eogonek, +// //ffi::XK_Ecaron => VirtualKeyCode::Ecaron, +// //ffi::XK_Dcaron => VirtualKeyCode::Dcaron, +// //ffi::XK_Dstroke => VirtualKeyCode::Dstroke, +// //ffi::XK_Nacute => VirtualKeyCode::Nacute, +// //ffi::XK_Ncaron => VirtualKeyCode::Ncaron, +// //ffi::XK_Odoubleacute => VirtualKeyCode::Odoubleacute, +// //ffi::XK_Rcaron => VirtualKeyCode::Rcaron, +// //ffi::XK_Uring => VirtualKeyCode::Uring, +// //ffi::XK_Udoubleacute => VirtualKeyCode::Udoubleacute, +// //ffi::XK_Tcedilla => VirtualKeyCode::Tcedilla, +// //ffi::XK_racute => VirtualKeyCode::Racute, +// //ffi::XK_abreve => VirtualKeyCode::Abreve, +// //ffi::XK_lacute => VirtualKeyCode::Lacute, +// //ffi::XK_cacute => VirtualKeyCode::Cacute, +// //ffi::XK_ccaron => VirtualKeyCode::Ccaron, +// //ffi::XK_eogonek => VirtualKeyCode::Eogonek, +// //ffi::XK_ecaron => VirtualKeyCode::Ecaron, +// //ffi::XK_dcaron => VirtualKeyCode::Dcaron, +// //ffi::XK_dstroke => VirtualKeyCode::Dstroke, +// //ffi::XK_nacute => VirtualKeyCode::Nacute, +// //ffi::XK_ncaron => VirtualKeyCode::Ncaron, +// //ffi::XK_odoubleacute => VirtualKeyCode::Odoubleacute, +// //ffi::XK_udoubleacute => VirtualKeyCode::Udoubleacute, +// //ffi::XK_rcaron => VirtualKeyCode::Rcaron, +// //ffi::XK_uring => VirtualKeyCode::Uring, +// //ffi::XK_tcedilla => VirtualKeyCode::Tcedilla, +// //ffi::XK_abovedot => VirtualKeyCode::Abovedot, +// //ffi::XK_Hstroke => VirtualKeyCode::Hstroke, +// //ffi::XK_Hcircumflex => VirtualKeyCode::Hcircumflex, +// //ffi::XK_Iabovedot => VirtualKeyCode::Iabovedot, +// //ffi::XK_Gbreve => VirtualKeyCode::Gbreve, +// //ffi::XK_Jcircumflex => VirtualKeyCode::Jcircumflex, +// //ffi::XK_hstroke => VirtualKeyCode::Hstroke, +// //ffi::XK_hcircumflex => VirtualKeyCode::Hcircumflex, +// //ffi::XK_idotless => VirtualKeyCode::Idotless, +// //ffi::XK_gbreve => VirtualKeyCode::Gbreve, +// //ffi::XK_jcircumflex => VirtualKeyCode::Jcircumflex, +// //ffi::XK_Cabovedot => VirtualKeyCode::Cabovedot, +// //ffi::XK_Ccircumflex => VirtualKeyCode::Ccircumflex, +// //ffi::XK_Gabovedot => VirtualKeyCode::Gabovedot, +// //ffi::XK_Gcircumflex => VirtualKeyCode::Gcircumflex, +// //ffi::XK_Ubreve => VirtualKeyCode::Ubreve, +// //ffi::XK_Scircumflex => VirtualKeyCode::Scircumflex, +// //ffi::XK_cabovedot => VirtualKeyCode::Cabovedot, +// //ffi::XK_ccircumflex => VirtualKeyCode::Ccircumflex, +// //ffi::XK_gabovedot => VirtualKeyCode::Gabovedot, +// //ffi::XK_gcircumflex => VirtualKeyCode::Gcircumflex, +// //ffi::XK_ubreve => VirtualKeyCode::Ubreve, +// //ffi::XK_scircumflex => VirtualKeyCode::Scircumflex, +// //ffi::XK_kra => VirtualKeyCode::Kra, +// //ffi::XK_kappa => VirtualKeyCode::Kappa, +// //ffi::XK_Rcedilla => VirtualKeyCode::Rcedilla, +// //ffi::XK_Itilde => VirtualKeyCode::Itilde, +// //ffi::XK_Lcedilla => VirtualKeyCode::Lcedilla, +// //ffi::XK_Emacron => VirtualKeyCode::Emacron, +// //ffi::XK_Gcedilla => VirtualKeyCode::Gcedilla, +// //ffi::XK_Tslash => VirtualKeyCode::Tslash, +// //ffi::XK_rcedilla => VirtualKeyCode::Rcedilla, +// //ffi::XK_itilde => VirtualKeyCode::Itilde, +// //ffi::XK_lcedilla => VirtualKeyCode::Lcedilla, +// //ffi::XK_emacron => VirtualKeyCode::Emacron, +// //ffi::XK_gcedilla => VirtualKeyCode::Gcedilla, +// //ffi::XK_tslash => VirtualKeyCode::Tslash, +// //ffi::XK_ENG => VirtualKeyCode::Eng, +// //ffi::XK_eng => VirtualKeyCode::Eng, +// //ffi::XK_Amacron => VirtualKeyCode::Amacron, +// //ffi::XK_Iogonek => VirtualKeyCode::Iogonek, +// //ffi::XK_Eabovedot => VirtualKeyCode::Eabovedot, +// //ffi::XK_Imacron => VirtualKeyCode::Imacron, +// //ffi::XK_Ncedilla => VirtualKeyCode::Ncedilla, +// //ffi::XK_Omacron => VirtualKeyCode::Omacron, +// //ffi::XK_Kcedilla => VirtualKeyCode::Kcedilla, +// //ffi::XK_Uogonek => VirtualKeyCode::Uogonek, +// //ffi::XK_Utilde => VirtualKeyCode::Utilde, +// //ffi::XK_Umacron => VirtualKeyCode::Umacron, +// //ffi::XK_amacron => VirtualKeyCode::Amacron, +// //ffi::XK_iogonek => VirtualKeyCode::Iogonek, +// //ffi::XK_eabovedot => VirtualKeyCode::Eabovedot, +// //ffi::XK_imacron => VirtualKeyCode::Imacron, +// //ffi::XK_ncedilla => VirtualKeyCode::Ncedilla, +// //ffi::XK_omacron => VirtualKeyCode::Omacron, +// //ffi::XK_kcedilla => VirtualKeyCode::Kcedilla, +// //ffi::XK_uogonek => VirtualKeyCode::Uogonek, +// //ffi::XK_utilde => VirtualKeyCode::Utilde, +// //ffi::XK_umacron => VirtualKeyCode::Umacron, +// //ffi::XK_overline => VirtualKeyCode::Overline, +// //ffi::XK_kana_fullstop => VirtualKeyCode::Kana_fullstop, +// //ffi::XK_kana_openingbracket => VirtualKeyCode::Kana_openingbracket, +// //ffi::XK_kana_closingbracket => VirtualKeyCode::Kana_closingbracket, +// //ffi::XK_kana_comma => VirtualKeyCode::Kana_comma, +// //ffi::XK_kana_conjunctive => VirtualKeyCode::Kana_conjunctive, +// //ffi::XK_kana_middledot => VirtualKeyCode::Kana_middledot, +// //ffi::XK_kana_WO => VirtualKeyCode::Kana_wo, +// //ffi::XK_kana_a => VirtualKeyCode::Kana_a, +// //ffi::XK_kana_i => VirtualKeyCode::Kana_i, +// //ffi::XK_kana_u => VirtualKeyCode::Kana_u, +// //ffi::XK_kana_e => VirtualKeyCode::Kana_e, +// //ffi::XK_kana_o => VirtualKeyCode::Kana_o, +// //ffi::XK_kana_ya => VirtualKeyCode::Kana_ya, +// //ffi::XK_kana_yu => VirtualKeyCode::Kana_yu, +// //ffi::XK_kana_yo => VirtualKeyCode::Kana_yo, +// //ffi::XK_kana_tsu => VirtualKeyCode::Kana_tsu, +// //ffi::XK_kana_tu => VirtualKeyCode::Kana_tu, +// //ffi::XK_prolongedsound => VirtualKeyCode::Prolongedsound, +// //ffi::XK_kana_A => VirtualKeyCode::Kana_a, +// //ffi::XK_kana_I => VirtualKeyCode::Kana_i, +// //ffi::XK_kana_U => VirtualKeyCode::Kana_u, +// //ffi::XK_kana_E => VirtualKeyCode::Kana_e, +// //ffi::XK_kana_O => VirtualKeyCode::Kana_o, +// //ffi::XK_kana_KA => VirtualKeyCode::Kana_ka, +// //ffi::XK_kana_KI => VirtualKeyCode::Kana_ki, +// //ffi::XK_kana_KU => VirtualKeyCode::Kana_ku, +// //ffi::XK_kana_KE => VirtualKeyCode::Kana_ke, +// //ffi::XK_kana_KO => VirtualKeyCode::Kana_ko, +// //ffi::XK_kana_SA => VirtualKeyCode::Kana_sa, +// //ffi::XK_kana_SHI => VirtualKeyCode::Kana_shi, +// //ffi::XK_kana_SU => VirtualKeyCode::Kana_su, +// //ffi::XK_kana_SE => VirtualKeyCode::Kana_se, +// //ffi::XK_kana_SO => VirtualKeyCode::Kana_so, +// //ffi::XK_kana_TA => VirtualKeyCode::Kana_ta, +// //ffi::XK_kana_CHI => VirtualKeyCode::Kana_chi, +// //ffi::XK_kana_TI => VirtualKeyCode::Kana_ti, +// //ffi::XK_kana_TSU => VirtualKeyCode::Kana_tsu, +// //ffi::XK_kana_TU => VirtualKeyCode::Kana_tu, +// //ffi::XK_kana_TE => VirtualKeyCode::Kana_te, +// //ffi::XK_kana_TO => VirtualKeyCode::Kana_to, +// //ffi::XK_kana_NA => VirtualKeyCode::Kana_na, +// //ffi::XK_kana_NI => VirtualKeyCode::Kana_ni, +// //ffi::XK_kana_NU => VirtualKeyCode::Kana_nu, +// //ffi::XK_kana_NE => VirtualKeyCode::Kana_ne, +// //ffi::XK_kana_NO => VirtualKeyCode::Kana_no, +// //ffi::XK_kana_HA => VirtualKeyCode::Kana_ha, +// //ffi::XK_kana_HI => VirtualKeyCode::Kana_hi, +// //ffi::XK_kana_FU => VirtualKeyCode::Kana_fu, +// //ffi::XK_kana_HU => VirtualKeyCode::Kana_hu, +// //ffi::XK_kana_HE => VirtualKeyCode::Kana_he, +// //ffi::XK_kana_HO => VirtualKeyCode::Kana_ho, +// //ffi::XK_kana_MA => VirtualKeyCode::Kana_ma, +// //ffi::XK_kana_MI => VirtualKeyCode::Kana_mi, +// //ffi::XK_kana_MU => VirtualKeyCode::Kana_mu, +// //ffi::XK_kana_ME => VirtualKeyCode::Kana_me, +// //ffi::XK_kana_MO => VirtualKeyCode::Kana_mo, +// //ffi::XK_kana_YA => VirtualKeyCode::Kana_ya, +// //ffi::XK_kana_YU => VirtualKeyCode::Kana_yu, +// //ffi::XK_kana_YO => VirtualKeyCode::Kana_yo, +// //ffi::XK_kana_RA => VirtualKeyCode::Kana_ra, +// //ffi::XK_kana_RI => VirtualKeyCode::Kana_ri, +// //ffi::XK_kana_RU => VirtualKeyCode::Kana_ru, +// //ffi::XK_kana_RE => VirtualKeyCode::Kana_re, +// //ffi::XK_kana_RO => VirtualKeyCode::Kana_ro, +// //ffi::XK_kana_WA => VirtualKeyCode::Kana_wa, +// //ffi::XK_kana_N => VirtualKeyCode::Kana_n, +// //ffi::XK_voicedsound => VirtualKeyCode::Voicedsound, +// //ffi::XK_semivoicedsound => VirtualKeyCode::Semivoicedsound, +// //ffi::XK_kana_switch => VirtualKeyCode::Kana_switch, +// //ffi::XK_Arabic_comma => VirtualKeyCode::Arabic_comma, +// //ffi::XK_Arabic_semicolon => VirtualKeyCode::Arabic_semicolon, +// //ffi::XK_Arabic_question_mark => VirtualKeyCode::Arabic_question_mark, +// //ffi::XK_Arabic_hamza => VirtualKeyCode::Arabic_hamza, +// //ffi::XK_Arabic_maddaonalef => VirtualKeyCode::Arabic_maddaonalef, +// //ffi::XK_Arabic_hamzaonalef => VirtualKeyCode::Arabic_hamzaonalef, +// //ffi::XK_Arabic_hamzaonwaw => VirtualKeyCode::Arabic_hamzaonwaw, +// //ffi::XK_Arabic_hamzaunderalef => VirtualKeyCode::Arabic_hamzaunderalef, +// //ffi::XK_Arabic_hamzaonyeh => VirtualKeyCode::Arabic_hamzaonyeh, +// //ffi::XK_Arabic_alef => VirtualKeyCode::Arabic_alef, +// //ffi::XK_Arabic_beh => VirtualKeyCode::Arabic_beh, +// //ffi::XK_Arabic_tehmarbuta => VirtualKeyCode::Arabic_tehmarbuta, +// //ffi::XK_Arabic_teh => VirtualKeyCode::Arabic_teh, +// //ffi::XK_Arabic_theh => VirtualKeyCode::Arabic_theh, +// //ffi::XK_Arabic_jeem => VirtualKeyCode::Arabic_jeem, +// //ffi::XK_Arabic_hah => VirtualKeyCode::Arabic_hah, +// //ffi::XK_Arabic_khah => VirtualKeyCode::Arabic_khah, +// //ffi::XK_Arabic_dal => VirtualKeyCode::Arabic_dal, +// //ffi::XK_Arabic_thal => VirtualKeyCode::Arabic_thal, +// //ffi::XK_Arabic_ra => VirtualKeyCode::Arabic_ra, +// //ffi::XK_Arabic_zain => VirtualKeyCode::Arabic_zain, +// //ffi::XK_Arabic_seen => VirtualKeyCode::Arabic_seen, +// //ffi::XK_Arabic_sheen => VirtualKeyCode::Arabic_sheen, +// //ffi::XK_Arabic_sad => VirtualKeyCode::Arabic_sad, +// //ffi::XK_Arabic_dad => VirtualKeyCode::Arabic_dad, +// //ffi::XK_Arabic_tah => VirtualKeyCode::Arabic_tah, +// //ffi::XK_Arabic_zah => VirtualKeyCode::Arabic_zah, +// //ffi::XK_Arabic_ain => VirtualKeyCode::Arabic_ain, +// //ffi::XK_Arabic_ghain => VirtualKeyCode::Arabic_ghain, +// //ffi::XK_Arabic_tatweel => VirtualKeyCode::Arabic_tatweel, +// //ffi::XK_Arabic_feh => VirtualKeyCode::Arabic_feh, +// //ffi::XK_Arabic_qaf => VirtualKeyCode::Arabic_qaf, +// //ffi::XK_Arabic_kaf => VirtualKeyCode::Arabic_kaf, +// //ffi::XK_Arabic_lam => VirtualKeyCode::Arabic_lam, +// //ffi::XK_Arabic_meem => VirtualKeyCode::Arabic_meem, +// //ffi::XK_Arabic_noon => VirtualKeyCode::Arabic_noon, +// //ffi::XK_Arabic_ha => VirtualKeyCode::Arabic_ha, +// //ffi::XK_Arabic_heh => VirtualKeyCode::Arabic_heh, +// //ffi::XK_Arabic_waw => VirtualKeyCode::Arabic_waw, +// //ffi::XK_Arabic_alefmaksura => VirtualKeyCode::Arabic_alefmaksura, +// //ffi::XK_Arabic_yeh => VirtualKeyCode::Arabic_yeh, +// //ffi::XK_Arabic_fathatan => VirtualKeyCode::Arabic_fathatan, +// //ffi::XK_Arabic_dammatan => VirtualKeyCode::Arabic_dammatan, +// //ffi::XK_Arabic_kasratan => VirtualKeyCode::Arabic_kasratan, +// //ffi::XK_Arabic_fatha => VirtualKeyCode::Arabic_fatha, +// //ffi::XK_Arabic_damma => VirtualKeyCode::Arabic_damma, +// //ffi::XK_Arabic_kasra => VirtualKeyCode::Arabic_kasra, +// //ffi::XK_Arabic_shadda => VirtualKeyCode::Arabic_shadda, +// //ffi::XK_Arabic_sukun => VirtualKeyCode::Arabic_sukun, +// //ffi::XK_Arabic_switch => VirtualKeyCode::Arabic_switch, +// //ffi::XK_Serbian_dje => VirtualKeyCode::Serbian_dje, +// //ffi::XK_Macedonia_gje => VirtualKeyCode::Macedonia_gje, +// //ffi::XK_Cyrillic_io => VirtualKeyCode::Cyrillic_io, +// //ffi::XK_Ukrainian_ie => VirtualKeyCode::Ukrainian_ie, +// //ffi::XK_Ukranian_je => VirtualKeyCode::Ukranian_je, +// //ffi::XK_Macedonia_dse => VirtualKeyCode::Macedonia_dse, +// //ffi::XK_Ukrainian_i => VirtualKeyCode::Ukrainian_i, +// //ffi::XK_Ukranian_i => VirtualKeyCode::Ukranian_i, +// //ffi::XK_Ukrainian_yi => VirtualKeyCode::Ukrainian_yi, +// //ffi::XK_Ukranian_yi => VirtualKeyCode::Ukranian_yi, +// //ffi::XK_Cyrillic_je => VirtualKeyCode::Cyrillic_je, +// //ffi::XK_Serbian_je => VirtualKeyCode::Serbian_je, +// //ffi::XK_Cyrillic_lje => VirtualKeyCode::Cyrillic_lje, +// //ffi::XK_Serbian_lje => VirtualKeyCode::Serbian_lje, +// //ffi::XK_Cyrillic_nje => VirtualKeyCode::Cyrillic_nje, +// //ffi::XK_Serbian_nje => VirtualKeyCode::Serbian_nje, +// //ffi::XK_Serbian_tshe => VirtualKeyCode::Serbian_tshe, +// //ffi::XK_Macedonia_kje => VirtualKeyCode::Macedonia_kje, +// //ffi::XK_Byelorussian_shortu => VirtualKeyCode::Byelorussian_shortu, +// //ffi::XK_Cyrillic_dzhe => VirtualKeyCode::Cyrillic_dzhe, +// //ffi::XK_Serbian_dze => VirtualKeyCode::Serbian_dze, +// //ffi::XK_numerosign => VirtualKeyCode::Numerosign, +// //ffi::XK_Serbian_DJE => VirtualKeyCode::Serbian_dje, +// //ffi::XK_Macedonia_GJE => VirtualKeyCode::Macedonia_gje, +// //ffi::XK_Cyrillic_IO => VirtualKeyCode::Cyrillic_io, +// //ffi::XK_Ukrainian_IE => VirtualKeyCode::Ukrainian_ie, +// //ffi::XK_Ukranian_JE => VirtualKeyCode::Ukranian_je, +// //ffi::XK_Macedonia_DSE => VirtualKeyCode::Macedonia_dse, +// //ffi::XK_Ukrainian_I => VirtualKeyCode::Ukrainian_i, +// //ffi::XK_Ukranian_I => VirtualKeyCode::Ukranian_i, +// //ffi::XK_Ukrainian_YI => VirtualKeyCode::Ukrainian_yi, +// //ffi::XK_Ukranian_YI => VirtualKeyCode::Ukranian_yi, +// //ffi::XK_Cyrillic_JE => VirtualKeyCode::Cyrillic_je, +// //ffi::XK_Serbian_JE => VirtualKeyCode::Serbian_je, +// //ffi::XK_Cyrillic_LJE => VirtualKeyCode::Cyrillic_lje, +// //ffi::XK_Serbian_LJE => VirtualKeyCode::Serbian_lje, +// //ffi::XK_Cyrillic_NJE => VirtualKeyCode::Cyrillic_nje, +// //ffi::XK_Serbian_NJE => VirtualKeyCode::Serbian_nje, +// //ffi::XK_Serbian_TSHE => VirtualKeyCode::Serbian_tshe, +// //ffi::XK_Macedonia_KJE => VirtualKeyCode::Macedonia_kje, +// //ffi::XK_Byelorussian_SHORTU => VirtualKeyCode::Byelorussian_shortu, +// //ffi::XK_Cyrillic_DZHE => VirtualKeyCode::Cyrillic_dzhe, +// //ffi::XK_Serbian_DZE => VirtualKeyCode::Serbian_dze, +// //ffi::XK_Cyrillic_yu => VirtualKeyCode::Cyrillic_yu, +// //ffi::XK_Cyrillic_a => VirtualKeyCode::Cyrillic_a, +// //ffi::XK_Cyrillic_be => VirtualKeyCode::Cyrillic_be, +// //ffi::XK_Cyrillic_tse => VirtualKeyCode::Cyrillic_tse, +// //ffi::XK_Cyrillic_de => VirtualKeyCode::Cyrillic_de, +// //ffi::XK_Cyrillic_ie => VirtualKeyCode::Cyrillic_ie, +// //ffi::XK_Cyrillic_ef => VirtualKeyCode::Cyrillic_ef, +// //ffi::XK_Cyrillic_ghe => VirtualKeyCode::Cyrillic_ghe, +// //ffi::XK_Cyrillic_ha => VirtualKeyCode::Cyrillic_ha, +// //ffi::XK_Cyrillic_i => VirtualKeyCode::Cyrillic_i, +// //ffi::XK_Cyrillic_shorti => VirtualKeyCode::Cyrillic_shorti, +// //ffi::XK_Cyrillic_ka => VirtualKeyCode::Cyrillic_ka, +// //ffi::XK_Cyrillic_el => VirtualKeyCode::Cyrillic_el, +// //ffi::XK_Cyrillic_em => VirtualKeyCode::Cyrillic_em, +// //ffi::XK_Cyrillic_en => VirtualKeyCode::Cyrillic_en, +// //ffi::XK_Cyrillic_o => VirtualKeyCode::Cyrillic_o, +// //ffi::XK_Cyrillic_pe => VirtualKeyCode::Cyrillic_pe, +// //ffi::XK_Cyrillic_ya => VirtualKeyCode::Cyrillic_ya, +// //ffi::XK_Cyrillic_er => VirtualKeyCode::Cyrillic_er, +// //ffi::XK_Cyrillic_es => VirtualKeyCode::Cyrillic_es, +// //ffi::XK_Cyrillic_te => VirtualKeyCode::Cyrillic_te, +// //ffi::XK_Cyrillic_u => VirtualKeyCode::Cyrillic_u, +// //ffi::XK_Cyrillic_zhe => VirtualKeyCode::Cyrillic_zhe, +// //ffi::XK_Cyrillic_ve => VirtualKeyCode::Cyrillic_ve, +// //ffi::XK_Cyrillic_softsign => VirtualKeyCode::Cyrillic_softsign, +// //ffi::XK_Cyrillic_yeru => VirtualKeyCode::Cyrillic_yeru, +// //ffi::XK_Cyrillic_ze => VirtualKeyCode::Cyrillic_ze, +// //ffi::XK_Cyrillic_sha => VirtualKeyCode::Cyrillic_sha, +// //ffi::XK_Cyrillic_e => VirtualKeyCode::Cyrillic_e, +// //ffi::XK_Cyrillic_shcha => VirtualKeyCode::Cyrillic_shcha, +// //ffi::XK_Cyrillic_che => VirtualKeyCode::Cyrillic_che, +// //ffi::XK_Cyrillic_hardsign => VirtualKeyCode::Cyrillic_hardsign, +// //ffi::XK_Cyrillic_YU => VirtualKeyCode::Cyrillic_yu, +// //ffi::XK_Cyrillic_A => VirtualKeyCode::Cyrillic_a, +// //ffi::XK_Cyrillic_BE => VirtualKeyCode::Cyrillic_be, +// //ffi::XK_Cyrillic_TSE => VirtualKeyCode::Cyrillic_tse, +// //ffi::XK_Cyrillic_DE => VirtualKeyCode::Cyrillic_de, +// //ffi::XK_Cyrillic_IE => VirtualKeyCode::Cyrillic_ie, +// //ffi::XK_Cyrillic_EF => VirtualKeyCode::Cyrillic_ef, +// //ffi::XK_Cyrillic_GHE => VirtualKeyCode::Cyrillic_ghe, +// //ffi::XK_Cyrillic_HA => VirtualKeyCode::Cyrillic_ha, +// //ffi::XK_Cyrillic_I => VirtualKeyCode::Cyrillic_i, +// //ffi::XK_Cyrillic_SHORTI => VirtualKeyCode::Cyrillic_shorti, +// //ffi::XK_Cyrillic_KA => VirtualKeyCode::Cyrillic_ka, +// //ffi::XK_Cyrillic_EL => VirtualKeyCode::Cyrillic_el, +// //ffi::XK_Cyrillic_EM => VirtualKeyCode::Cyrillic_em, +// //ffi::XK_Cyrillic_EN => VirtualKeyCode::Cyrillic_en, +// //ffi::XK_Cyrillic_O => VirtualKeyCode::Cyrillic_o, +// //ffi::XK_Cyrillic_PE => VirtualKeyCode::Cyrillic_pe, +// //ffi::XK_Cyrillic_YA => VirtualKeyCode::Cyrillic_ya, +// //ffi::XK_Cyrillic_ER => VirtualKeyCode::Cyrillic_er, +// //ffi::XK_Cyrillic_ES => VirtualKeyCode::Cyrillic_es, +// //ffi::XK_Cyrillic_TE => VirtualKeyCode::Cyrillic_te, +// //ffi::XK_Cyrillic_U => VirtualKeyCode::Cyrillic_u, +// //ffi::XK_Cyrillic_ZHE => VirtualKeyCode::Cyrillic_zhe, +// //ffi::XK_Cyrillic_VE => VirtualKeyCode::Cyrillic_ve, +// //ffi::XK_Cyrillic_SOFTSIGN => VirtualKeyCode::Cyrillic_softsign, +// //ffi::XK_Cyrillic_YERU => VirtualKeyCode::Cyrillic_yeru, +// //ffi::XK_Cyrillic_ZE => VirtualKeyCode::Cyrillic_ze, +// //ffi::XK_Cyrillic_SHA => VirtualKeyCode::Cyrillic_sha, +// //ffi::XK_Cyrillic_E => VirtualKeyCode::Cyrillic_e, +// //ffi::XK_Cyrillic_SHCHA => VirtualKeyCode::Cyrillic_shcha, +// //ffi::XK_Cyrillic_CHE => VirtualKeyCode::Cyrillic_che, +// //ffi::XK_Cyrillic_HARDSIGN => VirtualKeyCode::Cyrillic_hardsign, +// //ffi::XK_Greek_ALPHAaccent => VirtualKeyCode::Greek_alphaaccent, +// //ffi::XK_Greek_EPSILONaccent => VirtualKeyCode::Greek_epsilonaccent, +// //ffi::XK_Greek_ETAaccent => VirtualKeyCode::Greek_etaaccent, +// //ffi::XK_Greek_IOTAaccent => VirtualKeyCode::Greek_iotaaccent, +// //ffi::XK_Greek_IOTAdiaeresis => VirtualKeyCode::Greek_iotadiaeresis, +// //ffi::XK_Greek_OMICRONaccent => VirtualKeyCode::Greek_omicronaccent, +// //ffi::XK_Greek_UPSILONaccent => VirtualKeyCode::Greek_upsilonaccent, +// //ffi::XK_Greek_UPSILONdieresis => VirtualKeyCode::Greek_upsilondieresis, +// //ffi::XK_Greek_OMEGAaccent => VirtualKeyCode::Greek_omegaaccent, +// //ffi::XK_Greek_accentdieresis => VirtualKeyCode::Greek_accentdieresis, +// //ffi::XK_Greek_horizbar => VirtualKeyCode::Greek_horizbar, +// //ffi::XK_Greek_alphaaccent => VirtualKeyCode::Greek_alphaaccent, +// //ffi::XK_Greek_epsilonaccent => VirtualKeyCode::Greek_epsilonaccent, +// //ffi::XK_Greek_etaaccent => VirtualKeyCode::Greek_etaaccent, +// //ffi::XK_Greek_iotaaccent => VirtualKeyCode::Greek_iotaaccent, +// //ffi::XK_Greek_iotadieresis => VirtualKeyCode::Greek_iotadieresis, +// //ffi::XK_Greek_iotaaccentdieresis => VirtualKeyCode::Greek_iotaaccentdieresis, +// //ffi::XK_Greek_omicronaccent => VirtualKeyCode::Greek_omicronaccent, +// //ffi::XK_Greek_upsilonaccent => VirtualKeyCode::Greek_upsilonaccent, +// //ffi::XK_Greek_upsilondieresis => VirtualKeyCode::Greek_upsilondieresis, +// //ffi::XK_Greek_upsilonaccentdieresis => VirtualKeyCode::Greek_upsilonaccentdieresis, +// //ffi::XK_Greek_omegaaccent => VirtualKeyCode::Greek_omegaaccent, +// //ffi::XK_Greek_ALPHA => VirtualKeyCode::Greek_alpha, +// //ffi::XK_Greek_BETA => VirtualKeyCode::Greek_beta, +// //ffi::XK_Greek_GAMMA => VirtualKeyCode::Greek_gamma, +// //ffi::XK_Greek_DELTA => VirtualKeyCode::Greek_delta, +// //ffi::XK_Greek_EPSILON => VirtualKeyCode::Greek_epsilon, +// //ffi::XK_Greek_ZETA => VirtualKeyCode::Greek_zeta, +// //ffi::XK_Greek_ETA => VirtualKeyCode::Greek_eta, +// //ffi::XK_Greek_THETA => VirtualKeyCode::Greek_theta, +// //ffi::XK_Greek_IOTA => VirtualKeyCode::Greek_iota, +// //ffi::XK_Greek_KAPPA => VirtualKeyCode::Greek_kappa, +// //ffi::XK_Greek_LAMDA => VirtualKeyCode::Greek_lamda, +// //ffi::XK_Greek_LAMBDA => VirtualKeyCode::Greek_lambda, +// //ffi::XK_Greek_MU => VirtualKeyCode::Greek_mu, +// //ffi::XK_Greek_NU => VirtualKeyCode::Greek_nu, +// //ffi::XK_Greek_XI => VirtualKeyCode::Greek_xi, +// //ffi::XK_Greek_OMICRON => VirtualKeyCode::Greek_omicron, +// //ffi::XK_Greek_PI => VirtualKeyCode::Greek_pi, +// //ffi::XK_Greek_RHO => VirtualKeyCode::Greek_rho, +// //ffi::XK_Greek_SIGMA => VirtualKeyCode::Greek_sigma, +// //ffi::XK_Greek_TAU => VirtualKeyCode::Greek_tau, +// //ffi::XK_Greek_UPSILON => VirtualKeyCode::Greek_upsilon, +// //ffi::XK_Greek_PHI => VirtualKeyCode::Greek_phi, +// //ffi::XK_Greek_CHI => VirtualKeyCode::Greek_chi, +// //ffi::XK_Greek_PSI => VirtualKeyCode::Greek_psi, +// //ffi::XK_Greek_OMEGA => VirtualKeyCode::Greek_omega, +// //ffi::XK_Greek_alpha => VirtualKeyCode::Greek_alpha, +// //ffi::XK_Greek_beta => VirtualKeyCode::Greek_beta, +// //ffi::XK_Greek_gamma => VirtualKeyCode::Greek_gamma, +// //ffi::XK_Greek_delta => VirtualKeyCode::Greek_delta, +// //ffi::XK_Greek_epsilon => VirtualKeyCode::Greek_epsilon, +// //ffi::XK_Greek_zeta => VirtualKeyCode::Greek_zeta, +// //ffi::XK_Greek_eta => VirtualKeyCode::Greek_eta, +// //ffi::XK_Greek_theta => VirtualKeyCode::Greek_theta, +// //ffi::XK_Greek_iota => VirtualKeyCode::Greek_iota, +// //ffi::XK_Greek_kappa => VirtualKeyCode::Greek_kappa, +// //ffi::XK_Greek_lamda => VirtualKeyCode::Greek_lamda, +// //ffi::XK_Greek_lambda => VirtualKeyCode::Greek_lambda, +// //ffi::XK_Greek_mu => VirtualKeyCode::Greek_mu, +// //ffi::XK_Greek_nu => VirtualKeyCode::Greek_nu, +// //ffi::XK_Greek_xi => VirtualKeyCode::Greek_xi, +// //ffi::XK_Greek_omicron => VirtualKeyCode::Greek_omicron, +// //ffi::XK_Greek_pi => VirtualKeyCode::Greek_pi, +// //ffi::XK_Greek_rho => VirtualKeyCode::Greek_rho, +// //ffi::XK_Greek_sigma => VirtualKeyCode::Greek_sigma, +// //ffi::XK_Greek_finalsmallsigma => VirtualKeyCode::Greek_finalsmallsigma, +// //ffi::XK_Greek_tau => VirtualKeyCode::Greek_tau, +// //ffi::XK_Greek_upsilon => VirtualKeyCode::Greek_upsilon, +// //ffi::XK_Greek_phi => VirtualKeyCode::Greek_phi, +// //ffi::XK_Greek_chi => VirtualKeyCode::Greek_chi, +// //ffi::XK_Greek_psi => VirtualKeyCode::Greek_psi, +// //ffi::XK_Greek_omega => VirtualKeyCode::Greek_omega, +// //ffi::XK_Greek_switch => VirtualKeyCode::Greek_switch, +// //ffi::XK_leftradical => VirtualKeyCode::Leftradical, +// //ffi::XK_topleftradical => VirtualKeyCode::Topleftradical, +// //ffi::XK_horizconnector => VirtualKeyCode::Horizconnector, +// //ffi::XK_topintegral => VirtualKeyCode::Topintegral, +// //ffi::XK_botintegral => VirtualKeyCode::Botintegral, +// //ffi::XK_vertconnector => VirtualKeyCode::Vertconnector, +// //ffi::XK_topleftsqbracket => VirtualKeyCode::Topleftsqbracket, +// //ffi::XK_botleftsqbracket => VirtualKeyCode::Botleftsqbracket, +// //ffi::XK_toprightsqbracket => VirtualKeyCode::Toprightsqbracket, +// //ffi::XK_botrightsqbracket => VirtualKeyCode::Botrightsqbracket, +// //ffi::XK_topleftparens => VirtualKeyCode::Topleftparens, +// //ffi::XK_botleftparens => VirtualKeyCode::Botleftparens, +// //ffi::XK_toprightparens => VirtualKeyCode::Toprightparens, +// //ffi::XK_botrightparens => VirtualKeyCode::Botrightparens, +// //ffi::XK_leftmiddlecurlybrace => VirtualKeyCode::Leftmiddlecurlybrace, +// //ffi::XK_rightmiddlecurlybrace => VirtualKeyCode::Rightmiddlecurlybrace, +// //ffi::XK_topleftsummation => VirtualKeyCode::Topleftsummation, +// //ffi::XK_botleftsummation => VirtualKeyCode::Botleftsummation, +// //ffi::XK_topvertsummationconnector => VirtualKeyCode::Topvertsummationconnector, +// //ffi::XK_botvertsummationconnector => VirtualKeyCode::Botvertsummationconnector, +// //ffi::XK_toprightsummation => VirtualKeyCode::Toprightsummation, +// //ffi::XK_botrightsummation => VirtualKeyCode::Botrightsummation, +// //ffi::XK_rightmiddlesummation => VirtualKeyCode::Rightmiddlesummation, +// //ffi::XK_lessthanequal => VirtualKeyCode::Lessthanequal, +// //ffi::XK_notequal => VirtualKeyCode::Notequal, +// //ffi::XK_greaterthanequal => VirtualKeyCode::Greaterthanequal, +// //ffi::XK_integral => VirtualKeyCode::Integral, +// //ffi::XK_therefore => VirtualKeyCode::Therefore, +// //ffi::XK_variation => VirtualKeyCode::Variation, +// //ffi::XK_infinity => VirtualKeyCode::Infinity, +// //ffi::XK_nabla => VirtualKeyCode::Nabla, +// //ffi::XK_approximate => VirtualKeyCode::Approximate, +// //ffi::XK_similarequal => VirtualKeyCode::Similarequal, +// //ffi::XK_ifonlyif => VirtualKeyCode::Ifonlyif, +// //ffi::XK_implies => VirtualKeyCode::Implies, +// //ffi::XK_identical => VirtualKeyCode::Identical, +// //ffi::XK_radical => VirtualKeyCode::Radical, +// //ffi::XK_includedin => VirtualKeyCode::Includedin, +// //ffi::XK_includes => VirtualKeyCode::Includes, +// //ffi::XK_intersection => VirtualKeyCode::Intersection, +// //ffi::XK_union => VirtualKeyCode::Union, +// //ffi::XK_logicaland => VirtualKeyCode::Logicaland, +// //ffi::XK_logicalor => VirtualKeyCode::Logicalor, +// //ffi::XK_partialderivative => VirtualKeyCode::Partialderivative, +// //ffi::XK_function => VirtualKeyCode::Function, +// //ffi::XK_leftarrow => VirtualKeyCode::Leftarrow, +// //ffi::XK_uparrow => VirtualKeyCode::Uparrow, +// //ffi::XK_rightarrow => VirtualKeyCode::Rightarrow, +// //ffi::XK_downarrow => VirtualKeyCode::Downarrow, +// //ffi::XK_blank => VirtualKeyCode::Blank, +// //ffi::XK_soliddiamond => VirtualKeyCode::Soliddiamond, +// //ffi::XK_checkerboard => VirtualKeyCode::Checkerboard, +// //ffi::XK_ht => VirtualKeyCode::Ht, +// //ffi::XK_ff => VirtualKeyCode::Ff, +// //ffi::XK_cr => VirtualKeyCode::Cr, +// //ffi::XK_lf => VirtualKeyCode::Lf, +// //ffi::XK_nl => VirtualKeyCode::Nl, +// //ffi::XK_vt => VirtualKeyCode::Vt, +// //ffi::XK_lowrightcorner => VirtualKeyCode::Lowrightcorner, +// //ffi::XK_uprightcorner => VirtualKeyCode::Uprightcorner, +// //ffi::XK_upleftcorner => VirtualKeyCode::Upleftcorner, +// //ffi::XK_lowleftcorner => VirtualKeyCode::Lowleftcorner, +// //ffi::XK_crossinglines => VirtualKeyCode::Crossinglines, +// //ffi::XK_horizlinescan1 => VirtualKeyCode::Horizlinescan1, +// //ffi::XK_horizlinescan3 => VirtualKeyCode::Horizlinescan3, +// //ffi::XK_horizlinescan5 => VirtualKeyCode::Horizlinescan5, +// //ffi::XK_horizlinescan7 => VirtualKeyCode::Horizlinescan7, +// //ffi::XK_horizlinescan9 => VirtualKeyCode::Horizlinescan9, +// //ffi::XK_leftt => VirtualKeyCode::Leftt, +// //ffi::XK_rightt => VirtualKeyCode::Rightt, +// //ffi::XK_bott => VirtualKeyCode::Bott, +// //ffi::XK_topt => VirtualKeyCode::Topt, +// //ffi::XK_vertbar => VirtualKeyCode::Vertbar, +// //ffi::XK_emspace => VirtualKeyCode::Emspace, +// //ffi::XK_enspace => VirtualKeyCode::Enspace, +// //ffi::XK_em3space => VirtualKeyCode::Em3space, +// //ffi::XK_em4space => VirtualKeyCode::Em4space, +// //ffi::XK_digitspace => VirtualKeyCode::Digitspace, +// //ffi::XK_punctspace => VirtualKeyCode::Punctspace, +// //ffi::XK_thinspace => VirtualKeyCode::Thinspace, +// //ffi::XK_hairspace => VirtualKeyCode::Hairspace, +// //ffi::XK_emdash => VirtualKeyCode::Emdash, +// //ffi::XK_endash => VirtualKeyCode::Endash, +// //ffi::XK_signifblank => VirtualKeyCode::Signifblank, +// //ffi::XK_ellipsis => VirtualKeyCode::Ellipsis, +// //ffi::XK_doubbaselinedot => VirtualKeyCode::Doubbaselinedot, +// //ffi::XK_onethird => VirtualKeyCode::Onethird, +// //ffi::XK_twothirds => VirtualKeyCode::Twothirds, +// //ffi::XK_onefifth => VirtualKeyCode::Onefifth, +// //ffi::XK_twofifths => VirtualKeyCode::Twofifths, +// //ffi::XK_threefifths => VirtualKeyCode::Threefifths, +// //ffi::XK_fourfifths => VirtualKeyCode::Fourfifths, +// //ffi::XK_onesixth => VirtualKeyCode::Onesixth, +// //ffi::XK_fivesixths => VirtualKeyCode::Fivesixths, +// //ffi::XK_careof => VirtualKeyCode::Careof, +// //ffi::XK_figdash => VirtualKeyCode::Figdash, +// //ffi::XK_leftanglebracket => VirtualKeyCode::Leftanglebracket, +// //ffi::XK_decimalpoint => VirtualKeyCode::Decimalpoint, +// //ffi::XK_rightanglebracket => VirtualKeyCode::Rightanglebracket, +// //ffi::XK_marker => VirtualKeyCode::Marker, +// //ffi::XK_oneeighth => VirtualKeyCode::Oneeighth, +// //ffi::XK_threeeighths => VirtualKeyCode::Threeeighths, +// //ffi::XK_fiveeighths => VirtualKeyCode::Fiveeighths, +// //ffi::XK_seveneighths => VirtualKeyCode::Seveneighths, +// //ffi::XK_trademark => VirtualKeyCode::Trademark, +// //ffi::XK_signaturemark => VirtualKeyCode::Signaturemark, +// //ffi::XK_trademarkincircle => VirtualKeyCode::Trademarkincircle, +// //ffi::XK_leftopentriangle => VirtualKeyCode::Leftopentriangle, +// //ffi::XK_rightopentriangle => VirtualKeyCode::Rightopentriangle, +// //ffi::XK_emopencircle => VirtualKeyCode::Emopencircle, +// //ffi::XK_emopenrectangle => VirtualKeyCode::Emopenrectangle, +// //ffi::XK_leftsinglequotemark => VirtualKeyCode::Leftsinglequotemark, +// //ffi::XK_rightsinglequotemark => VirtualKeyCode::Rightsinglequotemark, +// //ffi::XK_leftdoublequotemark => VirtualKeyCode::Leftdoublequotemark, +// //ffi::XK_rightdoublequotemark => VirtualKeyCode::Rightdoublequotemark, +// //ffi::XK_prescription => VirtualKeyCode::Prescription, +// //ffi::XK_minutes => VirtualKeyCode::Minutes, +// //ffi::XK_seconds => VirtualKeyCode::Seconds, +// //ffi::XK_latincross => VirtualKeyCode::Latincross, +// //ffi::XK_hexagram => VirtualKeyCode::Hexagram, +// //ffi::XK_filledrectbullet => VirtualKeyCode::Filledrectbullet, +// //ffi::XK_filledlefttribullet => VirtualKeyCode::Filledlefttribullet, +// //ffi::XK_filledrighttribullet => VirtualKeyCode::Filledrighttribullet, +// //ffi::XK_emfilledcircle => VirtualKeyCode::Emfilledcircle, +// //ffi::XK_emfilledrect => VirtualKeyCode::Emfilledrect, +// //ffi::XK_enopencircbullet => VirtualKeyCode::Enopencircbullet, +// //ffi::XK_enopensquarebullet => VirtualKeyCode::Enopensquarebullet, +// //ffi::XK_openrectbullet => VirtualKeyCode::Openrectbullet, +// //ffi::XK_opentribulletup => VirtualKeyCode::Opentribulletup, +// //ffi::XK_opentribulletdown => VirtualKeyCode::Opentribulletdown, +// //ffi::XK_openstar => VirtualKeyCode::Openstar, +// //ffi::XK_enfilledcircbullet => VirtualKeyCode::Enfilledcircbullet, +// //ffi::XK_enfilledsqbullet => VirtualKeyCode::Enfilledsqbullet, +// //ffi::XK_filledtribulletup => VirtualKeyCode::Filledtribulletup, +// //ffi::XK_filledtribulletdown => VirtualKeyCode::Filledtribulletdown, +// //ffi::XK_leftpointer => VirtualKeyCode::Leftpointer, +// //ffi::XK_rightpointer => VirtualKeyCode::Rightpointer, +// //ffi::XK_club => VirtualKeyCode::Club, +// //ffi::XK_diamond => VirtualKeyCode::Diamond, +// //ffi::XK_heart => VirtualKeyCode::Heart, +// //ffi::XK_maltesecross => VirtualKeyCode::Maltesecross, +// //ffi::XK_dagger => VirtualKeyCode::Dagger, +// //ffi::XK_doubledagger => VirtualKeyCode::Doubledagger, +// //ffi::XK_checkmark => VirtualKeyCode::Checkmark, +// //ffi::XK_ballotcross => VirtualKeyCode::Ballotcross, +// //ffi::XK_musicalsharp => VirtualKeyCode::Musicalsharp, +// //ffi::XK_musicalflat => VirtualKeyCode::Musicalflat, +// //ffi::XK_malesymbol => VirtualKeyCode::Malesymbol, +// //ffi::XK_femalesymbol => VirtualKeyCode::Femalesymbol, +// //ffi::XK_telephone => VirtualKeyCode::Telephone, +// //ffi::XK_telephonerecorder => VirtualKeyCode::Telephonerecorder, +// //ffi::XK_phonographcopyright => VirtualKeyCode::Phonographcopyright, +// //ffi::XK_caret => VirtualKeyCode::Caret, +// //ffi::XK_singlelowquotemark => VirtualKeyCode::Singlelowquotemark, +// //ffi::XK_doublelowquotemark => VirtualKeyCode::Doublelowquotemark, +// //ffi::XK_cursor => VirtualKeyCode::Cursor, +// //ffi::XK_leftcaret => VirtualKeyCode::Leftcaret, +// //ffi::XK_rightcaret => VirtualKeyCode::Rightcaret, +// //ffi::XK_downcaret => VirtualKeyCode::Downcaret, +// //ffi::XK_upcaret => VirtualKeyCode::Upcaret, +// //ffi::XK_overbar => VirtualKeyCode::Overbar, +// //ffi::XK_downtack => VirtualKeyCode::Downtack, +// //ffi::XK_upshoe => VirtualKeyCode::Upshoe, +// //ffi::XK_downstile => VirtualKeyCode::Downstile, +// //ffi::XK_underbar => VirtualKeyCode::Underbar, +// //ffi::XK_jot => VirtualKeyCode::Jot, +// //ffi::XK_quad => VirtualKeyCode::Quad, +// //ffi::XK_uptack => VirtualKeyCode::Uptack, +// //ffi::XK_circle => VirtualKeyCode::Circle, +// //ffi::XK_upstile => VirtualKeyCode::Upstile, +// //ffi::XK_downshoe => VirtualKeyCode::Downshoe, +// //ffi::XK_rightshoe => VirtualKeyCode::Rightshoe, +// //ffi::XK_leftshoe => VirtualKeyCode::Leftshoe, +// //ffi::XK_lefttack => VirtualKeyCode::Lefttack, +// //ffi::XK_righttack => VirtualKeyCode::Righttack, +// //ffi::XK_hebrew_doublelowline => VirtualKeyCode::Hebrew_doublelowline, +// //ffi::XK_hebrew_aleph => VirtualKeyCode::Hebrew_aleph, +// //ffi::XK_hebrew_bet => VirtualKeyCode::Hebrew_bet, +// //ffi::XK_hebrew_beth => VirtualKeyCode::Hebrew_beth, +// //ffi::XK_hebrew_gimel => VirtualKeyCode::Hebrew_gimel, +// //ffi::XK_hebrew_gimmel => VirtualKeyCode::Hebrew_gimmel, +// //ffi::XK_hebrew_dalet => VirtualKeyCode::Hebrew_dalet, +// //ffi::XK_hebrew_daleth => VirtualKeyCode::Hebrew_daleth, +// //ffi::XK_hebrew_he => VirtualKeyCode::Hebrew_he, +// //ffi::XK_hebrew_waw => VirtualKeyCode::Hebrew_waw, +// //ffi::XK_hebrew_zain => VirtualKeyCode::Hebrew_zain, +// //ffi::XK_hebrew_zayin => VirtualKeyCode::Hebrew_zayin, +// //ffi::XK_hebrew_chet => VirtualKeyCode::Hebrew_chet, +// //ffi::XK_hebrew_het => VirtualKeyCode::Hebrew_het, +// //ffi::XK_hebrew_tet => VirtualKeyCode::Hebrew_tet, +// //ffi::XK_hebrew_teth => VirtualKeyCode::Hebrew_teth, +// //ffi::XK_hebrew_yod => VirtualKeyCode::Hebrew_yod, +// //ffi::XK_hebrew_finalkaph => VirtualKeyCode::Hebrew_finalkaph, +// //ffi::XK_hebrew_kaph => VirtualKeyCode::Hebrew_kaph, +// //ffi::XK_hebrew_lamed => VirtualKeyCode::Hebrew_lamed, +// //ffi::XK_hebrew_finalmem => VirtualKeyCode::Hebrew_finalmem, +// //ffi::XK_hebrew_mem => VirtualKeyCode::Hebrew_mem, +// //ffi::XK_hebrew_finalnun => VirtualKeyCode::Hebrew_finalnun, +// //ffi::XK_hebrew_nun => VirtualKeyCode::Hebrew_nun, +// //ffi::XK_hebrew_samech => VirtualKeyCode::Hebrew_samech, +// //ffi::XK_hebrew_samekh => VirtualKeyCode::Hebrew_samekh, +// //ffi::XK_hebrew_ayin => VirtualKeyCode::Hebrew_ayin, +// //ffi::XK_hebrew_finalpe => VirtualKeyCode::Hebrew_finalpe, +// //ffi::XK_hebrew_pe => VirtualKeyCode::Hebrew_pe, +// //ffi::XK_hebrew_finalzade => VirtualKeyCode::Hebrew_finalzade, +// //ffi::XK_hebrew_finalzadi => VirtualKeyCode::Hebrew_finalzadi, +// //ffi::XK_hebrew_zade => VirtualKeyCode::Hebrew_zade, +// //ffi::XK_hebrew_zadi => VirtualKeyCode::Hebrew_zadi, +// //ffi::XK_hebrew_qoph => VirtualKeyCode::Hebrew_qoph, +// //ffi::XK_hebrew_kuf => VirtualKeyCode::Hebrew_kuf, +// //ffi::XK_hebrew_resh => VirtualKeyCode::Hebrew_resh, +// //ffi::XK_hebrew_shin => VirtualKeyCode::Hebrew_shin, +// //ffi::XK_hebrew_taw => VirtualKeyCode::Hebrew_taw, +// //ffi::XK_hebrew_taf => VirtualKeyCode::Hebrew_taf, +// //ffi::XK_Hebrew_switch => VirtualKeyCode::Hebrew_switch, +// ffi::XF86XK_Back => VirtualKeyCode::NavigateBackward, +// ffi::XF86XK_Forward => VirtualKeyCode::NavigateForward, +// ffi::XF86XK_Copy => VirtualKeyCode::Copy, +// ffi::XF86XK_Paste => VirtualKeyCode::Paste, +// ffi::XF86XK_Cut => VirtualKeyCode::Cut, +// _ => return None, +// }) +// } diff --git a/src/platform_impl/linux/x11/util/input.rs b/src/platform_impl/linux/x11/util/input.rs index e9f45aee1c..6c7c651eed 100644 --- a/src/platform_impl/linux/x11/util/input.rs +++ b/src/platform_impl/linux/x11/util/input.rs @@ -1,7 +1,7 @@ use std::{slice, str}; use super::*; -use crate::event::ModifiersState; +use crate::keyboard::ModifiersState; pub const VIRTUAL_CORE_POINTER: c_int = 2; pub const VIRTUAL_CORE_KEYBOARD: c_int = 3; @@ -20,8 +20,8 @@ impl ModifiersState { let mut m = ModifiersState::empty(); m.set(ModifiersState::ALT, mask & ffi::Mod1Mask != 0); m.set(ModifiersState::SHIFT, mask & ffi::ShiftMask != 0); - m.set(ModifiersState::CTRL, mask & ffi::ControlMask != 0); - m.set(ModifiersState::LOGO, mask & ffi::Mod4Mask != 0); + m.set(ModifiersState::CONTROL, mask & ffi::ControlMask != 0); + m.set(ModifiersState::SUPER, mask & ffi::Mod4Mask != 0); m } } diff --git a/src/platform_impl/linux/x11/util/modifiers.rs b/src/platform_impl/linux/x11/util/modifiers.rs index acdab577e0..31db220263 100644 --- a/src/platform_impl/linux/x11/util/modifiers.rs +++ b/src/platform_impl/linux/x11/util/modifiers.rs @@ -2,7 +2,8 @@ use std::{collections::HashMap, slice}; use super::*; -use crate::event::{ElementState, ModifiersState}; +use crate::event::ElementState; +use crate::keyboard::ModifiersState; // Offsets within XModifierKeymap to each set of keycodes. // We are only interested in Shift, Control, Alt, and Logo. @@ -116,10 +117,12 @@ impl ModifierKeyState { let mut new_state = *state; match except { - Some(Modifier::Alt) => new_state.set(ModifiersState::ALT, self.state.alt()), - Some(Modifier::Ctrl) => new_state.set(ModifiersState::CTRL, self.state.ctrl()), - Some(Modifier::Shift) => new_state.set(ModifiersState::SHIFT, self.state.shift()), - Some(Modifier::Logo) => new_state.set(ModifiersState::LOGO, self.state.logo()), + Some(Modifier::Alt) => new_state.set(ModifiersState::ALT, self.state.alt_key()), + Some(Modifier::Ctrl) => { + new_state.set(ModifiersState::CONTROL, self.state.control_key()) + } + Some(Modifier::Shift) => new_state.set(ModifiersState::SHIFT, self.state.shift_key()), + Some(Modifier::Logo) => new_state.set(ModifiersState::SUPER, self.state.super_key()), None => (), } @@ -170,18 +173,18 @@ impl ModifierKeyState { fn get_modifier(state: &ModifiersState, modifier: Modifier) -> bool { match modifier { - Modifier::Alt => state.alt(), - Modifier::Ctrl => state.ctrl(), - Modifier::Shift => state.shift(), - Modifier::Logo => state.logo(), + Modifier::Alt => state.alt_key(), + Modifier::Ctrl => state.control_key(), + Modifier::Shift => state.shift_key(), + Modifier::Logo => state.super_key(), } } fn set_modifier(state: &mut ModifiersState, modifier: Modifier, value: bool) { match modifier { Modifier::Alt => state.set(ModifiersState::ALT, value), - Modifier::Ctrl => state.set(ModifiersState::CTRL, value), + Modifier::Ctrl => state.set(ModifiersState::CONTROL, value), Modifier::Shift => state.set(ModifiersState::SHIFT, value), - Modifier::Logo => state.set(ModifiersState::LOGO, value), + Modifier::Logo => state.set(ModifiersState::SUPER, value), } } From a24b543d591cf38aa09e4c8f5c39814e77822ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Mon, 10 Jan 2022 15:51:27 +0100 Subject: [PATCH 04/53] fixup! Get stuff to compile --- src/platform_impl/linux/x11/event_processor.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 22474abaa1..261ba15d76 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -1104,7 +1104,6 @@ impl EventProcessor { event: DeviceEvent::Key(RawKeyEvent { physical_key: todo!(), state: todo!(), - repeat: todo!(), }), }); From 3ef7f7f4b15d43cb64d12a35911c7660604d0f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Sat, 20 Mar 2021 00:46:14 +0100 Subject: [PATCH 05/53] WIP --- .../linux/wayland/seat/keyboard/handlers.rs | 35 +- .../linux/wayland/seat/keyboard/keymap.rs | 694 ++++++++++++------ 2 files changed, 493 insertions(+), 236 deletions(-) diff --git a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs index d81e440cc5..47cbc984ad 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs @@ -5,9 +5,10 @@ use sctk::reexports::client::protocol::wl_keyboard::KeyState; use sctk::seat::keyboard::Event as KeyboardEvent; use crate::event::{ElementState, KeyEvent, WindowEvent}; -use crate::keyboard::ModifiersState; +use crate::keyboard::{Key, KeyLocation, ModifiersState, NativeKeyCode}; use crate::platform_impl::wayland::event_loop::WinitState; use crate::platform_impl::wayland::{self, DeviceId}; +use crate::platform_impl::KeyEventExtra; use super::keymap; use super::KeyboardInner; @@ -69,7 +70,8 @@ pub(super) fn handle_keyboard( _ => unreachable!(), }; - // let virtual_keycode = keymap::keysym_to_vkey(keysym); + let physical_key = keymap::rawkey_to_keycode(rawkey); + let logical_key = keymap::keysym_to_key(keysym); event_sink.push_window_event( WindowEvent::KeyboardInput { @@ -77,13 +79,16 @@ pub(super) fn handle_keyboard( DeviceId, )), event: KeyEvent { - physical_key: todo!(), - logical_key: todo!(), - text: todo!(), - location: todo!(), + physical_key, + logical_key, + text: None, + location: KeyLocation::Standard, state, repeat: false, - platform_specific: todo!(), + platform_specific: KeyEventExtra { + key_without_modifiers: Key::Unidentified(NativeKeyCode::Unidentified), + text_with_all_modifers: None, + }, }, is_synthetic: false, }, @@ -112,7 +117,8 @@ pub(super) fn handle_keyboard( None => return, }; - // let virtual_keycode = keymap::keysym_to_vkey(keysym); + let physical_key = keymap::rawkey_to_keycode(rawkey); + let logical_key = keymap::keysym_to_key(keysym); event_sink.push_window_event( WindowEvent::KeyboardInput { @@ -120,13 +126,16 @@ pub(super) fn handle_keyboard( DeviceId, )), event: KeyEvent { - physical_key: todo!(), - logical_key: todo!(), - text: todo!(), - location: todo!(), + physical_key, + logical_key, + text: None, + location: KeyLocation::Standard, state: ElementState::Pressed, repeat: false, - platform_specific: todo!(), + platform_specific: KeyEventExtra { + key_without_modifiers: Key::Unidentified(NativeKeyCode::Unidentified), + text_with_all_modifers: None, + }, }, is_synthetic: false, }, diff --git a/src/platform_impl/linux/wayland/seat/keyboard/keymap.rs b/src/platform_impl/linux/wayland/seat/keyboard/keymap.rs index b674dd2945..ae48fc95cf 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/keymap.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/keymap.rs @@ -1,229 +1,477 @@ // //! Convert Wayland keys to winit keys. -// use crate::keyboard::Key; +use crate::keyboard::{Key, KeyCode, NativeKeyCode}; -// pub fn keysym_to_vkey(keysym: u32) -> Option> { -// use sctk::seat::keyboard::keysyms; -// match keysym { -// // Numbers. -// // keysyms::XKB_KEY_1 => Some(Key::Character("1")), -// // keysyms::XKB_KEY_2 => Some(Key::Character("2")), -// // keysyms::XKB_KEY_3 => Some(Key::Character("3")), -// // keysyms::XKB_KEY_4 => Some(Key::Character("4")), -// // keysyms::XKB_KEY_5 => Some(Key::Character("5")), -// // keysyms::XKB_KEY_6 => Some(Key::Character("6")), -// // keysyms::XKB_KEY_7 => Some(Key::Character("7")), -// // keysyms::XKB_KEY_8 => Some(Key::Character("8")), -// // keysyms::XKB_KEY_9 => Some(Key::Character("9")), -// // keysyms::XKB_KEY_0 => Some(Key::Character("0")), -// // Letters. -// // keysyms::XKB_KEY_A => Some(Key::Character("A")), -// // keysyms::XKB_KEY_a => Some(Key::Character("a")), -// // keysyms::XKB_KEY_B => Some(Key::Character("B")), -// // keysyms::XKB_KEY_b => Some(Key::Character("b")), -// // keysyms::XKB_KEY_C => Some(Key::Character("C")), -// // keysyms::XKB_KEY_c => Some(Key::Character("c")), -// // keysyms::XKB_KEY_D => Some(Key::Character("D")), -// // keysyms::XKB_KEY_d => Some(Key::Character("d")), -// // keysyms::XKB_KEY_E => Some(Key::Character("E")), -// // keysyms::XKB_KEY_e => Some(Key::Character("e")), -// // keysyms::XKB_KEY_F => Some(Key::Character("F")), -// // keysyms::XKB_KEY_f => Some(Key::Character("f")), -// // keysyms::XKB_KEY_G => Some(Key::Character("G")), -// // keysyms::XKB_KEY_g => Some(Key::Character("g")), -// // keysyms::XKB_KEY_H => Some(Key::Character("H")), -// // keysyms::XKB_KEY_h => Some(Key::Character("h")), -// // keysyms::XKB_KEY_I => Some(Key::Character("I")), -// // keysyms::XKB_KEY_i => Some(Key::Character("i")), -// // keysyms::XKB_KEY_J => Some(Key::Character("J")), -// // keysyms::XKB_KEY_j => Some(Key::Character("j")), -// // keysyms::XKB_KEY_K => Some(Key::Character("K")), -// // keysyms::XKB_KEY_k => Some(Key::Character("k")), -// // keysyms::XKB_KEY_L => Some(Key::Character("L")), -// // keysyms::XKB_KEY_l => Some(Key::Character("l")), -// // keysyms::XKB_KEY_M => Some(Key::Character("M")), -// // keysyms::XKB_KEY_m => Some(Key::Character("m")), -// // keysyms::XKB_KEY_N => Some(Key::Character("N")), -// // keysyms::XKB_KEY_n => Some(Key::Character("n")), -// // keysyms::XKB_KEY_O => Some(Key::Character("O")), -// // keysyms::XKB_KEY_o => Some(Key::Character("o")), -// // keysyms::XKB_KEY_P => Some(Key::Character("P")), -// // keysyms::XKB_KEY_p => Some(Key::Character("p")), -// // keysyms::XKB_KEY_Q => Some(Key::Character("Q")), -// // keysyms::XKB_KEY_q => Some(Key::Character("q")), -// // keysyms::XKB_KEY_R => Some(Key::Character("R")), -// // keysyms::XKB_KEY_r => Some(Key::Character("r")), -// // keysyms::XKB_KEY_S => Some(Key::Character("S")), -// // keysyms::XKB_KEY_s => Some(Key::Character("s")), -// // keysyms::XKB_KEY_T => Some(Key::Character("T")), -// // keysyms::XKB_KEY_t => Some(Key::Character("t")), -// // keysyms::XKB_KEY_U => Some(Key::Character("U")), -// // keysyms::XKB_KEY_u => Some(Key::Character("u")), -// // keysyms::XKB_KEY_V => Some(Key::Character("V")), -// // keysyms::XKB_KEY_v => Some(Key::Character("v")), -// // keysyms::XKB_KEY_W => Some(Key::Character("W")), -// // keysyms::XKB_KEY_w => Some(Key::Character("w")), -// // keysyms::XKB_KEY_X => Some(Key::Character("X")), -// // keysyms::XKB_KEY_x => Some(Key::Character("x")), -// // keysyms::XKB_KEY_Y => Some(Key::Character("Y")), -// // keysyms::XKB_KEY_y => Some(Key::Character("y")), -// // keysyms::XKB_KEY_Z => Some(Key::Character("Z")), -// // keysyms::XKB_KEY_z => Some(Key::Character("z")), -// // Escape. -// keysyms::XKB_KEY_Escape => Some(Key::Escape), -// // Function keys. -// keysyms::XKB_KEY_F1 => Some(Key::F1), -// keysyms::XKB_KEY_F2 => Some(Key::F2), -// keysyms::XKB_KEY_F3 => Some(Key::F3), -// keysyms::XKB_KEY_F4 => Some(Key::F4), -// keysyms::XKB_KEY_F5 => Some(Key::F5), -// keysyms::XKB_KEY_F6 => Some(Key::F6), -// keysyms::XKB_KEY_F7 => Some(Key::F7), -// keysyms::XKB_KEY_F8 => Some(Key::F8), -// keysyms::XKB_KEY_F9 => Some(Key::F9), -// keysyms::XKB_KEY_F10 => Some(Key::F10), -// keysyms::XKB_KEY_F11 => Some(Key::F11), -// keysyms::XKB_KEY_F12 => Some(Key::F12), -// keysyms::XKB_KEY_F13 => Some(Key::F13), -// keysyms::XKB_KEY_F14 => Some(Key::F14), -// keysyms::XKB_KEY_F15 => Some(Key::F15), -// keysyms::XKB_KEY_F16 => Some(Key::F16), -// keysyms::XKB_KEY_F17 => Some(Key::F17), -// keysyms::XKB_KEY_F18 => Some(Key::F18), -// keysyms::XKB_KEY_F19 => Some(Key::F19), -// keysyms::XKB_KEY_F20 => Some(Key::F20), -// keysyms::XKB_KEY_F21 => Some(Key::F21), -// keysyms::XKB_KEY_F22 => Some(Key::F22), -// keysyms::XKB_KEY_F23 => Some(Key::F23), -// keysyms::XKB_KEY_F24 => Some(Key::F24), -// keysyms::XKB_KEY_F25 => Some(Key::F25), -// keysyms::XKB_KEY_F26 => Some(Key::F26), -// keysyms::XKB_KEY_F27 => Some(Key::F27), -// keysyms::XKB_KEY_F28 => Some(Key::F28), -// keysyms::XKB_KEY_F29 => Some(Key::F29), -// keysyms::XKB_KEY_F30 => Some(Key::F30), -// keysyms::XKB_KEY_F31 => Some(Key::F31), -// keysyms::XKB_KEY_F32 => Some(Key::F32), -// keysyms::XKB_KEY_F33 => Some(Key::F33), -// keysyms::XKB_KEY_F34 => Some(Key::F34), -// keysyms::XKB_KEY_F35 => Some(Key::F35), -// // Flow control. -// keysyms::XKB_KEY_Print => Some(Key::PrintScreen), -// keysyms::XKB_KEY_Scroll_Lock => Some(Key::ScrollLock), -// keysyms::XKB_KEY_Pause => Some(Key::Pause), -// keysyms::XKB_KEY_Insert => Some(Key::Insert), -// keysyms::XKB_KEY_Home => Some(Key::Home), -// keysyms::XKB_KEY_Delete => Some(Key::Delete), -// keysyms::XKB_KEY_End => Some(Key::End), -// keysyms::XKB_KEY_Page_Down => Some(Key::PageDown), -// keysyms::XKB_KEY_Page_Up => Some(Key::PageUp), -// // Arrows. -// keysyms::XKB_KEY_Left => Some(Key::Left), -// keysyms::XKB_KEY_Up => Some(Key::Up), -// keysyms::XKB_KEY_Right => Some(Key::Right), -// keysyms::XKB_KEY_Down => Some(Key::Down), +pub fn rawkey_to_keycode(rawkey: u32) -> KeyCode { + // keycodes are taken from linux/include/uapi/linux/input-event-codes.h + match rawkey { + 0 => todo!("What should be done in this case? Return `NativeKeyCode`, or perhaps `None`?"), + 1 => KeyCode::Escape, + 2 => KeyCode::Digit1, + 3 => KeyCode::Digit2, + 4 => KeyCode::Digit3, + 5 => KeyCode::Digit4, + 6 => KeyCode::Digit5, + 7 => KeyCode::Digit6, + 8 => KeyCode::Digit7, + 9 => KeyCode::Digit8, + 10 => KeyCode::Digit9, + 11 => KeyCode::Digit0, + 12 => KeyCode::Minus, + 13 => KeyCode::Equal, + 14 => KeyCode::Backspace, + 15 => KeyCode::Tab, + 16 => KeyCode::KeyQ, + 17 => KeyCode::KeyW, + 18 => KeyCode::KeyE, + 19 => KeyCode::KeyR, + 20 => KeyCode::KeyT, + 21 => KeyCode::KeyY, + 22 => KeyCode::KeyU, + 23 => KeyCode::KeyI, + 24 => KeyCode::KeyO, + 25 => KeyCode::KeyP, + 26 => KeyCode::BracketLeft, + 27 => KeyCode::BracketRight, + 28 => KeyCode::Enter, + 29 => KeyCode::ControlLeft, + 30 => KeyCode::KeyA, + 31 => KeyCode::KeyS, + 32 => KeyCode::KeyD, + 33 => KeyCode::KeyF, + 34 => KeyCode::KeyG, + 35 => KeyCode::KeyH, + 36 => KeyCode::KeyJ, + 37 => KeyCode::KeyK, + 38 => KeyCode::KeyL, + 39 => KeyCode::Semicolon, + 40 => KeyCode::Quote, + 41 => KeyCode::Backquote, + 42 => KeyCode::ShiftLeft, + 43 => KeyCode::Backslash, + 44 => KeyCode::KeyZ, + 45 => KeyCode::KeyX, + 46 => KeyCode::KeyC, + 47 => KeyCode::KeyV, + 48 => KeyCode::KeyB, + 49 => KeyCode::KeyN, + 50 => KeyCode::KeyM, + 51 => KeyCode::Comma, + 52 => KeyCode::Period, + 53 => KeyCode::Slash, + 54 => KeyCode::ShiftRight, + 55 => KeyCode::NumpadMultiply, + 56 => KeyCode::AltLeft, + 57 => KeyCode::Space, + 58 => KeyCode::CapsLock, + 59 => KeyCode::F1, + 60 => KeyCode::F2, + 61 => KeyCode::F3, + 62 => KeyCode::F4, + 63 => KeyCode::F5, + 64 => KeyCode::F6, + 65 => KeyCode::F7, + 66 => KeyCode::F8, + 67 => KeyCode::F9, + 68 => KeyCode::F10, + 69 => KeyCode::NumLock, + 70 => KeyCode::ScrollLock, + 71 => KeyCode::Numpad7, + 72 => KeyCode::Numpad8, + 73 => KeyCode::Numpad9, + 74 => KeyCode::NumpadSubtract, + 75 => KeyCode::Numpad4, + 76 => KeyCode::Numpad4, + 77 => KeyCode::Numpad6, + 78 => KeyCode::NumpadAdd, + 79 => KeyCode::Numpad1, + 80 => KeyCode::Numpad2, + 81 => KeyCode::Numpad3, + 82 => KeyCode::Numpad0, + 83 => KeyCode::NumpadDecimal, + 85 => KeyCode::Lang5, + 86 => KeyCode::IntlBackslash, // TODO: Verify. + 87 => KeyCode::F11, + 88 => KeyCode::F12, + 89 => KeyCode::IntlRo, + 90 => KeyCode::Lang3, + 91 => KeyCode::Lang4, + 92 => KeyCode::Convert, + 93 => KeyCode::KanaMode, + 94 => KeyCode::NonConvert, + // 95 => KeyCode::KPJPCOMMA, // TODO: What the heck is this supposed to be? + 96 => KeyCode::NumpadEnter, + 97 => KeyCode::ControlRight, + 98 => KeyCode::NumpadDivide, + 99 => KeyCode::PrintScreen, // TODO: Verify. + 100 => KeyCode::AltRight, + // 101 => KeyCode::LINEFEED, // TODO: What the heck is this supposed to be? + 102 => KeyCode::Home, + 103 => KeyCode::ArrowUp, + 104 => KeyCode::PageUp, + 105 => KeyCode::ArrowLeft, + 106 => KeyCode::ArrowRight, + 107 => KeyCode::End, + 108 => KeyCode::ArrowDown, + 109 => KeyCode::PageDown, + 110 => KeyCode::Insert, + 111 => KeyCode::Delete, + // 112 => KeyCode::MACRO, // TODO: What the heck is this supposed to be? + 113 => KeyCode::AudioVolumeMute, + 114 => KeyCode::AudioVolumeDown, + 115 => KeyCode::AudioVolumeUp, + // TODO: I have no idea if this should be mapped to `KeyCode::Power` + // Neither the Linux header or the uievents-code document disambigues this. + // 116 => KeyCode::POWER, + 117 => KeyCode::NumpadEqual, + // 118 => KeyCode::KPPLUSMINUS, // TODO: What the heck is this supposed to be? + 119 => KeyCode::Pause, + // 120 => KeyCode::SCALE, // TODO: What the heck is this supposed to be? + 121 => KeyCode::NumpadComma, + 122 => KeyCode::Lang1, + 123 => KeyCode::Lang2, + 124 => KeyCode::IntlYen, + 125 => KeyCode::SuperLeft, + 126 => KeyCode::SuperRight, + 127 => KeyCode::ContextMenu, + // 128 => KeyCode::STOP, + // 129 => KeyCode::AGAIN, + // 130 => KeyCode::PROPS, + // 131 => KeyCode::UNDO, + // 132 => KeyCode::FRONT, + // 133 => KeyCode::COPY, + // 134 => KeyCode::OPEN, + // 135 => KeyCode::PASTE, + // 136 => KeyCode::FIND, + // 137 => KeyCode::CUT, + // 138 => KeyCode::HELP, + // 139 => KeyCode::MENU, + // 140 => KeyCode::CALC, + // 141 => KeyCode::SETUP, + // 142 => KeyCode::SLEEP, + // 143 => KeyCode::WAKEUP, + // 144 => KeyCode::FILE, + // 145 => KeyCode::SENDFILE, + // 146 => KeyCode::DELETEFILE, + // 147 => KeyCode::XFER, + // 148 => KeyCode::PROG1, + // 149 => KeyCode::PROG2, + // 150 => KeyCode::WWW, + // 151 => KeyCode::MSDOS, + // 152 => KeyCode::COFFEE, + // 153 => KeyCode::ROTATE_DISPLAY, + // 154 => KeyCode::CYCLEWINDOWS, + // 155 => KeyCode::MAIL, + // 156 => KeyCode::BOOKMARKS, + // 157 => KeyCode::COMPUTER, + // 158 => KeyCode::BACK, + // 159 => KeyCode::FORWARD, + // 160 => KeyCode::CLOSECD, + // 161 => KeyCode::EJECTCD, + // 162 => KeyCode::EJECTCLOSECD, + 163 => KeyCode::MediaTrackNext, + 164 => KeyCode::MediaPlayPause, + 165 => KeyCode::MediaTrackPrevious, + 166 => KeyCode::MediaStop, + // 167 => KeyCode::RECORD, + // 168 => KeyCode::REWIND, + // 169 => KeyCode::PHONE, + // 170 => KeyCode::ISO, + // 171 => KeyCode::CONFIG, + // 172 => KeyCode::HOMEPAGE, + // 173 => KeyCode::REFRESH, + // 174 => KeyCode::EXIT, + // 175 => KeyCode::MOVE, + // 176 => KeyCode::EDIT, + // 177 => KeyCode::SCROLLUP, + // 178 => KeyCode::SCROLLDOWN, + // 179 => KeyCode::KPLEFTPAREN, + // 180 => KeyCode::KPRIGHTPAREN, + // 181 => KeyCode::NEW, + // 182 => KeyCode::REDO, + 183 => KeyCode::F13, + 184 => KeyCode::F14, + 185 => KeyCode::F15, + 186 => KeyCode::F16, + 187 => KeyCode::F17, + 188 => KeyCode::F18, + 189 => KeyCode::F19, + 190 => KeyCode::F20, + 191 => KeyCode::F21, + 192 => KeyCode::F22, + 193 => KeyCode::F23, + 194 => KeyCode::F24, + // 200 => KeyCode::PLAYCD, + // 201 => KeyCode::PAUSECD, + // 202 => KeyCode::PROG3, + // 203 => KeyCode::PROG4, + // 204 => KeyCode::DASHBOARD, + // 205 => KeyCode::SUSPEND, + // 206 => KeyCode::CLOSE, + // 207 => KeyCode::PLAY, + // 208 => KeyCode::FASTFORWARD, + // 209 => KeyCode::BASSBOOST, + // 210 => KeyCode::PRINT, + // 211 => KeyCode::HP, + // 212 => KeyCode::CAMERA, + // 213 => KeyCode::SOUND, + // 214 => KeyCode::QUESTION, + // 215 => KeyCode::EMAIL, + // 216 => KeyCode::CHAT, + // 217 => KeyCode::SEARCH, + // 218 => KeyCode::CONNECT, + // 219 => KeyCode::FINANCE, + // 220 => KeyCode::SPORT, + // 221 => KeyCode::SHOP, + // 222 => KeyCode::ALTERASE, + // 223 => KeyCode::CANCEL, + // 224 => KeyCode::BRIGHTNESSDOW, + // 225 => KeyCode::BRIGHTNESSU, + // 226 => KeyCode::MEDIA, + // 227 => KeyCode::SWITCHVIDEOMODE, + // 228 => KeyCode::KBDILLUMTOGGLE, + // 229 => KeyCode::KBDILLUMDOWN, + // 230 => KeyCode::KBDILLUMUP, + // 231 => KeyCode::SEND, + // 232 => KeyCode::REPLY, + // 233 => KeyCode::FORWARDMAIL, + // 234 => KeyCode::SAVE, + // 235 => KeyCode::DOCUMENTS, + // 236 => KeyCode::BATTERY, + // 237 => KeyCode::BLUETOOTH, + // 238 => KeyCode::WLAN, + // 239 => KeyCode::UWB, + 240 => KeyCode::Unidentified(NativeKeyCode::Unidentified), + // 241 => KeyCode::VIDEO_NEXT, + // 242 => KeyCode::VIDEO_PREV, + // 243 => KeyCode::BRIGHTNESS_CYCLE, + // 244 => KeyCode::BRIGHTNESS_AUTO, + _ => KeyCode::Unidentified(NativeKeyCode::XKB(rawkey)), + } +} -// keysyms::XKB_KEY_BackSpace => Some(Key::Back), -// keysyms::XKB_KEY_Return => Some(Key::Return), -// keysyms::XKB_KEY_space => Some(Key::Space), +pub fn keysym_to_key(keysym: u32) -> Key<'static> { + use sctk::seat::keyboard::keysyms; + match keysym { + // // Numbers. + // // keysyms::XKB_KEY_1 => Some(Key::Character("1")), + // // keysyms::XKB_KEY_2 => Some(Key::Character("2")), + // // keysyms::XKB_KEY_3 => Some(Key::Character("3")), + // // keysyms::XKB_KEY_4 => Some(Key::Character("4")), + // // keysyms::XKB_KEY_5 => Some(Key::Character("5")), + // // keysyms::XKB_KEY_6 => Some(Key::Character("6")), + // // keysyms::XKB_KEY_7 => Some(Key::Character("7")), + // // keysyms::XKB_KEY_8 => Some(Key::Character("8")), + // // keysyms::XKB_KEY_9 => Some(Key::Character("9")), + // // keysyms::XKB_KEY_0 => Some(Key::Character("0")), + // // Letters. + // // keysyms::XKB_KEY_A => Some(Key::Character("A")), + // // keysyms::XKB_KEY_a => Some(Key::Character("a")), + // // keysyms::XKB_KEY_B => Some(Key::Character("B")), + // // keysyms::XKB_KEY_b => Some(Key::Character("b")), + // // keysyms::XKB_KEY_C => Some(Key::Character("C")), + // // keysyms::XKB_KEY_c => Some(Key::Character("c")), + // // keysyms::XKB_KEY_D => Some(Key::Character("D")), + // // keysyms::XKB_KEY_d => Some(Key::Character("d")), + // // keysyms::XKB_KEY_E => Some(Key::Character("E")), + // // keysyms::XKB_KEY_e => Some(Key::Character("e")), + // // keysyms::XKB_KEY_F => Some(Key::Character("F")), + // // keysyms::XKB_KEY_f => Some(Key::Character("f")), + // // keysyms::XKB_KEY_G => Some(Key::Character("G")), + // // keysyms::XKB_KEY_g => Some(Key::Character("g")), + // // keysyms::XKB_KEY_H => Some(Key::Character("H")), + // // keysyms::XKB_KEY_h => Some(Key::Character("h")), + // // keysyms::XKB_KEY_I => Some(Key::Character("I")), + // // keysyms::XKB_KEY_i => Some(Key::Character("i")), + // // keysyms::XKB_KEY_J => Some(Key::Character("J")), + // // keysyms::XKB_KEY_j => Some(Key::Character("j")), + // // keysyms::XKB_KEY_K => Some(Key::Character("K")), + // // keysyms::XKB_KEY_k => Some(Key::Character("k")), + // // keysyms::XKB_KEY_L => Some(Key::Character("L")), + // // keysyms::XKB_KEY_l => Some(Key::Character("l")), + // // keysyms::XKB_KEY_M => Some(Key::Character("M")), + // // keysyms::XKB_KEY_m => Some(Key::Character("m")), + // // keysyms::XKB_KEY_N => Some(Key::Character("N")), + // // keysyms::XKB_KEY_n => Some(Key::Character("n")), + // // keysyms::XKB_KEY_O => Some(Key::Character("O")), + // // keysyms::XKB_KEY_o => Some(Key::Character("o")), + // // keysyms::XKB_KEY_P => Some(Key::Character("P")), + // // keysyms::XKB_KEY_p => Some(Key::Character("p")), + // // keysyms::XKB_KEY_Q => Some(Key::Character("Q")), + // // keysyms::XKB_KEY_q => Some(Key::Character("q")), + // // keysyms::XKB_KEY_R => Some(Key::Character("R")), + // // keysyms::XKB_KEY_r => Some(Key::Character("r")), + // // keysyms::XKB_KEY_S => Some(Key::Character("S")), + // // keysyms::XKB_KEY_s => Some(Key::Character("s")), + // // keysyms::XKB_KEY_T => Some(Key::Character("T")), + // // keysyms::XKB_KEY_t => Some(Key::Character("t")), + // // keysyms::XKB_KEY_U => Some(Key::Character("U")), + // // keysyms::XKB_KEY_u => Some(Key::Character("u")), + // // keysyms::XKB_KEY_V => Some(Key::Character("V")), + // // keysyms::XKB_KEY_v => Some(Key::Character("v")), + // // keysyms::XKB_KEY_W => Some(Key::Character("W")), + // // keysyms::XKB_KEY_w => Some(Key::Character("w")), + // // keysyms::XKB_KEY_X => Some(Key::Character("X")), + // // keysyms::XKB_KEY_x => Some(Key::Character("x")), + // // keysyms::XKB_KEY_Y => Some(Key::Character("Y")), + // // keysyms::XKB_KEY_y => Some(Key::Character("y")), + // // keysyms::XKB_KEY_Z => Some(Key::Character("Z")), + // // keysyms::XKB_KEY_z => Some(Key::Character("z")), + // // Escape. + // keysyms::XKB_KEY_Escape => Some(Key::Escape), + // // Function keys. + // keysyms::XKB_KEY_F1 => Some(Key::F1), + // keysyms::XKB_KEY_F2 => Some(Key::F2), + // keysyms::XKB_KEY_F3 => Some(Key::F3), + // keysyms::XKB_KEY_F4 => Some(Key::F4), + // keysyms::XKB_KEY_F5 => Some(Key::F5), + // keysyms::XKB_KEY_F6 => Some(Key::F6), + // keysyms::XKB_KEY_F7 => Some(Key::F7), + // keysyms::XKB_KEY_F8 => Some(Key::F8), + // keysyms::XKB_KEY_F9 => Some(Key::F9), + // keysyms::XKB_KEY_F10 => Some(Key::F10), + // keysyms::XKB_KEY_F11 => Some(Key::F11), + // keysyms::XKB_KEY_F12 => Some(Key::F12), + // keysyms::XKB_KEY_F13 => Some(Key::F13), + // keysyms::XKB_KEY_F14 => Some(Key::F14), + // keysyms::XKB_KEY_F15 => Some(Key::F15), + // keysyms::XKB_KEY_F16 => Some(Key::F16), + // keysyms::XKB_KEY_F17 => Some(Key::F17), + // keysyms::XKB_KEY_F18 => Some(Key::F18), + // keysyms::XKB_KEY_F19 => Some(Key::F19), + // keysyms::XKB_KEY_F20 => Some(Key::F20), + // keysyms::XKB_KEY_F21 => Some(Key::F21), + // keysyms::XKB_KEY_F22 => Some(Key::F22), + // keysyms::XKB_KEY_F23 => Some(Key::F23), + // keysyms::XKB_KEY_F24 => Some(Key::F24), + // keysyms::XKB_KEY_F25 => Some(Key::F25), + // keysyms::XKB_KEY_F26 => Some(Key::F26), + // keysyms::XKB_KEY_F27 => Some(Key::F27), + // keysyms::XKB_KEY_F28 => Some(Key::F28), + // keysyms::XKB_KEY_F29 => Some(Key::F29), + // keysyms::XKB_KEY_F30 => Some(Key::F30), + // keysyms::XKB_KEY_F31 => Some(Key::F31), + // keysyms::XKB_KEY_F32 => Some(Key::F32), + // keysyms::XKB_KEY_F33 => Some(Key::F33), + // keysyms::XKB_KEY_F34 => Some(Key::F34), + // keysyms::XKB_KEY_F35 => Some(Key::F35), + // // Flow control. + // keysyms::XKB_KEY_Print => Some(Key::PrintScreen), + // keysyms::XKB_KEY_Scroll_Lock => Some(Key::ScrollLock), + // keysyms::XKB_KEY_Pause => Some(Key::Pause), + // keysyms::XKB_KEY_Insert => Some(Key::Insert), + // keysyms::XKB_KEY_Home => Some(Key::Home), + // keysyms::XKB_KEY_Delete => Some(Key::Delete), + // keysyms::XKB_KEY_End => Some(Key::End), + // keysyms::XKB_KEY_Page_Down => Some(Key::PageDown), + // keysyms::XKB_KEY_Page_Up => Some(Key::PageUp), + // // Arrows. + // keysyms::XKB_KEY_Left => Some(Key::Left), + // keysyms::XKB_KEY_Up => Some(Key::Up), + // keysyms::XKB_KEY_Right => Some(Key::Right), + // keysyms::XKB_KEY_Down => Some(Key::Down), -// keysyms::XKB_KEY_Multi_key => Some(Key::Compose), -// keysyms::XKB_KEY_caret => Some(Key::Caret), + // keysyms::XKB_KEY_BackSpace => Some(Key::Back), + // keysyms::XKB_KEY_Return => Some(Key::Return), + // keysyms::XKB_KEY_space => Some(Key::Space), -// // Keypad. -// keysyms::XKB_KEY_Num_Lock => Some(Key::Numlock), -// keysyms::XKB_KEY_KP_0 => Some(Key::Numpad0), -// keysyms::XKB_KEY_KP_1 => Some(Key::Numpad1), -// keysyms::XKB_KEY_KP_2 => Some(Key::Numpad2), -// keysyms::XKB_KEY_KP_3 => Some(Key::Numpad3), -// keysyms::XKB_KEY_KP_4 => Some(Key::Numpad4), -// keysyms::XKB_KEY_KP_5 => Some(Key::Numpad5), -// keysyms::XKB_KEY_KP_6 => Some(Key::Numpad6), -// keysyms::XKB_KEY_KP_7 => Some(Key::Numpad7), -// keysyms::XKB_KEY_KP_8 => Some(Key::Numpad8), -// keysyms::XKB_KEY_KP_9 => Some(Key::Numpad9), -// // Misc. -// // => Some(Key::AbntC1), -// // => Some(Key::AbntC2), -// keysyms::XKB_KEY_plus => Some(Key::Plus), -// keysyms::XKB_KEY_apostrophe => Some(Key::Apostrophe), -// // => Some(Key::Apps), -// keysyms::XKB_KEY_at => Some(Key::At), -// // => Some(Key::Ax), -// keysyms::XKB_KEY_backslash => Some(Key::Backslash), -// keysyms::XKB_KEY_XF86Calculator => Some(Key::Calculator), -// // => Some(Key::Capital), -// keysyms::XKB_KEY_colon => Some(Key::Colon), -// keysyms::XKB_KEY_comma => Some(Key::Comma), -// // => Some(Key::Convert), -// keysyms::XKB_KEY_equal => Some(Key::Equals), -// keysyms::XKB_KEY_grave => Some(Key::Grave), -// // => Some(Key::Kana), -// keysyms::XKB_KEY_Kanji => Some(Key::Kanji), -// keysyms::XKB_KEY_Alt_L => Some(Key::LAlt), -// keysyms::XKB_KEY_bracketleft => Some(Key::LBracket), -// keysyms::XKB_KEY_Control_L => Some(Key::LControl), -// keysyms::XKB_KEY_Shift_L => Some(Key::LShift), -// keysyms::XKB_KEY_Super_L => Some(Key::LWin), -// keysyms::XKB_KEY_XF86Mail => Some(Key::Mail), -// // => Some(Key::MediaSelect), -// // => Some(Key::MediaStop), -// keysyms::XKB_KEY_minus => Some(Key::Minus), -// keysyms::XKB_KEY_asterisk => Some(Key::Asterisk), -// keysyms::XKB_KEY_XF86AudioMute => Some(Key::Mute), -// // => Some(Key::MyComputer), -// keysyms::XKB_KEY_XF86AudioNext => Some(Key::NextTrack), -// // => Some(Key::NoConvert), -// keysyms::XKB_KEY_KP_Separator => Some(Key::NumpadComma), -// keysyms::XKB_KEY_KP_Enter => Some(Key::NumpadEnter), -// keysyms::XKB_KEY_KP_Equal => Some(Key::NumpadEquals), -// keysyms::XKB_KEY_KP_Add => Some(Key::NumpadAdd), -// keysyms::XKB_KEY_KP_Subtract => Some(Key::NumpadSubtract), -// keysyms::XKB_KEY_KP_Multiply => Some(Key::NumpadMultiply), -// keysyms::XKB_KEY_KP_Divide => Some(Key::NumpadDivide), -// keysyms::XKB_KEY_KP_Decimal => Some(Key::NumpadDecimal), -// keysyms::XKB_KEY_KP_Page_Up => Some(Key::PageUp), -// keysyms::XKB_KEY_KP_Page_Down => Some(Key::PageDown), -// keysyms::XKB_KEY_KP_Home => Some(Key::Home), -// keysyms::XKB_KEY_KP_End => Some(Key::End), -// keysyms::XKB_KEY_KP_Left => Some(Key::Left), -// keysyms::XKB_KEY_KP_Up => Some(Key::Up), -// keysyms::XKB_KEY_KP_Right => Some(Key::Right), -// keysyms::XKB_KEY_KP_Down => Some(Key::Down), -// // => Some(Key::OEM102), -// keysyms::XKB_KEY_period => Some(Key::Period), -// // => Some(Key::Playpause), -// keysyms::XKB_KEY_XF86PowerOff => Some(Key::Power), -// keysyms::XKB_KEY_XF86AudioPrev => Some(Key::PrevTrack), -// keysyms::XKB_KEY_Alt_R => Some(Key::RAlt), -// keysyms::XKB_KEY_bracketright => Some(Key::RBracket), -// keysyms::XKB_KEY_Control_R => Some(Key::RControl), -// keysyms::XKB_KEY_Shift_R => Some(Key::RShift), -// keysyms::XKB_KEY_Super_R => Some(Key::RWin), -// keysyms::XKB_KEY_semicolon => Some(Key::Semicolon), -// keysyms::XKB_KEY_slash => Some(Key::Slash), -// keysyms::XKB_KEY_XF86Sleep => Some(Key::Sleep), -// // => Some(Key::Stop), -// // => Some(Key::Sysrq), -// keysyms::XKB_KEY_Tab => Some(Key::Tab), -// keysyms::XKB_KEY_ISO_Left_Tab => Some(Key::Tab), -// keysyms::XKB_KEY_underscore => Some(Key::Underline), -// // => Some(Key::Unlabeled), -// keysyms::XKB_KEY_XF86AudioLowerVolume => Some(Key::VolumeDown), -// keysyms::XKB_KEY_XF86AudioRaiseVolume => Some(Key::VolumeUp), -// // => Some(Key::Wake), -// // => Some(Key::Webback), -// // => Some(Key::WebFavorites), -// // => Some(Key::WebForward), -// // => Some(Key::WebHome), -// // => Some(Key::WebRefresh), -// // => Some(Key::WebSearch), -// // => Some(Key::WebStop), -// keysyms::XKB_KEY_yen => Some(Key::Yen), -// keysyms::XKB_KEY_XF86Copy => Some(Key::Copy), -// keysyms::XKB_KEY_XF86Paste => Some(Key::Paste), -// keysyms::XKB_KEY_XF86Cut => Some(Key::Cut), -// // Fallback. -// _ => None, -// } -// } + // keysyms::XKB_KEY_Multi_key => Some(Key::Compose), + // keysyms::XKB_KEY_caret => Some(Key::Caret), + + // // Keypad. + // keysyms::XKB_KEY_Num_Lock => Some(Key::Numlock), + // keysyms::XKB_KEY_KP_0 => Some(Key::Numpad0), + // keysyms::XKB_KEY_KP_1 => Some(Key::Numpad1), + // keysyms::XKB_KEY_KP_2 => Some(Key::Numpad2), + // keysyms::XKB_KEY_KP_3 => Some(Key::Numpad3), + // keysyms::XKB_KEY_KP_4 => Some(Key::Numpad4), + // keysyms::XKB_KEY_KP_5 => Some(Key::Numpad5), + // keysyms::XKB_KEY_KP_6 => Some(Key::Numpad6), + // keysyms::XKB_KEY_KP_7 => Some(Key::Numpad7), + // keysyms::XKB_KEY_KP_8 => Some(Key::Numpad8), + // keysyms::XKB_KEY_KP_9 => Some(Key::Numpad9), + // // Misc. + // // => Some(Key::AbntC1), + // // => Some(Key::AbntC2), + // keysyms::XKB_KEY_plus => Some(Key::Plus), + // keysyms::XKB_KEY_apostrophe => Some(Key::Apostrophe), + // // => Some(Key::Apps), + // keysyms::XKB_KEY_at => Some(Key::At), + // // => Some(Key::Ax), + // keysyms::XKB_KEY_backslash => Some(Key::Backslash), + // keysyms::XKB_KEY_XF86Calculator => Some(Key::Calculator), + // // => Some(Key::Capital), + // keysyms::XKB_KEY_colon => Some(Key::Colon), + // keysyms::XKB_KEY_comma => Some(Key::Comma), + // // => Some(Key::Convert), + // keysyms::XKB_KEY_equal => Some(Key::Equals), + // keysyms::XKB_KEY_grave => Some(Key::Grave), + // // => Some(Key::Kana), + // keysyms::XKB_KEY_Kanji => Some(Key::Kanji), + // keysyms::XKB_KEY_Alt_L => Some(Key::LAlt), + // keysyms::XKB_KEY_bracketleft => Some(Key::LBracket), + // keysyms::XKB_KEY_Control_L => Some(Key::LControl), + // keysyms::XKB_KEY_Shift_L => Some(Key::LShift), + // keysyms::XKB_KEY_Super_L => Some(Key::LWin), + // keysyms::XKB_KEY_XF86Mail => Some(Key::Mail), + // // => Some(Key::MediaSelect), + // // => Some(Key::MediaStop), + // keysyms::XKB_KEY_minus => Some(Key::Minus), + // keysyms::XKB_KEY_asterisk => Some(Key::Asterisk), + // keysyms::XKB_KEY_XF86AudioMute => Some(Key::Mute), + // // => Some(Key::MyComputer), + // keysyms::XKB_KEY_XF86AudioNext => Some(Key::NextTrack), + // // => Some(Key::NoConvert), + // keysyms::XKB_KEY_KP_Separator => Some(Key::NumpadComma), + // keysyms::XKB_KEY_KP_Enter => Some(Key::NumpadEnter), + // keysyms::XKB_KEY_KP_Equal => Some(Key::NumpadEquals), + // keysyms::XKB_KEY_KP_Add => Some(Key::NumpadAdd), + // keysyms::XKB_KEY_KP_Subtract => Some(Key::NumpadSubtract), + // keysyms::XKB_KEY_KP_Multiply => Some(Key::NumpadMultiply), + // keysyms::XKB_KEY_KP_Divide => Some(Key::NumpadDivide), + // keysyms::XKB_KEY_KP_Decimal => Some(Key::NumpadDecimal), + // keysyms::XKB_KEY_KP_Page_Up => Some(Key::PageUp), + // keysyms::XKB_KEY_KP_Page_Down => Some(Key::PageDown), + // keysyms::XKB_KEY_KP_Home => Some(Key::Home), + // keysyms::XKB_KEY_KP_End => Some(Key::End), + // keysyms::XKB_KEY_KP_Left => Some(Key::Left), + // keysyms::XKB_KEY_KP_Up => Some(Key::Up), + // keysyms::XKB_KEY_KP_Right => Some(Key::Right), + // keysyms::XKB_KEY_KP_Down => Some(Key::Down), + // // => Some(Key::OEM102), + // keysyms::XKB_KEY_period => Some(Key::Period), + // // => Some(Key::Playpause), + // keysyms::XKB_KEY_XF86PowerOff => Some(Key::Power), + // keysyms::XKB_KEY_XF86AudioPrev => Some(Key::PrevTrack), + // keysyms::XKB_KEY_Alt_R => Some(Key::RAlt), + // keysyms::XKB_KEY_bracketright => Some(Key::RBracket), + // keysyms::XKB_KEY_Control_R => Some(Key::RControl), + // keysyms::XKB_KEY_Shift_R => Some(Key::RShift), + // keysyms::XKB_KEY_Super_R => Some(Key::RWin), + // keysyms::XKB_KEY_semicolon => Some(Key::Semicolon), + // keysyms::XKB_KEY_slash => Some(Key::Slash), + // keysyms::XKB_KEY_XF86Sleep => Some(Key::Sleep), + // // => Some(Key::Stop), + // // => Some(Key::Sysrq), + // keysyms::XKB_KEY_Tab => Some(Key::Tab), + // keysyms::XKB_KEY_ISO_Left_Tab => Some(Key::Tab), + // keysyms::XKB_KEY_underscore => Some(Key::Underline), + // // => Some(Key::Unlabeled), + // keysyms::XKB_KEY_XF86AudioLowerVolume => Some(Key::VolumeDown), + // keysyms::XKB_KEY_XF86AudioRaiseVolume => Some(Key::VolumeUp), + // // => Some(Key::Wake), + // // => Some(Key::Webback), + // // => Some(Key::WebFavorites), + // // => Some(Key::WebForward), + // // => Some(Key::WebHome), + // // => Some(Key::WebRefresh), + // // => Some(Key::WebSearch), + // // => Some(Key::WebStop), + // keysyms::XKB_KEY_yen => Some(Key::Yen), + // keysyms::XKB_KEY_XF86Copy => Some(Key::Copy), + // keysyms::XKB_KEY_XF86Paste => Some(Key::Paste), + // keysyms::XKB_KEY_XF86Cut => Some(Key::Cut), + // // Fallback. + _ => Key::Unidentified(NativeKeyCode::Unidentified), + } +} From 488e65dadde0e633d66d76c08d61cfb56c49b496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Mon, 29 Mar 2021 01:49:30 +0200 Subject: [PATCH 06/53] Add some keysym mappings and move the keymap.rs file --- Cargo.toml | 1 + src/platform_impl/linux/common/keymap.rs | 685 ++++++++++++++++++ src/platform_impl/linux/common/mod.rs | 1 + src/platform_impl/linux/mod.rs | 3 + .../linux/wayland/seat/keyboard/handlers.rs | 3 +- .../linux/wayland/seat/keyboard/keymap.rs | 477 ------------ .../linux/wayland/seat/keyboard/mod.rs | 1 - 7 files changed, 692 insertions(+), 479 deletions(-) create mode 100644 src/platform_impl/linux/common/keymap.rs create mode 100644 src/platform_impl/linux/common/mod.rs delete mode 100644 src/platform_impl/linux/wayland/seat/keyboard/keymap.rs diff --git a/Cargo.toml b/Cargo.toml index d65620d493..eb6815c1f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,7 @@ x11-dl = { version = "2.18.5", optional = true } percent-encoding = { version = "2.0", optional = true } parking_lot = { version = "0.11.0", optional = true } libc = "0.2.64" +xkbcommon = "0.4.0" [target.'cfg(target_arch = "wasm32")'.dependencies.web_sys] package = "web-sys" diff --git a/src/platform_impl/linux/common/keymap.rs b/src/platform_impl/linux/common/keymap.rs new file mode 100644 index 0000000000..eeccf65a97 --- /dev/null +++ b/src/platform_impl/linux/common/keymap.rs @@ -0,0 +1,685 @@ +//! Convert Wayland keys to winit keys. + +use crate::keyboard::{Key, KeyCode, KeyLocation, NativeKeyCode}; + +// TODO: Do another pass on all of this + +pub fn rawkey_to_keycode(rawkey: u32) -> KeyCode { + // The keycode values are taken from linux/include/uapi/linux/input-event-codes.h, as + // libxkbcommon's documentation indicates that the keycode values we're getting from it are + // defined by the Linux kernel. If Winit programs end up being run on other Unix-likes which + // also use libxkbcommon, then I dearly hope the keycode values mean the same thing. + // + // Some of the keycodes are likely superfluous for our purposes, and some are ones which are + // difficult to test the correctness of, or discover the purpose of. Because of this, they've + // either been commented out here, or not included at all. + // + // TODO: There are probably a couple more unproblematic keycodes to map here. + match rawkey { + 0 => KeyCode::Unidentified(NativeKeyCode::XKB(0)), // TODO: Is `NativeKeyCode::Unidentified` better? + 1 => KeyCode::Escape, + 2 => KeyCode::Digit1, + 3 => KeyCode::Digit2, + 4 => KeyCode::Digit3, + 5 => KeyCode::Digit4, + 6 => KeyCode::Digit5, + 7 => KeyCode::Digit6, + 8 => KeyCode::Digit7, + 9 => KeyCode::Digit8, + 10 => KeyCode::Digit9, + 11 => KeyCode::Digit0, + 12 => KeyCode::Minus, + 13 => KeyCode::Equal, + 14 => KeyCode::Backspace, + 15 => KeyCode::Tab, + 16 => KeyCode::KeyQ, + 17 => KeyCode::KeyW, + 18 => KeyCode::KeyE, + 19 => KeyCode::KeyR, + 20 => KeyCode::KeyT, + 21 => KeyCode::KeyY, + 22 => KeyCode::KeyU, + 23 => KeyCode::KeyI, + 24 => KeyCode::KeyO, + 25 => KeyCode::KeyP, + 26 => KeyCode::BracketLeft, + 27 => KeyCode::BracketRight, + 28 => KeyCode::Enter, + 29 => KeyCode::ControlLeft, + 30 => KeyCode::KeyA, + 31 => KeyCode::KeyS, + 32 => KeyCode::KeyD, + 33 => KeyCode::KeyF, + 34 => KeyCode::KeyG, + 35 => KeyCode::KeyH, + 36 => KeyCode::KeyJ, + 37 => KeyCode::KeyK, + 38 => KeyCode::KeyL, + 39 => KeyCode::Semicolon, + 40 => KeyCode::Quote, + 41 => KeyCode::Backquote, + 42 => KeyCode::ShiftLeft, + 43 => KeyCode::Backslash, + 44 => KeyCode::KeyZ, + 45 => KeyCode::KeyX, + 46 => KeyCode::KeyC, + 47 => KeyCode::KeyV, + 48 => KeyCode::KeyB, + 49 => KeyCode::KeyN, + 50 => KeyCode::KeyM, + 51 => KeyCode::Comma, + 52 => KeyCode::Period, + 53 => KeyCode::Slash, + 54 => KeyCode::ShiftRight, + 55 => KeyCode::NumpadMultiply, + 56 => KeyCode::AltLeft, + 57 => KeyCode::Space, + 58 => KeyCode::CapsLock, + 59 => KeyCode::F1, + 60 => KeyCode::F2, + 61 => KeyCode::F3, + 62 => KeyCode::F4, + 63 => KeyCode::F5, + 64 => KeyCode::F6, + 65 => KeyCode::F7, + 66 => KeyCode::F8, + 67 => KeyCode::F9, + 68 => KeyCode::F10, + 69 => KeyCode::NumLock, + 70 => KeyCode::ScrollLock, + 71 => KeyCode::Numpad7, + 72 => KeyCode::Numpad8, + 73 => KeyCode::Numpad9, + 74 => KeyCode::NumpadSubtract, + 75 => KeyCode::Numpad4, + 76 => KeyCode::Numpad4, + 77 => KeyCode::Numpad6, + 78 => KeyCode::NumpadAdd, + 79 => KeyCode::Numpad1, + 80 => KeyCode::Numpad2, + 81 => KeyCode::Numpad3, + 82 => KeyCode::Numpad0, + 83 => KeyCode::NumpadDecimal, + 85 => KeyCode::Lang5, + 86 => KeyCode::IntlBackslash, + 87 => KeyCode::F11, + 88 => KeyCode::F12, + 89 => KeyCode::IntlRo, + 90 => KeyCode::Lang3, + 91 => KeyCode::Lang4, + 92 => KeyCode::Convert, + 93 => KeyCode::KanaMode, + 94 => KeyCode::NonConvert, + // 95 => KeyCode::KPJPCOMMA, + 96 => KeyCode::NumpadEnter, + 97 => KeyCode::ControlRight, + 98 => KeyCode::NumpadDivide, + 99 => KeyCode::PrintScreen, + 100 => KeyCode::AltRight, + // 101 => KeyCode::LINEFEED, + 102 => KeyCode::Home, + 103 => KeyCode::ArrowUp, + 104 => KeyCode::PageUp, + 105 => KeyCode::ArrowLeft, + 106 => KeyCode::ArrowRight, + 107 => KeyCode::End, + 108 => KeyCode::ArrowDown, + 109 => KeyCode::PageDown, + 110 => KeyCode::Insert, + 111 => KeyCode::Delete, + // 112 => KeyCode::MACRO, + 113 => KeyCode::AudioVolumeMute, + 114 => KeyCode::AudioVolumeDown, + 115 => KeyCode::AudioVolumeUp, + // 116 => KeyCode::POWER, + 117 => KeyCode::NumpadEqual, + // 118 => KeyCode::KPPLUSMINUS, + 119 => KeyCode::Pause, + // 120 => KeyCode::SCALE, + 121 => KeyCode::NumpadComma, + 122 => KeyCode::Lang1, + 123 => KeyCode::Lang2, + 124 => KeyCode::IntlYen, + 125 => KeyCode::SuperLeft, + 126 => KeyCode::SuperRight, + 127 => KeyCode::ContextMenu, + // 128 => KeyCode::STOP, + // 129 => KeyCode::AGAIN, + // 130 => KeyCode::PROPS, + // 131 => KeyCode::UNDO, + // 132 => KeyCode::FRONT, + // 133 => KeyCode::COPY, + // 134 => KeyCode::OPEN, + // 135 => KeyCode::PASTE, + // 136 => KeyCode::FIND, + // 137 => KeyCode::CUT, + // 138 => KeyCode::HELP, + // 139 => KeyCode::MENU, + // 140 => KeyCode::CALC, + // 141 => KeyCode::SETUP, + // 142 => KeyCode::SLEEP, + // 143 => KeyCode::WAKEUP, + // 144 => KeyCode::FILE, + // 145 => KeyCode::SENDFILE, + // 146 => KeyCode::DELETEFILE, + // 147 => KeyCode::XFER, + // 148 => KeyCode::PROG1, + // 149 => KeyCode::PROG2, + // 150 => KeyCode::WWW, + // 151 => KeyCode::MSDOS, + // 152 => KeyCode::COFFEE, + // 153 => KeyCode::ROTATE_DISPLAY, + // 154 => KeyCode::CYCLEWINDOWS, + // 155 => KeyCode::MAIL, + // 156 => KeyCode::BOOKMARKS, + // 157 => KeyCode::COMPUTER, + // 158 => KeyCode::BACK, + // 159 => KeyCode::FORWARD, + // 160 => KeyCode::CLOSECD, + // 161 => KeyCode::EJECTCD, + // 162 => KeyCode::EJECTCLOSECD, + 163 => KeyCode::MediaTrackNext, + 164 => KeyCode::MediaPlayPause, + 165 => KeyCode::MediaTrackPrevious, + 166 => KeyCode::MediaStop, + // 167 => KeyCode::RECORD, + // 168 => KeyCode::REWIND, + // 169 => KeyCode::PHONE, + // 170 => KeyCode::ISO, + // 171 => KeyCode::CONFIG, + // 172 => KeyCode::HOMEPAGE, + // 173 => KeyCode::REFRESH, + // 174 => KeyCode::EXIT, + // 175 => KeyCode::MOVE, + // 176 => KeyCode::EDIT, + // 177 => KeyCode::SCROLLUP, + // 178 => KeyCode::SCROLLDOWN, + // 179 => KeyCode::KPLEFTPAREN, + // 180 => KeyCode::KPRIGHTPAREN, + // 181 => KeyCode::NEW, + // 182 => KeyCode::REDO, + 183 => KeyCode::F13, + 184 => KeyCode::F14, + 185 => KeyCode::F15, + 186 => KeyCode::F16, + 187 => KeyCode::F17, + 188 => KeyCode::F18, + 189 => KeyCode::F19, + 190 => KeyCode::F20, + 191 => KeyCode::F21, + 192 => KeyCode::F22, + 193 => KeyCode::F23, + 194 => KeyCode::F24, + // 200 => KeyCode::PLAYCD, + // 201 => KeyCode::PAUSECD, + // 202 => KeyCode::PROG3, + // 203 => KeyCode::PROG4, + // 204 => KeyCode::DASHBOARD, + // 205 => KeyCode::SUSPEND, + // 206 => KeyCode::CLOSE, + // 207 => KeyCode::PLAY, + // 208 => KeyCode::FASTFORWARD, + // 209 => KeyCode::BASSBOOST, + // 210 => KeyCode::PRINT, + // 211 => KeyCode::HP, + // 212 => KeyCode::CAMERA, + // 213 => KeyCode::SOUND, + // 214 => KeyCode::QUESTION, + // 215 => KeyCode::EMAIL, + // 216 => KeyCode::CHAT, + // 217 => KeyCode::SEARCH, + // 218 => KeyCode::CONNECT, + // 219 => KeyCode::FINANCE, + // 220 => KeyCode::SPORT, + // 221 => KeyCode::SHOP, + // 222 => KeyCode::ALTERASE, + // 223 => KeyCode::CANCEL, + // 224 => KeyCode::BRIGHTNESSDOW, + // 225 => KeyCode::BRIGHTNESSU, + // 226 => KeyCode::MEDIA, + // 227 => KeyCode::SWITCHVIDEOMODE, + // 228 => KeyCode::KBDILLUMTOGGLE, + // 229 => KeyCode::KBDILLUMDOWN, + // 230 => KeyCode::KBDILLUMUP, + // 231 => KeyCode::SEND, + // 232 => KeyCode::REPLY, + // 233 => KeyCode::FORWARDMAIL, + // 234 => KeyCode::SAVE, + // 235 => KeyCode::DOCUMENTS, + // 236 => KeyCode::BATTERY, + // 237 => KeyCode::BLUETOOTH, + // 238 => KeyCode::WLAN, + // 239 => KeyCode::UWB, + 240 => KeyCode::Unidentified(NativeKeyCode::Unidentified), + // 241 => KeyCode::VIDEO_NEXT, + // 242 => KeyCode::VIDEO_PREV, + // 243 => KeyCode::BRIGHTNESS_CYCLE, + // 244 => KeyCode::BRIGHTNESS_AUTO, + // 245 => KeyCode::DISPLAY_OFF, + // 246 => KeyCode::WWAN, + // 247 => KeyCode::RFKILL, + // 248 => KeyCode::KEY_MICMUTE, + _ => KeyCode::Unidentified(NativeKeyCode::XKB(rawkey)), + } +} + +pub fn keysym_to_key(keysym: u32) -> Key<'static> { + use xkbcommon::xkb; + match keysym { + // TTY function keys + xkb::KEY_BackSpace => Key::Backspace, + xkb::KEY_Tab => Key::Tab, + // xkb::KEY_Linefeed => Key::Linefeed, + xkb::KEY_Clear => Key::Clear, + xkb::KEY_Return => Key::Enter, + // xkb::KEY_Pause => Key::Pause, + xkb::KEY_Scroll_Lock => Key::ScrollLock, + xkb::KEY_Sys_Req => Key::PrintScreen, + xkb::KEY_Escape => Key::Escape, + xkb::KEY_Delete => Key::Delete, + + // IME keys + xkb::KEY_Multi_key => Key::Compose, + xkb::KEY_Codeinput => Key::CodeInput, + xkb::KEY_SingleCandidate => Key::SingleCandidate, + xkb::KEY_MultipleCandidate => Key::AllCandidates, + xkb::KEY_PreviousCandidate => Key::PreviousCandidate, + + // Japanese keys + xkb::KEY_Kanji => Key::KanjiMode, + xkb::KEY_Muhenkan => Key::NonConvert, + xkb::KEY_Henkan_Mode => Key::Convert, + xkb::KEY_Romaji => Key::Romaji, + xkb::KEY_Hiragana => Key::Hiragana, + xkb::KEY_Hiragana_Katakana => Key::HiraganaKatakana, + xkb::KEY_Zenkaku => Key::Zenkaku, + xkb::KEY_Hankaku => Key::Hankaku, + xkb::KEY_Zenkaku_Hankaku => Key::ZenkakuHankaku, + // xkb::KEY_Touroku => Key::Touroku, + // xkb::KEY_Massyo => Key::Massyo, + xkb::KEY_Kana_Lock => Key::KanaMode, + // TODO: This seems a tad perverse, but I'm not really familiar with japanese keyboards. + // MDN documents this as a valid mapping, however. + // xkb::KEY_Kana_Shift => Key::KanaMode, + // TODO: Is this the correct mapping? + // xkb::KEY_Eisu_Shift => Key::Alphanumeric, + // xkb::KEY_Eisu_toggle => Key::Alphanumeric, + // NOTE: The next three items are aliases for values we've already mapped. + // xkb::KEY_Kanji_Bangou => Key::CodeInput, + // xkb::KEY_Zen_Koho => Key::AllCandidates, + // xkb::KEY_Mae_Koho => Key::PreviousCandidate, + + // Cursor control & motion + xkb::KEY_Home => Key::Home, + xkb::KEY_Left => Key::ArrowLeft, + xkb::KEY_Up => Key::ArrowUp, + xkb::KEY_Right => Key::ArrowRight, + xkb::KEY_Down => Key::ArrowDown, + // xkb::KEY_Prior => Key::Prior, + xkb::KEY_Page_Up => Key::PageUp, + // xkb::KEY_Next => Key::Next, + xkb::KEY_End => Key::End, + // xkb::KEY_Begin => Key::Begin, + + // Misc. functions + xkb::KEY_Select => Key::Select, + xkb::KEY_Print => Key::PrintScreen, + xkb::KEY_Execute => Key::Execute, + xkb::KEY_Insert => Key::Insert, + xkb::KEY_Undo => Key::Undo, + xkb::KEY_Redo => Key::Redo, + xkb::KEY_Menu => Key::ContextMenu, + xkb::KEY_Find => Key::Find, + xkb::KEY_Cancel => Key::Cancel, + xkb::KEY_Help => Key::Help, + xkb::KEY_Break => Key::Pause, + xkb::KEY_Mode_switch => Key::ModeChange, + // xkb::KEY_script_switch => Key::ModeChange, + xkb::KEY_Num_Lock => Key::NumLock, + + // Keypad keys + // xkb::KEY_KP_Space => Key::Character(" "), + xkb::KEY_KP_Tab => Key::Tab, + xkb::KEY_KP_Enter => Key::Enter, + xkb::KEY_KP_F1 => Key::F1, + xkb::KEY_KP_F2 => Key::F2, + xkb::KEY_KP_F3 => Key::F3, + xkb::KEY_KP_F4 => Key::F4, + xkb::KEY_KP_Home => Key::Home, + xkb::KEY_KP_Left => Key::ArrowLeft, + xkb::KEY_KP_Up => Key::ArrowLeft, + xkb::KEY_KP_Right => Key::ArrowRight, + xkb::KEY_KP_Down => Key::ArrowDown, + // xkb::KEY_KP_Prior => Key::Prior, + xkb::KEY_KP_Page_Up => Key::PageUp, + // xkb::KEY_KP_Next => Key::Next, + xkb::KEY_KP_Page_Down => Key::PageDown, + xkb::KEY_KP_End => Key::End, + // xkb::KEY_KP_Begin => Key::Begin, + xkb::KEY_KP_Insert => Key::Insert, + xkb::KEY_KP_Delete => Key::Delete, + // xkb::KEY_KP_Equal => Key::Equal, + // xkb::KEY_KP_Multiply => Key::Multiply, + // xkb::KEY_KP_Add => Key::Add, + // xkb::KEY_KP_Separator => Key::Separator, + // xkb::KEY_KP_Subtract => Key::Subtract, + // xkb::KEY_KP_Decimal => Key::Decimal, + // xkb::KEY_KP_Divide => Key::Divide, + + // xkb::KEY_KP_0 => Key::Character("0"), + // xkb::KEY_KP_1 => Key::Character("1"), + // xkb::KEY_KP_2 => Key::Character("2"), + // xkb::KEY_KP_3 => Key::Character("3"), + // xkb::KEY_KP_4 => Key::Character("4"), + // xkb::KEY_KP_5 => Key::Character("5"), + // xkb::KEY_KP_6 => Key::Character("6"), + // xkb::KEY_KP_7 => Key::Character("7"), + // xkb::KEY_KP_8 => Key::Character("8"), + // xkb::KEY_KP_9 => Key::Character("9"), + + // Function keys + xkb::KEY_F1 => Key::F1, + xkb::KEY_F2 => Key::F2, + xkb::KEY_F3 => Key::F3, + xkb::KEY_F4 => Key::F4, + xkb::KEY_F5 => Key::F5, + xkb::KEY_F6 => Key::F6, + xkb::KEY_F7 => Key::F7, + xkb::KEY_F8 => Key::F8, + xkb::KEY_F9 => Key::F9, + xkb::KEY_F10 => Key::F10, + xkb::KEY_F11 => Key::F11, + xkb::KEY_F12 => Key::F12, + xkb::KEY_F13 => Key::F13, + xkb::KEY_F14 => Key::F14, + xkb::KEY_F15 => Key::F15, + xkb::KEY_F16 => Key::F16, + xkb::KEY_F17 => Key::F17, + xkb::KEY_F18 => Key::F18, + xkb::KEY_F19 => Key::F19, + xkb::KEY_F20 => Key::F20, + xkb::KEY_F21 => Key::F21, + xkb::KEY_F22 => Key::F22, + xkb::KEY_F23 => Key::F23, + xkb::KEY_F24 => Key::F24, + xkb::KEY_F25 => Key::F25, + xkb::KEY_F26 => Key::F26, + xkb::KEY_F27 => Key::F27, + xkb::KEY_F28 => Key::F28, + xkb::KEY_F29 => Key::F29, + xkb::KEY_F30 => Key::F30, + xkb::KEY_F31 => Key::F31, + xkb::KEY_F32 => Key::F32, + xkb::KEY_F33 => Key::F33, + xkb::KEY_F34 => Key::F34, + xkb::KEY_F35 => Key::F35, + + // Modifiers + xkb::KEY_Shift_L => Key::Shift, + xkb::KEY_Shift_R => Key::Shift, + xkb::KEY_Control_L => Key::Control, + xkb::KEY_Control_R => Key::Control, + xkb::KEY_Caps_Lock => Key::CapsLock, + // xkb::KEY_Shift_Lock => Key::ShiftLock, + // + xkb::KEY_Meta_L => Key::Super, + xkb::KEY_Meta_R => Key::Super, + xkb::KEY_Alt_L => Key::Alt, + xkb::KEY_Alt_R => Key::Alt, + // NOTE: The key xkb calls "Meta" is called "Super" by Winit. + // xkb::KEY_Super_L => Key::Super, + // xkb::KEY_Super_R => Key::Super, + xkb::KEY_Hyper_L => Key::Hyper, + xkb::KEY_Hyper_R => Key::Hyper, + + // XKB function and modifier keys + // xkb::KEY_ISO_Lock => Key::IsoLock, + // xkb::KEY_ISO_Level2_Latch => Key::IsoLevel2Latch, + // NOTE: I'm not quite certain if mapping the next 3 values to AltGraph is correct. + // xkb::KEY_ISO_Level3_Shift => Key::AltGraph, + // xkb::KEY_ISO_Level3_Latch => Key::AltGraph, + // xkb::KEY_ISO_Level3_Lock => Key::AltGraph, + // xkb::KEY_ISO_Level5_Shift => Key::IsoLevel5Shift, + // xkb::KEY_ISO_Level5_Latch => Key::IsoLevel5Latch, + // xkb::KEY_ISO_Level5_Lock => Key::IsoLevel5Lock, + // xkb::KEY_ISO_Group_Shift => Key::IsoGroupShift, + // xkb::KEY_ISO_Group_Latch => Key::IsoGroupLatch, + // xkb::KEY_ISO_Group_Lock => Key::IsoGroupLock, + xkb::KEY_ISO_Next_Group => Key::GroupNext, + // xkb::KEY_ISO_Next_Group_Lock => Key::GroupNextLock, + xkb::KEY_ISO_Prev_Group => Key::GroupPrevious, + // xkb::KEY_ISO_Prev_Group_Lock => Key::GroupPreviousLock, + xkb::KEY_ISO_First_Group => Key::GroupFirst, + // xkb::KEY_ISO_First_Group_Lock => Key::GroupFirstLock, + xkb::KEY_ISO_Last_Group => Key::GroupLast, + // xkb::KEY_ISO_Last_Group_Lock => Key::GroupLastLock, + // + xkb::KEY_ISO_Left_Tab => Key::Tab, + // xkb::KEY_ISO_Move_Line_Up => Key::IsoMoveLineUp, + // xkb::KEY_ISO_Move_Line_Down => Key::IsoMoveLineDown, + // xkb::KEY_ISO_Partial_Line_Up => Key::IsoPartialLineUp, + // xkb::KEY_ISO_Partial_Line_Down => Key::IsoPartialLineDown, + // xkb::KEY_ISO_Partial_Space_Left => Key::IsoPartialSpaceLeft, + // xkb::KEY_ISO_Partial_Space_Right => Key::IsoPartialSpaceRight, + // xkb::KEY_ISO_Set_Margin_Left => Key::IsoSetMarginLeft, + // xkb::KEY_ISO_Set_Margin_Right => Key::IsoSetMarginRight, + // xkb::KEY_ISO_Release_Margin_Left => Key::IsoReleaseMarginLeft, + // xkb::KEY_ISO_Release_Margin_Right => Key::IsoReleaseMarginRight, + // xkb::KEY_ISO_Release_Both_Margins => Key::IsoReleaseBothMargins, + // xkb::KEY_ISO_Fast_Cursor_Left => Key::IsoFastCursorLeft, + // xkb::KEY_ISO_Fast_Cursor_Right => Key::IsoFastCursorRight, + // xkb::KEY_ISO_Fast_Cursor_Up => Key::IsoFastCursorUp, + // xkb::KEY_ISO_Fast_Cursor_Down => Key::IsoFastCursorDown, + // xkb::KEY_ISO_Continuous_Underline => Key::IsoContinuousUnderline, + // xkb::KEY_ISO_Discontinuous_Underline => Key::IsoDiscontinuousUnderline, + // xkb::KEY_ISO_Emphasize => Key::IsoEmphasize, + // xkb::KEY_ISO_Center_Object => Key::IsoCenterObject, + xkb::KEY_ISO_Enter => Key::Enter, + + // KEY_dead_grave..KEY_dead_currency + + // KEY_dead_lowline..KEY_dead_longsolidusoverlay + + // KEY_dead_a..KEY_dead_capital_schwa + + // KEY_dead_greek + + // KEY_First_Virtual_Screen..KEY_Terminate_Server + + // KEY_AccessX_Enable..KEY_AudibleBell_Enable + + // KEY_Pointer_Left..KEY_Pointer_Drag5 + + // KEY_Pointer_EnableKeys..KEY_Pointer_DfltBtnPrev + + // KEY_ch..KEY_C_H + + // 3270 terminal keys + // xkb::KEY_3270_Duplicate => Key::Duplicate, + // xkb::KEY_3270_FieldMark => Key::FieldMark, + // xkb::KEY_3270_Right2 => Key::Right2, + // xkb::KEY_3270_Left2 => Key::Left2, + // xkb::KEY_3270_BackTab => Key::BackTab, + xkb::KEY_3270_EraseEOF => Key::EraseEof, + // xkb::KEY_3270_EraseInput => Key::EraseInput, + // xkb::KEY_3270_Reset => Key::Reset, + // xkb::KEY_3270_Quit => Key::Quit, + // xkb::KEY_3270_PA1 => Key::Pa1, + // xkb::KEY_3270_PA2 => Key::Pa2, + // xkb::KEY_3270_PA3 => Key::Pa3, + // xkb::KEY_3270_Test => Key::Test, + xkb::KEY_3270_Attn => Key::Attn, + // xkb::KEY_3270_CursorBlink => Key::CursorBlink, + // xkb::KEY_3270_AltCursor => Key::AltCursor, + // xkb::KEY_3270_KeyClick => Key::KeyClick, + // xkb::KEY_3270_Jump => Key::Jump, + // xkb::KEY_3270_Ident => Key::Ident, + // xkb::KEY_3270_Rule => Key::Rule, + // xkb::KEY_3270_Copy => Key::Copy, + xkb::KEY_3270_Play => Key::Play, + // xkb::KEY_3270_Setup => Key::Setup, + // xkb::KEY_3270_Record => Key::Record, + // xkb::KEY_3270_ChangeScreen => Key::ChangeScreen, + // xkb::KEY_3270_DeleteWord => Key::DeleteWord, + xkb::KEY_3270_ExSelect => Key::ExSel, + xkb::KEY_3270_CursorSelect => Key::CrSel, + xkb::KEY_3270_PrintScreen => Key::PrintScreen, + xkb::KEY_3270_Enter => Key::Enter, + + xkb::KEY_space => Key::Space, + // KEY_exclam..KEY_Sinh_kunddaliya + + // XFree86 + // xkb::KEY_XF86ModeLock => Key::ModeLock, + + // XFree86 - Backlight controls + xkb::KEY_XF86MonBrightnessUp => Key::BrightnessUp, + xkb::KEY_XF86MonBrightnessDown => Key::BrightnessDown, + // xkb::KEY_XF86KbdLightOnOff => Key::LightOnOff, + // xkb::KEY_XF86KbdBrightnessUp => Key::KeyboardBrightnessUp, + // xkb::KEY_XF86KbdBrightnessDown => Key::KeyboardBrightnessDown, + + // XFree86 - "Internet" + xkb::KEY_XF86Standby => Key::Standby, + xkb::KEY_XF86AudioLowerVolume => Key::AudioVolumeDown, + xkb::KEY_XF86AudioRaiseVolume => Key::AudioVolumeUp, + xkb::KEY_XF86AudioPlay => Key::MediaPlay, + xkb::KEY_XF86AudioStop => Key::MediaStop, + xkb::KEY_XF86AudioPrev => Key::MediaTrackPrevious, + xkb::KEY_XF86AudioNext => Key::MediaTrackNext, + xkb::KEY_XF86HomePage => Key::BrowserHome, + xkb::KEY_XF86Mail => Key::LaunchMail, + // xkb::KEY_XF86Start => Key::Start, + xkb::KEY_XF86Search => Key::BrowserSearch, + xkb::KEY_XF86AudioRecord => Key::MediaRecord, + + // XFree86 - PDA + xkb::KEY_XF86Calculator => Key::LaunchApplication2, + // xkb::KEY_XF86Memo => Key::Memo, + // xkb::KEY_XF86ToDoList => Key::ToDoList, + xkb::KEY_XF86Calendar => Key::LaunchCalendar, + xkb::KEY_XF86PowerDown => Key::Power, + // xkb::KEY_XF86ContrastAdjust => Key::AdjustContrast, + // xkb::KEY_XF86RockerUp => Key::RockerUp, // TODO: Use Key::ArrowUp? + // xkb::KEY_XF86RockerDown => Key::RockerDown, // TODO: Use Key::ArrowDown? + // xkb::KEY_XF86RockerEnter => Key::RockerEnter, // TODO: Use Key::Enter? + + // XFree86 - More "Internet" + xkb::KEY_XF86Back => Key::BrowserBack, + xkb::KEY_XF86Forward => Key::BrowserForward, + // xkb::KEY_XF86Stop => Key::Stop, + xkb::KEY_XF86Refresh => Key::BrowserRefresh, + xkb::KEY_XF86PowerOff => Key::Power, + xkb::KEY_XF86WakeUp => Key::WakeUp, + xkb::KEY_XF86Eject => Key::Eject, + xkb::KEY_XF86ScreenSaver => Key::LaunchScreenSaver, + xkb::KEY_XF86WWW => Key::LaunchWebBrowser, + xkb::KEY_XF86Sleep => Key::Standby, + xkb::KEY_XF86Favorites => Key::BrowserFavorites, + xkb::KEY_XF86AudioPause => Key::MediaPause, + // xkb::KEY_XF86AudioMedia => Key::AudioMedia, + xkb::KEY_XF86MyComputer => Key::LaunchApplication1, + // xkb::KEY_XF86VendorHome => Key::VendorHome, + // xkb::KEY_XF86LightBulb => Key::LightBulb, + // xkb::KEY_XF86Shop => Key::BrowserShop, + // xkb::KEY_XF86History => Key::BrowserHistory, + // xkb::KEY_XF86OpenURL => Key::OpenUrl, + // xkb::KEY_XF86AddFavorite => Key::AddFavorite, + // xkb::KEY_XF86HotLinks => Key::HotLinks, + // xkb::KEY_XF86BrightnessAdjust => Key::BrightnessAdjust, + // xkb::KEY_XF86Finance => Key::BrowserFinance, + // xkb::KEY_XF86Community => Key::BrowserCommunity, + xkb::KEY_XF86AudioRewind => Key::MediaRewind, + // xkb::KEY_XF86BackForward => Key::???, + // KEY_XF86Launch0..KEY_XF86LaunchF + + // KEY_XF86ApplicationLeft..KEY_XF86CD + xkb::KEY_XF86Calculater => Key::LaunchApplication2, // This must be a typo, right? + // KEY_XF86Clear + xkb::KEY_XF86Close => Key::Close, + xkb::KEY_XF86Copy => Key::Copy, + xkb::KEY_XF86Cut => Key::Cut, + // KEY_XF86Display..KEY_XF86Documents + xkb::KEY_XF86Excel => Key::LaunchSpreadsheet, + // KEY_XF86Explorer..KEY_XF86iTouch + xkb::KEY_XF86LogOff => Key::LogOff, + // KEY_XF86Market..KEY_XF86MenuPB + xkb::KEY_XF86MySites => Key::BrowserFavorites, + xkb::KEY_XF86New => Key::New, + // KEY_XF86News..KEY_XF86OfficeHome + xkb::KEY_XF86Open => Key::Open, + // KEY_XF86Option + xkb::KEY_XF86Paste => Key::Paste, + xkb::KEY_XF86Phone => Key::LaunchPhone, + // KEY_XF86Q + xkb::KEY_XF86Reply => Key::MailReply, + xkb::KEY_XF86Reload => Key::BrowserRefresh, + // KEY_XF86RotateWindows..KEY_XF86RotationKB + xkb::KEY_XF86Save => Key::Save, + // KEY_XF86ScrollUp..KEY_XF86ScrollClick + xkb::KEY_XF86Send => Key::MailSend, + xkb::KEY_XF86Spell => Key::SpellCheck, + xkb::KEY_XF86SplitScreen => Key::SplitScreenToggle, + // KEY_XF86Support..KEY_XF86User2KB + xkb::KEY_XF86Video => Key::LaunchMediaPlayer, + // KEY_XF86WheelButton + xkb::KEY_XF86Word => Key::LaunchWordProcessor, + // KEY_XF86Xfer + xkb::KEY_XF86ZoomIn => Key::ZoomIn, + xkb::KEY_XF86ZoomOut => Key::ZoomOut, + + // KEY_XF86Away..KEY_XF86Messenger + xkb::KEY_XF86WebCam => Key::LaunchWebCam, + xkb::KEY_XF86MailForward => Key::MailForward, + // KEY_XF86Pictures + xkb::KEY_XF86Music => Key::LaunchMusicPlayer, + + // KEY_XF86Battery..KEY_XF86UWB + // + xkb::KEY_XF86AudioForward => Key::MediaFastForward, + // KEY_XF86AudioRepeat + xkb::KEY_XF86AudioRandomPlay => Key::RandomToggle, + xkb::KEY_XF86Subtitle => Key::Subtitle, + xkb::KEY_XF86AudioCycleTrack => Key::MediaAudioTrack, + // KEY_XF86CycleAngle..KEY_XF86Blue + // + xkb::KEY_XF86Suspend => Key::Standby, + xkb::KEY_XF86Hibernate => Key::Hibernate, + // KEY_XF86TouchpadToggle..KEY_XF86TouchpadOff + // + xkb::KEY_XF86AudioMute => Key::AudioVolumeMute, + + // KEY_XF86Switch_VT_1..KEY_XF86Switch_VT_12 + + // KEY_XF86Ungrab..KEY_XF86ClearGrab + xkb::KEY_XF86Next_VMode => Key::VideoModeNext, + // xkb::KEY_XF86Prev_VMode => Key::VideoModePrevious, + // KEY_XF86LogWindowTree..KEY_XF86LogGrabInfo + + // KEY_SunFA_Grave..KEY_SunFA_Cedilla + + // xkb::KEY_SunF36 => Key::F36 | Key::F11, + // xkb::KEY_SunF37 => Key::F37 | Key::F12, + + // xkb::KEY_SunSys_Req => Key::PrintScreen, + // The next couple of xkb (until KEY_SunStop) are already handled. + // KEY_SunPrint_Screen..KEY_SunPageDown + + // KEY_SunUndo..KEY_SunFront + xkb::KEY_SunCopy => Key::Copy, + xkb::KEY_SunOpen => Key::Open, + xkb::KEY_SunPaste => Key::Paste, + xkb::KEY_SunCut => Key::Cut, + + // KEY_SunPowerSwitch + xkb::KEY_SunAudioLowerVolume => Key::AudioVolumeDown, + xkb::KEY_SunAudioMute => Key::AudioVolumeMute, + xkb::KEY_SunAudioRaiseVolume => Key::AudioVolumeUp, + // KEY_SunVideoDegauss + xkb::KEY_SunVideoLowerBrightness => Key::BrightnessDown, + xkb::KEY_SunVideoRaiseBrightness => Key::BrightnessUp, + // KEY_SunPowerSwitchShift + // + _ => Key::Unidentified(NativeKeyCode::XKB(keysym)), + } +} diff --git a/src/platform_impl/linux/common/mod.rs b/src/platform_impl/linux/common/mod.rs new file mode 100644 index 0000000000..32030aff05 --- /dev/null +++ b/src/platform_impl/linux/common/mod.rs @@ -0,0 +1 @@ +pub mod keymap; diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 3dfc73cd6c..3e8997a4cc 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -41,6 +41,9 @@ pub mod wayland; #[cfg(feature = "x11")] pub mod x11; +#[cfg(any(feature = "x11", feature = "wayland"))] +mod common; + #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct KeyEventExtra { pub text_with_all_modifers: Option<&'static str>, diff --git a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs index 47cbc984ad..91c1edf8cc 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs @@ -10,7 +10,8 @@ use crate::platform_impl::wayland::event_loop::WinitState; use crate::platform_impl::wayland::{self, DeviceId}; use crate::platform_impl::KeyEventExtra; -use super::keymap; +// TODO: This is kind of terrible +use super::super::super::super::common::keymap; use super::KeyboardInner; #[inline] diff --git a/src/platform_impl/linux/wayland/seat/keyboard/keymap.rs b/src/platform_impl/linux/wayland/seat/keyboard/keymap.rs deleted file mode 100644 index ae48fc95cf..0000000000 --- a/src/platform_impl/linux/wayland/seat/keyboard/keymap.rs +++ /dev/null @@ -1,477 +0,0 @@ -// //! Convert Wayland keys to winit keys. - -use crate::keyboard::{Key, KeyCode, NativeKeyCode}; - -pub fn rawkey_to_keycode(rawkey: u32) -> KeyCode { - // keycodes are taken from linux/include/uapi/linux/input-event-codes.h - match rawkey { - 0 => todo!("What should be done in this case? Return `NativeKeyCode`, or perhaps `None`?"), - 1 => KeyCode::Escape, - 2 => KeyCode::Digit1, - 3 => KeyCode::Digit2, - 4 => KeyCode::Digit3, - 5 => KeyCode::Digit4, - 6 => KeyCode::Digit5, - 7 => KeyCode::Digit6, - 8 => KeyCode::Digit7, - 9 => KeyCode::Digit8, - 10 => KeyCode::Digit9, - 11 => KeyCode::Digit0, - 12 => KeyCode::Minus, - 13 => KeyCode::Equal, - 14 => KeyCode::Backspace, - 15 => KeyCode::Tab, - 16 => KeyCode::KeyQ, - 17 => KeyCode::KeyW, - 18 => KeyCode::KeyE, - 19 => KeyCode::KeyR, - 20 => KeyCode::KeyT, - 21 => KeyCode::KeyY, - 22 => KeyCode::KeyU, - 23 => KeyCode::KeyI, - 24 => KeyCode::KeyO, - 25 => KeyCode::KeyP, - 26 => KeyCode::BracketLeft, - 27 => KeyCode::BracketRight, - 28 => KeyCode::Enter, - 29 => KeyCode::ControlLeft, - 30 => KeyCode::KeyA, - 31 => KeyCode::KeyS, - 32 => KeyCode::KeyD, - 33 => KeyCode::KeyF, - 34 => KeyCode::KeyG, - 35 => KeyCode::KeyH, - 36 => KeyCode::KeyJ, - 37 => KeyCode::KeyK, - 38 => KeyCode::KeyL, - 39 => KeyCode::Semicolon, - 40 => KeyCode::Quote, - 41 => KeyCode::Backquote, - 42 => KeyCode::ShiftLeft, - 43 => KeyCode::Backslash, - 44 => KeyCode::KeyZ, - 45 => KeyCode::KeyX, - 46 => KeyCode::KeyC, - 47 => KeyCode::KeyV, - 48 => KeyCode::KeyB, - 49 => KeyCode::KeyN, - 50 => KeyCode::KeyM, - 51 => KeyCode::Comma, - 52 => KeyCode::Period, - 53 => KeyCode::Slash, - 54 => KeyCode::ShiftRight, - 55 => KeyCode::NumpadMultiply, - 56 => KeyCode::AltLeft, - 57 => KeyCode::Space, - 58 => KeyCode::CapsLock, - 59 => KeyCode::F1, - 60 => KeyCode::F2, - 61 => KeyCode::F3, - 62 => KeyCode::F4, - 63 => KeyCode::F5, - 64 => KeyCode::F6, - 65 => KeyCode::F7, - 66 => KeyCode::F8, - 67 => KeyCode::F9, - 68 => KeyCode::F10, - 69 => KeyCode::NumLock, - 70 => KeyCode::ScrollLock, - 71 => KeyCode::Numpad7, - 72 => KeyCode::Numpad8, - 73 => KeyCode::Numpad9, - 74 => KeyCode::NumpadSubtract, - 75 => KeyCode::Numpad4, - 76 => KeyCode::Numpad4, - 77 => KeyCode::Numpad6, - 78 => KeyCode::NumpadAdd, - 79 => KeyCode::Numpad1, - 80 => KeyCode::Numpad2, - 81 => KeyCode::Numpad3, - 82 => KeyCode::Numpad0, - 83 => KeyCode::NumpadDecimal, - 85 => KeyCode::Lang5, - 86 => KeyCode::IntlBackslash, // TODO: Verify. - 87 => KeyCode::F11, - 88 => KeyCode::F12, - 89 => KeyCode::IntlRo, - 90 => KeyCode::Lang3, - 91 => KeyCode::Lang4, - 92 => KeyCode::Convert, - 93 => KeyCode::KanaMode, - 94 => KeyCode::NonConvert, - // 95 => KeyCode::KPJPCOMMA, // TODO: What the heck is this supposed to be? - 96 => KeyCode::NumpadEnter, - 97 => KeyCode::ControlRight, - 98 => KeyCode::NumpadDivide, - 99 => KeyCode::PrintScreen, // TODO: Verify. - 100 => KeyCode::AltRight, - // 101 => KeyCode::LINEFEED, // TODO: What the heck is this supposed to be? - 102 => KeyCode::Home, - 103 => KeyCode::ArrowUp, - 104 => KeyCode::PageUp, - 105 => KeyCode::ArrowLeft, - 106 => KeyCode::ArrowRight, - 107 => KeyCode::End, - 108 => KeyCode::ArrowDown, - 109 => KeyCode::PageDown, - 110 => KeyCode::Insert, - 111 => KeyCode::Delete, - // 112 => KeyCode::MACRO, // TODO: What the heck is this supposed to be? - 113 => KeyCode::AudioVolumeMute, - 114 => KeyCode::AudioVolumeDown, - 115 => KeyCode::AudioVolumeUp, - // TODO: I have no idea if this should be mapped to `KeyCode::Power` - // Neither the Linux header or the uievents-code document disambigues this. - // 116 => KeyCode::POWER, - 117 => KeyCode::NumpadEqual, - // 118 => KeyCode::KPPLUSMINUS, // TODO: What the heck is this supposed to be? - 119 => KeyCode::Pause, - // 120 => KeyCode::SCALE, // TODO: What the heck is this supposed to be? - 121 => KeyCode::NumpadComma, - 122 => KeyCode::Lang1, - 123 => KeyCode::Lang2, - 124 => KeyCode::IntlYen, - 125 => KeyCode::SuperLeft, - 126 => KeyCode::SuperRight, - 127 => KeyCode::ContextMenu, - // 128 => KeyCode::STOP, - // 129 => KeyCode::AGAIN, - // 130 => KeyCode::PROPS, - // 131 => KeyCode::UNDO, - // 132 => KeyCode::FRONT, - // 133 => KeyCode::COPY, - // 134 => KeyCode::OPEN, - // 135 => KeyCode::PASTE, - // 136 => KeyCode::FIND, - // 137 => KeyCode::CUT, - // 138 => KeyCode::HELP, - // 139 => KeyCode::MENU, - // 140 => KeyCode::CALC, - // 141 => KeyCode::SETUP, - // 142 => KeyCode::SLEEP, - // 143 => KeyCode::WAKEUP, - // 144 => KeyCode::FILE, - // 145 => KeyCode::SENDFILE, - // 146 => KeyCode::DELETEFILE, - // 147 => KeyCode::XFER, - // 148 => KeyCode::PROG1, - // 149 => KeyCode::PROG2, - // 150 => KeyCode::WWW, - // 151 => KeyCode::MSDOS, - // 152 => KeyCode::COFFEE, - // 153 => KeyCode::ROTATE_DISPLAY, - // 154 => KeyCode::CYCLEWINDOWS, - // 155 => KeyCode::MAIL, - // 156 => KeyCode::BOOKMARKS, - // 157 => KeyCode::COMPUTER, - // 158 => KeyCode::BACK, - // 159 => KeyCode::FORWARD, - // 160 => KeyCode::CLOSECD, - // 161 => KeyCode::EJECTCD, - // 162 => KeyCode::EJECTCLOSECD, - 163 => KeyCode::MediaTrackNext, - 164 => KeyCode::MediaPlayPause, - 165 => KeyCode::MediaTrackPrevious, - 166 => KeyCode::MediaStop, - // 167 => KeyCode::RECORD, - // 168 => KeyCode::REWIND, - // 169 => KeyCode::PHONE, - // 170 => KeyCode::ISO, - // 171 => KeyCode::CONFIG, - // 172 => KeyCode::HOMEPAGE, - // 173 => KeyCode::REFRESH, - // 174 => KeyCode::EXIT, - // 175 => KeyCode::MOVE, - // 176 => KeyCode::EDIT, - // 177 => KeyCode::SCROLLUP, - // 178 => KeyCode::SCROLLDOWN, - // 179 => KeyCode::KPLEFTPAREN, - // 180 => KeyCode::KPRIGHTPAREN, - // 181 => KeyCode::NEW, - // 182 => KeyCode::REDO, - 183 => KeyCode::F13, - 184 => KeyCode::F14, - 185 => KeyCode::F15, - 186 => KeyCode::F16, - 187 => KeyCode::F17, - 188 => KeyCode::F18, - 189 => KeyCode::F19, - 190 => KeyCode::F20, - 191 => KeyCode::F21, - 192 => KeyCode::F22, - 193 => KeyCode::F23, - 194 => KeyCode::F24, - // 200 => KeyCode::PLAYCD, - // 201 => KeyCode::PAUSECD, - // 202 => KeyCode::PROG3, - // 203 => KeyCode::PROG4, - // 204 => KeyCode::DASHBOARD, - // 205 => KeyCode::SUSPEND, - // 206 => KeyCode::CLOSE, - // 207 => KeyCode::PLAY, - // 208 => KeyCode::FASTFORWARD, - // 209 => KeyCode::BASSBOOST, - // 210 => KeyCode::PRINT, - // 211 => KeyCode::HP, - // 212 => KeyCode::CAMERA, - // 213 => KeyCode::SOUND, - // 214 => KeyCode::QUESTION, - // 215 => KeyCode::EMAIL, - // 216 => KeyCode::CHAT, - // 217 => KeyCode::SEARCH, - // 218 => KeyCode::CONNECT, - // 219 => KeyCode::FINANCE, - // 220 => KeyCode::SPORT, - // 221 => KeyCode::SHOP, - // 222 => KeyCode::ALTERASE, - // 223 => KeyCode::CANCEL, - // 224 => KeyCode::BRIGHTNESSDOW, - // 225 => KeyCode::BRIGHTNESSU, - // 226 => KeyCode::MEDIA, - // 227 => KeyCode::SWITCHVIDEOMODE, - // 228 => KeyCode::KBDILLUMTOGGLE, - // 229 => KeyCode::KBDILLUMDOWN, - // 230 => KeyCode::KBDILLUMUP, - // 231 => KeyCode::SEND, - // 232 => KeyCode::REPLY, - // 233 => KeyCode::FORWARDMAIL, - // 234 => KeyCode::SAVE, - // 235 => KeyCode::DOCUMENTS, - // 236 => KeyCode::BATTERY, - // 237 => KeyCode::BLUETOOTH, - // 238 => KeyCode::WLAN, - // 239 => KeyCode::UWB, - 240 => KeyCode::Unidentified(NativeKeyCode::Unidentified), - // 241 => KeyCode::VIDEO_NEXT, - // 242 => KeyCode::VIDEO_PREV, - // 243 => KeyCode::BRIGHTNESS_CYCLE, - // 244 => KeyCode::BRIGHTNESS_AUTO, - _ => KeyCode::Unidentified(NativeKeyCode::XKB(rawkey)), - } -} - -pub fn keysym_to_key(keysym: u32) -> Key<'static> { - use sctk::seat::keyboard::keysyms; - match keysym { - // // Numbers. - // // keysyms::XKB_KEY_1 => Some(Key::Character("1")), - // // keysyms::XKB_KEY_2 => Some(Key::Character("2")), - // // keysyms::XKB_KEY_3 => Some(Key::Character("3")), - // // keysyms::XKB_KEY_4 => Some(Key::Character("4")), - // // keysyms::XKB_KEY_5 => Some(Key::Character("5")), - // // keysyms::XKB_KEY_6 => Some(Key::Character("6")), - // // keysyms::XKB_KEY_7 => Some(Key::Character("7")), - // // keysyms::XKB_KEY_8 => Some(Key::Character("8")), - // // keysyms::XKB_KEY_9 => Some(Key::Character("9")), - // // keysyms::XKB_KEY_0 => Some(Key::Character("0")), - // // Letters. - // // keysyms::XKB_KEY_A => Some(Key::Character("A")), - // // keysyms::XKB_KEY_a => Some(Key::Character("a")), - // // keysyms::XKB_KEY_B => Some(Key::Character("B")), - // // keysyms::XKB_KEY_b => Some(Key::Character("b")), - // // keysyms::XKB_KEY_C => Some(Key::Character("C")), - // // keysyms::XKB_KEY_c => Some(Key::Character("c")), - // // keysyms::XKB_KEY_D => Some(Key::Character("D")), - // // keysyms::XKB_KEY_d => Some(Key::Character("d")), - // // keysyms::XKB_KEY_E => Some(Key::Character("E")), - // // keysyms::XKB_KEY_e => Some(Key::Character("e")), - // // keysyms::XKB_KEY_F => Some(Key::Character("F")), - // // keysyms::XKB_KEY_f => Some(Key::Character("f")), - // // keysyms::XKB_KEY_G => Some(Key::Character("G")), - // // keysyms::XKB_KEY_g => Some(Key::Character("g")), - // // keysyms::XKB_KEY_H => Some(Key::Character("H")), - // // keysyms::XKB_KEY_h => Some(Key::Character("h")), - // // keysyms::XKB_KEY_I => Some(Key::Character("I")), - // // keysyms::XKB_KEY_i => Some(Key::Character("i")), - // // keysyms::XKB_KEY_J => Some(Key::Character("J")), - // // keysyms::XKB_KEY_j => Some(Key::Character("j")), - // // keysyms::XKB_KEY_K => Some(Key::Character("K")), - // // keysyms::XKB_KEY_k => Some(Key::Character("k")), - // // keysyms::XKB_KEY_L => Some(Key::Character("L")), - // // keysyms::XKB_KEY_l => Some(Key::Character("l")), - // // keysyms::XKB_KEY_M => Some(Key::Character("M")), - // // keysyms::XKB_KEY_m => Some(Key::Character("m")), - // // keysyms::XKB_KEY_N => Some(Key::Character("N")), - // // keysyms::XKB_KEY_n => Some(Key::Character("n")), - // // keysyms::XKB_KEY_O => Some(Key::Character("O")), - // // keysyms::XKB_KEY_o => Some(Key::Character("o")), - // // keysyms::XKB_KEY_P => Some(Key::Character("P")), - // // keysyms::XKB_KEY_p => Some(Key::Character("p")), - // // keysyms::XKB_KEY_Q => Some(Key::Character("Q")), - // // keysyms::XKB_KEY_q => Some(Key::Character("q")), - // // keysyms::XKB_KEY_R => Some(Key::Character("R")), - // // keysyms::XKB_KEY_r => Some(Key::Character("r")), - // // keysyms::XKB_KEY_S => Some(Key::Character("S")), - // // keysyms::XKB_KEY_s => Some(Key::Character("s")), - // // keysyms::XKB_KEY_T => Some(Key::Character("T")), - // // keysyms::XKB_KEY_t => Some(Key::Character("t")), - // // keysyms::XKB_KEY_U => Some(Key::Character("U")), - // // keysyms::XKB_KEY_u => Some(Key::Character("u")), - // // keysyms::XKB_KEY_V => Some(Key::Character("V")), - // // keysyms::XKB_KEY_v => Some(Key::Character("v")), - // // keysyms::XKB_KEY_W => Some(Key::Character("W")), - // // keysyms::XKB_KEY_w => Some(Key::Character("w")), - // // keysyms::XKB_KEY_X => Some(Key::Character("X")), - // // keysyms::XKB_KEY_x => Some(Key::Character("x")), - // // keysyms::XKB_KEY_Y => Some(Key::Character("Y")), - // // keysyms::XKB_KEY_y => Some(Key::Character("y")), - // // keysyms::XKB_KEY_Z => Some(Key::Character("Z")), - // // keysyms::XKB_KEY_z => Some(Key::Character("z")), - // // Escape. - // keysyms::XKB_KEY_Escape => Some(Key::Escape), - // // Function keys. - // keysyms::XKB_KEY_F1 => Some(Key::F1), - // keysyms::XKB_KEY_F2 => Some(Key::F2), - // keysyms::XKB_KEY_F3 => Some(Key::F3), - // keysyms::XKB_KEY_F4 => Some(Key::F4), - // keysyms::XKB_KEY_F5 => Some(Key::F5), - // keysyms::XKB_KEY_F6 => Some(Key::F6), - // keysyms::XKB_KEY_F7 => Some(Key::F7), - // keysyms::XKB_KEY_F8 => Some(Key::F8), - // keysyms::XKB_KEY_F9 => Some(Key::F9), - // keysyms::XKB_KEY_F10 => Some(Key::F10), - // keysyms::XKB_KEY_F11 => Some(Key::F11), - // keysyms::XKB_KEY_F12 => Some(Key::F12), - // keysyms::XKB_KEY_F13 => Some(Key::F13), - // keysyms::XKB_KEY_F14 => Some(Key::F14), - // keysyms::XKB_KEY_F15 => Some(Key::F15), - // keysyms::XKB_KEY_F16 => Some(Key::F16), - // keysyms::XKB_KEY_F17 => Some(Key::F17), - // keysyms::XKB_KEY_F18 => Some(Key::F18), - // keysyms::XKB_KEY_F19 => Some(Key::F19), - // keysyms::XKB_KEY_F20 => Some(Key::F20), - // keysyms::XKB_KEY_F21 => Some(Key::F21), - // keysyms::XKB_KEY_F22 => Some(Key::F22), - // keysyms::XKB_KEY_F23 => Some(Key::F23), - // keysyms::XKB_KEY_F24 => Some(Key::F24), - // keysyms::XKB_KEY_F25 => Some(Key::F25), - // keysyms::XKB_KEY_F26 => Some(Key::F26), - // keysyms::XKB_KEY_F27 => Some(Key::F27), - // keysyms::XKB_KEY_F28 => Some(Key::F28), - // keysyms::XKB_KEY_F29 => Some(Key::F29), - // keysyms::XKB_KEY_F30 => Some(Key::F30), - // keysyms::XKB_KEY_F31 => Some(Key::F31), - // keysyms::XKB_KEY_F32 => Some(Key::F32), - // keysyms::XKB_KEY_F33 => Some(Key::F33), - // keysyms::XKB_KEY_F34 => Some(Key::F34), - // keysyms::XKB_KEY_F35 => Some(Key::F35), - // // Flow control. - // keysyms::XKB_KEY_Print => Some(Key::PrintScreen), - // keysyms::XKB_KEY_Scroll_Lock => Some(Key::ScrollLock), - // keysyms::XKB_KEY_Pause => Some(Key::Pause), - // keysyms::XKB_KEY_Insert => Some(Key::Insert), - // keysyms::XKB_KEY_Home => Some(Key::Home), - // keysyms::XKB_KEY_Delete => Some(Key::Delete), - // keysyms::XKB_KEY_End => Some(Key::End), - // keysyms::XKB_KEY_Page_Down => Some(Key::PageDown), - // keysyms::XKB_KEY_Page_Up => Some(Key::PageUp), - // // Arrows. - // keysyms::XKB_KEY_Left => Some(Key::Left), - // keysyms::XKB_KEY_Up => Some(Key::Up), - // keysyms::XKB_KEY_Right => Some(Key::Right), - // keysyms::XKB_KEY_Down => Some(Key::Down), - - // keysyms::XKB_KEY_BackSpace => Some(Key::Back), - // keysyms::XKB_KEY_Return => Some(Key::Return), - // keysyms::XKB_KEY_space => Some(Key::Space), - - // keysyms::XKB_KEY_Multi_key => Some(Key::Compose), - // keysyms::XKB_KEY_caret => Some(Key::Caret), - - // // Keypad. - // keysyms::XKB_KEY_Num_Lock => Some(Key::Numlock), - // keysyms::XKB_KEY_KP_0 => Some(Key::Numpad0), - // keysyms::XKB_KEY_KP_1 => Some(Key::Numpad1), - // keysyms::XKB_KEY_KP_2 => Some(Key::Numpad2), - // keysyms::XKB_KEY_KP_3 => Some(Key::Numpad3), - // keysyms::XKB_KEY_KP_4 => Some(Key::Numpad4), - // keysyms::XKB_KEY_KP_5 => Some(Key::Numpad5), - // keysyms::XKB_KEY_KP_6 => Some(Key::Numpad6), - // keysyms::XKB_KEY_KP_7 => Some(Key::Numpad7), - // keysyms::XKB_KEY_KP_8 => Some(Key::Numpad8), - // keysyms::XKB_KEY_KP_9 => Some(Key::Numpad9), - // // Misc. - // // => Some(Key::AbntC1), - // // => Some(Key::AbntC2), - // keysyms::XKB_KEY_plus => Some(Key::Plus), - // keysyms::XKB_KEY_apostrophe => Some(Key::Apostrophe), - // // => Some(Key::Apps), - // keysyms::XKB_KEY_at => Some(Key::At), - // // => Some(Key::Ax), - // keysyms::XKB_KEY_backslash => Some(Key::Backslash), - // keysyms::XKB_KEY_XF86Calculator => Some(Key::Calculator), - // // => Some(Key::Capital), - // keysyms::XKB_KEY_colon => Some(Key::Colon), - // keysyms::XKB_KEY_comma => Some(Key::Comma), - // // => Some(Key::Convert), - // keysyms::XKB_KEY_equal => Some(Key::Equals), - // keysyms::XKB_KEY_grave => Some(Key::Grave), - // // => Some(Key::Kana), - // keysyms::XKB_KEY_Kanji => Some(Key::Kanji), - // keysyms::XKB_KEY_Alt_L => Some(Key::LAlt), - // keysyms::XKB_KEY_bracketleft => Some(Key::LBracket), - // keysyms::XKB_KEY_Control_L => Some(Key::LControl), - // keysyms::XKB_KEY_Shift_L => Some(Key::LShift), - // keysyms::XKB_KEY_Super_L => Some(Key::LWin), - // keysyms::XKB_KEY_XF86Mail => Some(Key::Mail), - // // => Some(Key::MediaSelect), - // // => Some(Key::MediaStop), - // keysyms::XKB_KEY_minus => Some(Key::Minus), - // keysyms::XKB_KEY_asterisk => Some(Key::Asterisk), - // keysyms::XKB_KEY_XF86AudioMute => Some(Key::Mute), - // // => Some(Key::MyComputer), - // keysyms::XKB_KEY_XF86AudioNext => Some(Key::NextTrack), - // // => Some(Key::NoConvert), - // keysyms::XKB_KEY_KP_Separator => Some(Key::NumpadComma), - // keysyms::XKB_KEY_KP_Enter => Some(Key::NumpadEnter), - // keysyms::XKB_KEY_KP_Equal => Some(Key::NumpadEquals), - // keysyms::XKB_KEY_KP_Add => Some(Key::NumpadAdd), - // keysyms::XKB_KEY_KP_Subtract => Some(Key::NumpadSubtract), - // keysyms::XKB_KEY_KP_Multiply => Some(Key::NumpadMultiply), - // keysyms::XKB_KEY_KP_Divide => Some(Key::NumpadDivide), - // keysyms::XKB_KEY_KP_Decimal => Some(Key::NumpadDecimal), - // keysyms::XKB_KEY_KP_Page_Up => Some(Key::PageUp), - // keysyms::XKB_KEY_KP_Page_Down => Some(Key::PageDown), - // keysyms::XKB_KEY_KP_Home => Some(Key::Home), - // keysyms::XKB_KEY_KP_End => Some(Key::End), - // keysyms::XKB_KEY_KP_Left => Some(Key::Left), - // keysyms::XKB_KEY_KP_Up => Some(Key::Up), - // keysyms::XKB_KEY_KP_Right => Some(Key::Right), - // keysyms::XKB_KEY_KP_Down => Some(Key::Down), - // // => Some(Key::OEM102), - // keysyms::XKB_KEY_period => Some(Key::Period), - // // => Some(Key::Playpause), - // keysyms::XKB_KEY_XF86PowerOff => Some(Key::Power), - // keysyms::XKB_KEY_XF86AudioPrev => Some(Key::PrevTrack), - // keysyms::XKB_KEY_Alt_R => Some(Key::RAlt), - // keysyms::XKB_KEY_bracketright => Some(Key::RBracket), - // keysyms::XKB_KEY_Control_R => Some(Key::RControl), - // keysyms::XKB_KEY_Shift_R => Some(Key::RShift), - // keysyms::XKB_KEY_Super_R => Some(Key::RWin), - // keysyms::XKB_KEY_semicolon => Some(Key::Semicolon), - // keysyms::XKB_KEY_slash => Some(Key::Slash), - // keysyms::XKB_KEY_XF86Sleep => Some(Key::Sleep), - // // => Some(Key::Stop), - // // => Some(Key::Sysrq), - // keysyms::XKB_KEY_Tab => Some(Key::Tab), - // keysyms::XKB_KEY_ISO_Left_Tab => Some(Key::Tab), - // keysyms::XKB_KEY_underscore => Some(Key::Underline), - // // => Some(Key::Unlabeled), - // keysyms::XKB_KEY_XF86AudioLowerVolume => Some(Key::VolumeDown), - // keysyms::XKB_KEY_XF86AudioRaiseVolume => Some(Key::VolumeUp), - // // => Some(Key::Wake), - // // => Some(Key::Webback), - // // => Some(Key::WebFavorites), - // // => Some(Key::WebForward), - // // => Some(Key::WebHome), - // // => Some(Key::WebRefresh), - // // => Some(Key::WebSearch), - // // => Some(Key::WebStop), - // keysyms::XKB_KEY_yen => Some(Key::Yen), - // keysyms::XKB_KEY_XF86Copy => Some(Key::Copy), - // keysyms::XKB_KEY_XF86Paste => Some(Key::Paste), - // keysyms::XKB_KEY_XF86Cut => Some(Key::Cut), - // // Fallback. - _ => Key::Unidentified(NativeKeyCode::Unidentified), - } -} diff --git a/src/platform_impl/linux/wayland/seat/keyboard/mod.rs b/src/platform_impl/linux/wayland/seat/keyboard/mod.rs index fb7973f452..b63fe8bd9c 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/mod.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/mod.rs @@ -16,7 +16,6 @@ use crate::platform_impl::wayland::event_loop::WinitState; use crate::platform_impl::wayland::WindowId; mod handlers; -mod keymap; pub(crate) struct Keyboard { pub keyboard: WlKeyboard, From 22cba39b202c56e032de24e3f50cb47ae953ba97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Mon, 29 Mar 2021 02:24:03 +0200 Subject: [PATCH 07/53] Add key location and some minor corrections Also add a `Meta` key (code) value. --- src/keyboard.rs | 6 ++ src/platform_impl/linux/common/keymap.rs | 71 ++++++++++++++++--- .../linux/wayland/seat/keyboard/handlers.rs | 13 ++-- 3 files changed, 76 insertions(+), 14 deletions(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index 28983cfaf4..6329695fcf 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -536,6 +536,9 @@ pub enum KeyCode { AudioVolumeMute, AudioVolumeUp, WakeUp, + // Legacy modifier key. Also called "Super" in certain places. + Meta, + // Legacy modifier key. Hyper, Turbo, Abort, @@ -731,6 +734,9 @@ pub enum Key<'a> { /// The Symbol modifier key (used on some virtual keyboards). Symbol, SymbolLock, + // Legacy modifier key. Also called "Super" in certain places. + Meta, + // Legacy modifier key. Hyper, /// Used to enable "super" modifier function for interpreting concurrent or subsequent keyboard /// input. This key value is used for the "Windows Logo" key and the Apple `Command` or `⌘` key. diff --git a/src/platform_impl/linux/common/keymap.rs b/src/platform_impl/linux/common/keymap.rs index eeccf65a97..d3438f0ef9 100644 --- a/src/platform_impl/linux/common/keymap.rs +++ b/src/platform_impl/linux/common/keymap.rs @@ -315,9 +315,9 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { xkb::KEY_Up => Key::ArrowUp, xkb::KEY_Right => Key::ArrowRight, xkb::KEY_Down => Key::ArrowDown, - // xkb::KEY_Prior => Key::Prior, + // xkb::KEY_Prior => Key::PageUp, xkb::KEY_Page_Up => Key::PageUp, - // xkb::KEY_Next => Key::Next, + // xkb::KEY_Next => Key::PageDown, xkb::KEY_End => Key::End, // xkb::KEY_Begin => Key::Begin, @@ -350,9 +350,9 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { xkb::KEY_KP_Up => Key::ArrowLeft, xkb::KEY_KP_Right => Key::ArrowRight, xkb::KEY_KP_Down => Key::ArrowDown, - // xkb::KEY_KP_Prior => Key::Prior, + // xkb::KEY_KP_Prior => Key::PageUp, xkb::KEY_KP_Page_Up => Key::PageUp, - // xkb::KEY_KP_Next => Key::Next, + // xkb::KEY_KP_Next => Key::PageDown, xkb::KEY_KP_Page_Down => Key::PageDown, xkb::KEY_KP_End => Key::End, // xkb::KEY_KP_Begin => Key::Begin, @@ -421,14 +421,15 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { xkb::KEY_Control_R => Key::Control, xkb::KEY_Caps_Lock => Key::CapsLock, // xkb::KEY_Shift_Lock => Key::ShiftLock, - // + + // NOTE: The key xkb calls "Meta" is called "Super" by Winit, and vice versa. + // This is a tad confusing, but these keys have different names depending on who you ask. xkb::KEY_Meta_L => Key::Super, xkb::KEY_Meta_R => Key::Super, xkb::KEY_Alt_L => Key::Alt, xkb::KEY_Alt_R => Key::Alt, - // NOTE: The key xkb calls "Meta" is called "Super" by Winit. - // xkb::KEY_Super_L => Key::Super, - // xkb::KEY_Super_R => Key::Super, + xkb::KEY_Super_L => Key::Meta, + xkb::KEY_Super_R => Key::Meta, xkb::KEY_Hyper_L => Key::Hyper, xkb::KEY_Hyper_R => Key::Hyper, @@ -683,3 +684,57 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { _ => Key::Unidentified(NativeKeyCode::XKB(keysym)), } } + +pub fn keysym_location(keysym: u32) -> KeyLocation { + use xkbcommon::xkb; + match keysym { + xkb::KEY_Shift_L + | xkb::KEY_Control_L + | xkb::KEY_Meta_L + | xkb::KEY_Alt_L + | xkb::KEY_Super_L + | xkb::KEY_Hyper_L => KeyLocation::Left, + xkb::KEY_Shift_R + | xkb::KEY_Control_R + | xkb::KEY_Meta_R + | xkb::KEY_Alt_R + | xkb::KEY_Super_R + | xkb::KEY_Hyper_R => KeyLocation::Right, + xkb::KEY_KP_0 + | xkb::KEY_KP_1 + | xkb::KEY_KP_2 + | xkb::KEY_KP_3 + | xkb::KEY_KP_4 + | xkb::KEY_KP_5 + | xkb::KEY_KP_6 + | xkb::KEY_KP_7 + | xkb::KEY_KP_8 + | xkb::KEY_KP_9 + | xkb::KEY_KP_Space + | xkb::KEY_KP_Tab + | xkb::KEY_KP_Enter + | xkb::KEY_KP_F1 + | xkb::KEY_KP_F2 + | xkb::KEY_KP_F3 + | xkb::KEY_KP_F4 + | xkb::KEY_KP_Home + | xkb::KEY_KP_Left + | xkb::KEY_KP_Up + | xkb::KEY_KP_Right + | xkb::KEY_KP_Down + | xkb::KEY_KP_Page_Up + | xkb::KEY_KP_Page_Down + | xkb::KEY_KP_End + | xkb::KEY_KP_Begin + | xkb::KEY_KP_Insert + | xkb::KEY_KP_Delete + | xkb::KEY_KP_Equal + | xkb::KEY_KP_Multiply + | xkb::KEY_KP_Add + | xkb::KEY_KP_Separator + | xkb::KEY_KP_Subtract + | xkb::KEY_KP_Decimal + | xkb::KEY_KP_Divide => KeyLocation::Numpad, + _ => KeyLocation::Standard, + } +} diff --git a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs index 91c1edf8cc..268beb6fa3 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs @@ -5,13 +5,12 @@ use sctk::reexports::client::protocol::wl_keyboard::KeyState; use sctk::seat::keyboard::Event as KeyboardEvent; use crate::event::{ElementState, KeyEvent, WindowEvent}; -use crate::keyboard::{Key, KeyLocation, ModifiersState, NativeKeyCode}; +use crate::keyboard::{Key, ModifiersState, NativeKeyCode}; +use crate::platform_impl::platform::common::keymap; use crate::platform_impl::wayland::event_loop::WinitState; use crate::platform_impl::wayland::{self, DeviceId}; use crate::platform_impl::KeyEventExtra; -// TODO: This is kind of terrible -use super::super::super::super::common::keymap; use super::KeyboardInner; #[inline] @@ -73,6 +72,7 @@ pub(super) fn handle_keyboard( let physical_key = keymap::rawkey_to_keycode(rawkey); let logical_key = keymap::keysym_to_key(keysym); + let location = keymap::keysym_location(keysym); event_sink.push_window_event( WindowEvent::KeyboardInput { @@ -83,7 +83,7 @@ pub(super) fn handle_keyboard( physical_key, logical_key, text: None, - location: KeyLocation::Standard, + location, state, repeat: false, platform_specific: KeyEventExtra { @@ -120,6 +120,7 @@ pub(super) fn handle_keyboard( let physical_key = keymap::rawkey_to_keycode(rawkey); let logical_key = keymap::keysym_to_key(keysym); + let location = keymap::keysym_location(keysym); event_sink.push_window_event( WindowEvent::KeyboardInput { @@ -130,9 +131,9 @@ pub(super) fn handle_keyboard( physical_key, logical_key, text: None, - location: KeyLocation::Standard, + location, state: ElementState::Pressed, - repeat: false, + repeat: true, platform_specific: KeyEventExtra { key_without_modifiers: Key::Unidentified(NativeKeyCode::Unidentified), text_with_all_modifers: None, From 75ddf1df5c009f9ee6320837b5d210d4e4cae8c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Tue, 30 Mar 2021 00:12:38 +0200 Subject: [PATCH 08/53] Use xkbcommon-dl rather than xkbcommon --- Cargo.toml | 2 +- src/platform_impl/linux/common/keymap.rs | 826 +++++++++++------------ 2 files changed, 414 insertions(+), 414 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index eb6815c1f5..ac3d76aab9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,7 +96,7 @@ x11-dl = { version = "2.18.5", optional = true } percent-encoding = { version = "2.0", optional = true } parking_lot = { version = "0.11.0", optional = true } libc = "0.2.64" -xkbcommon = "0.4.0" +xkbcommon-dl = { git = "https://github.com/maroider/xkbcommon-dl", rev = "224646a" } [target.'cfg(target_arch = "wasm32")'.dependencies.web_sys] package = "web-sys" diff --git a/src/platform_impl/linux/common/keymap.rs b/src/platform_impl/linux/common/keymap.rs index d3438f0ef9..3016851dd0 100644 --- a/src/platform_impl/linux/common/keymap.rs +++ b/src/platform_impl/linux/common/keymap.rs @@ -264,477 +264,477 @@ pub fn rawkey_to_keycode(rawkey: u32) -> KeyCode { } pub fn keysym_to_key(keysym: u32) -> Key<'static> { - use xkbcommon::xkb; + use xkbcommon_dl::keysyms; match keysym { // TTY function keys - xkb::KEY_BackSpace => Key::Backspace, - xkb::KEY_Tab => Key::Tab, - // xkb::KEY_Linefeed => Key::Linefeed, - xkb::KEY_Clear => Key::Clear, - xkb::KEY_Return => Key::Enter, - // xkb::KEY_Pause => Key::Pause, - xkb::KEY_Scroll_Lock => Key::ScrollLock, - xkb::KEY_Sys_Req => Key::PrintScreen, - xkb::KEY_Escape => Key::Escape, - xkb::KEY_Delete => Key::Delete, + keysyms::XKB_KEY_BackSpace => Key::Backspace, + keysyms::XKB_KEY_Tab => Key::Tab, + // keysyms::XKB_KEY_Linefeed => Key::Linefeed, + keysyms::XKB_KEY_Clear => Key::Clear, + keysyms::XKB_KEY_Return => Key::Enter, + // keysyms::XKB_KEY_Pause => Key::Pause, + keysyms::XKB_KEY_Scroll_Lock => Key::ScrollLock, + keysyms::XKB_KEY_Sys_Req => Key::PrintScreen, + keysyms::XKB_KEY_Escape => Key::Escape, + keysyms::XKB_KEY_Delete => Key::Delete, // IME keys - xkb::KEY_Multi_key => Key::Compose, - xkb::KEY_Codeinput => Key::CodeInput, - xkb::KEY_SingleCandidate => Key::SingleCandidate, - xkb::KEY_MultipleCandidate => Key::AllCandidates, - xkb::KEY_PreviousCandidate => Key::PreviousCandidate, + keysyms::XKB_KEY_Multi_key => Key::Compose, + keysyms::XKB_KEY_Codeinput => Key::CodeInput, + keysyms::XKB_KEY_SingleCandidate => Key::SingleCandidate, + keysyms::XKB_KEY_MultipleCandidate => Key::AllCandidates, + keysyms::XKB_KEY_PreviousCandidate => Key::PreviousCandidate, // Japanese keys - xkb::KEY_Kanji => Key::KanjiMode, - xkb::KEY_Muhenkan => Key::NonConvert, - xkb::KEY_Henkan_Mode => Key::Convert, - xkb::KEY_Romaji => Key::Romaji, - xkb::KEY_Hiragana => Key::Hiragana, - xkb::KEY_Hiragana_Katakana => Key::HiraganaKatakana, - xkb::KEY_Zenkaku => Key::Zenkaku, - xkb::KEY_Hankaku => Key::Hankaku, - xkb::KEY_Zenkaku_Hankaku => Key::ZenkakuHankaku, - // xkb::KEY_Touroku => Key::Touroku, - // xkb::KEY_Massyo => Key::Massyo, - xkb::KEY_Kana_Lock => Key::KanaMode, + keysyms::XKB_KEY_Kanji => Key::KanjiMode, + keysyms::XKB_KEY_Muhenkan => Key::NonConvert, + keysyms::XKB_KEY_Henkan_Mode => Key::Convert, + keysyms::XKB_KEY_Romaji => Key::Romaji, + keysyms::XKB_KEY_Hiragana => Key::Hiragana, + keysyms::XKB_KEY_Hiragana_Katakana => Key::HiraganaKatakana, + keysyms::XKB_KEY_Zenkaku => Key::Zenkaku, + keysyms::XKB_KEY_Hankaku => Key::Hankaku, + keysyms::XKB_KEY_Zenkaku_Hankaku => Key::ZenkakuHankaku, + // keysyms::XKB_KEY_Touroku => Key::Touroku, + // keysyms::XKB_KEY_Massyo => Key::Massyo, + keysyms::XKB_KEY_Kana_Lock => Key::KanaMode, // TODO: This seems a tad perverse, but I'm not really familiar with japanese keyboards. // MDN documents this as a valid mapping, however. - // xkb::KEY_Kana_Shift => Key::KanaMode, + // keysyms::XKB_KEY_Kana_Shift => Key::KanaMode, // TODO: Is this the correct mapping? - // xkb::KEY_Eisu_Shift => Key::Alphanumeric, - // xkb::KEY_Eisu_toggle => Key::Alphanumeric, + // keysyms::XKB_KEY_Eisu_Shift => Key::Alphanumeric, + // keysyms::XKB_KEY_Eisu_toggle => Key::Alphanumeric, // NOTE: The next three items are aliases for values we've already mapped. - // xkb::KEY_Kanji_Bangou => Key::CodeInput, - // xkb::KEY_Zen_Koho => Key::AllCandidates, - // xkb::KEY_Mae_Koho => Key::PreviousCandidate, + // keysyms::XKB_KEY_Kanji_Bangou => Key::CodeInput, + // keysyms::XKB_KEY_Zen_Koho => Key::AllCandidates, + // keysyms::XKB_KEY_Mae_Koho => Key::PreviousCandidate, // Cursor control & motion - xkb::KEY_Home => Key::Home, - xkb::KEY_Left => Key::ArrowLeft, - xkb::KEY_Up => Key::ArrowUp, - xkb::KEY_Right => Key::ArrowRight, - xkb::KEY_Down => Key::ArrowDown, - // xkb::KEY_Prior => Key::PageUp, - xkb::KEY_Page_Up => Key::PageUp, - // xkb::KEY_Next => Key::PageDown, - xkb::KEY_End => Key::End, - // xkb::KEY_Begin => Key::Begin, + keysyms::XKB_KEY_Home => Key::Home, + keysyms::XKB_KEY_Left => Key::ArrowLeft, + keysyms::XKB_KEY_Up => Key::ArrowUp, + keysyms::XKB_KEY_Right => Key::ArrowRight, + keysyms::XKB_KEY_Down => Key::ArrowDown, + // keysyms::XKB_KEY_Prior => Key::PageUp, + keysyms::XKB_KEY_Page_Up => Key::PageUp, + // keysyms::XKB_KEY_Next => Key::PageDown, + keysyms::XKB_KEY_End => Key::End, + // keysyms::XKB_KEY_Begin => Key::Begin, // Misc. functions - xkb::KEY_Select => Key::Select, - xkb::KEY_Print => Key::PrintScreen, - xkb::KEY_Execute => Key::Execute, - xkb::KEY_Insert => Key::Insert, - xkb::KEY_Undo => Key::Undo, - xkb::KEY_Redo => Key::Redo, - xkb::KEY_Menu => Key::ContextMenu, - xkb::KEY_Find => Key::Find, - xkb::KEY_Cancel => Key::Cancel, - xkb::KEY_Help => Key::Help, - xkb::KEY_Break => Key::Pause, - xkb::KEY_Mode_switch => Key::ModeChange, - // xkb::KEY_script_switch => Key::ModeChange, - xkb::KEY_Num_Lock => Key::NumLock, + keysyms::XKB_KEY_Select => Key::Select, + keysyms::XKB_KEY_Print => Key::PrintScreen, + keysyms::XKB_KEY_Execute => Key::Execute, + keysyms::XKB_KEY_Insert => Key::Insert, + keysyms::XKB_KEY_Undo => Key::Undo, + keysyms::XKB_KEY_Redo => Key::Redo, + keysyms::XKB_KEY_Menu => Key::ContextMenu, + keysyms::XKB_KEY_Find => Key::Find, + keysyms::XKB_KEY_Cancel => Key::Cancel, + keysyms::XKB_KEY_Help => Key::Help, + keysyms::XKB_KEY_Break => Key::Pause, + keysyms::XKB_KEY_Mode_switch => Key::ModeChange, + // keysyms::XKB_KEY_script_switch => Key::ModeChange, + keysyms::XKB_KEY_Num_Lock => Key::NumLock, // Keypad keys - // xkb::KEY_KP_Space => Key::Character(" "), - xkb::KEY_KP_Tab => Key::Tab, - xkb::KEY_KP_Enter => Key::Enter, - xkb::KEY_KP_F1 => Key::F1, - xkb::KEY_KP_F2 => Key::F2, - xkb::KEY_KP_F3 => Key::F3, - xkb::KEY_KP_F4 => Key::F4, - xkb::KEY_KP_Home => Key::Home, - xkb::KEY_KP_Left => Key::ArrowLeft, - xkb::KEY_KP_Up => Key::ArrowLeft, - xkb::KEY_KP_Right => Key::ArrowRight, - xkb::KEY_KP_Down => Key::ArrowDown, - // xkb::KEY_KP_Prior => Key::PageUp, - xkb::KEY_KP_Page_Up => Key::PageUp, - // xkb::KEY_KP_Next => Key::PageDown, - xkb::KEY_KP_Page_Down => Key::PageDown, - xkb::KEY_KP_End => Key::End, - // xkb::KEY_KP_Begin => Key::Begin, - xkb::KEY_KP_Insert => Key::Insert, - xkb::KEY_KP_Delete => Key::Delete, - // xkb::KEY_KP_Equal => Key::Equal, - // xkb::KEY_KP_Multiply => Key::Multiply, - // xkb::KEY_KP_Add => Key::Add, - // xkb::KEY_KP_Separator => Key::Separator, - // xkb::KEY_KP_Subtract => Key::Subtract, - // xkb::KEY_KP_Decimal => Key::Decimal, - // xkb::KEY_KP_Divide => Key::Divide, - - // xkb::KEY_KP_0 => Key::Character("0"), - // xkb::KEY_KP_1 => Key::Character("1"), - // xkb::KEY_KP_2 => Key::Character("2"), - // xkb::KEY_KP_3 => Key::Character("3"), - // xkb::KEY_KP_4 => Key::Character("4"), - // xkb::KEY_KP_5 => Key::Character("5"), - // xkb::KEY_KP_6 => Key::Character("6"), - // xkb::KEY_KP_7 => Key::Character("7"), - // xkb::KEY_KP_8 => Key::Character("8"), - // xkb::KEY_KP_9 => Key::Character("9"), + // keysyms::XKB_KEY_KP_Space => Key::Character(" "), + keysyms::XKB_KEY_KP_Tab => Key::Tab, + keysyms::XKB_KEY_KP_Enter => Key::Enter, + keysyms::XKB_KEY_KP_F1 => Key::F1, + keysyms::XKB_KEY_KP_F2 => Key::F2, + keysyms::XKB_KEY_KP_F3 => Key::F3, + keysyms::XKB_KEY_KP_F4 => Key::F4, + keysyms::XKB_KEY_KP_Home => Key::Home, + keysyms::XKB_KEY_KP_Left => Key::ArrowLeft, + keysyms::XKB_KEY_KP_Up => Key::ArrowLeft, + keysyms::XKB_KEY_KP_Right => Key::ArrowRight, + keysyms::XKB_KEY_KP_Down => Key::ArrowDown, + // keysyms::XKB_KEY_KP_Prior => Key::PageUp, + keysyms::XKB_KEY_KP_Page_Up => Key::PageUp, + // keysyms::XKB_KEY_KP_Next => Key::PageDown, + keysyms::XKB_KEY_KP_Page_Down => Key::PageDown, + keysyms::XKB_KEY_KP_End => Key::End, + // keysyms::XKB_KEY_KP_Begin => Key::Begin, + keysyms::XKB_KEY_KP_Insert => Key::Insert, + keysyms::XKB_KEY_KP_Delete => Key::Delete, + // keysyms::XKB_KEY_KP_Equal => Key::Equal, + // keysyms::XKB_KEY_KP_Multiply => Key::Multiply, + // keysyms::XKB_KEY_KP_Add => Key::Add, + // keysyms::XKB_KEY_KP_Separator => Key::Separator, + // keysyms::XKB_KEY_KP_Subtract => Key::Subtract, + // keysyms::XKB_KEY_KP_Decimal => Key::Decimal, + // keysyms::XKB_KEY_KP_Divide => Key::Divide, + + // keysyms::XKB_KEY_KP_0 => Key::Character("0"), + // keysyms::XKB_KEY_KP_1 => Key::Character("1"), + // keysyms::XKB_KEY_KP_2 => Key::Character("2"), + // keysyms::XKB_KEY_KP_3 => Key::Character("3"), + // keysyms::XKB_KEY_KP_4 => Key::Character("4"), + // keysyms::XKB_KEY_KP_5 => Key::Character("5"), + // keysyms::XKB_KEY_KP_6 => Key::Character("6"), + // keysyms::XKB_KEY_KP_7 => Key::Character("7"), + // keysyms::XKB_KEY_KP_8 => Key::Character("8"), + // keysyms::XKB_KEY_KP_9 => Key::Character("9"), // Function keys - xkb::KEY_F1 => Key::F1, - xkb::KEY_F2 => Key::F2, - xkb::KEY_F3 => Key::F3, - xkb::KEY_F4 => Key::F4, - xkb::KEY_F5 => Key::F5, - xkb::KEY_F6 => Key::F6, - xkb::KEY_F7 => Key::F7, - xkb::KEY_F8 => Key::F8, - xkb::KEY_F9 => Key::F9, - xkb::KEY_F10 => Key::F10, - xkb::KEY_F11 => Key::F11, - xkb::KEY_F12 => Key::F12, - xkb::KEY_F13 => Key::F13, - xkb::KEY_F14 => Key::F14, - xkb::KEY_F15 => Key::F15, - xkb::KEY_F16 => Key::F16, - xkb::KEY_F17 => Key::F17, - xkb::KEY_F18 => Key::F18, - xkb::KEY_F19 => Key::F19, - xkb::KEY_F20 => Key::F20, - xkb::KEY_F21 => Key::F21, - xkb::KEY_F22 => Key::F22, - xkb::KEY_F23 => Key::F23, - xkb::KEY_F24 => Key::F24, - xkb::KEY_F25 => Key::F25, - xkb::KEY_F26 => Key::F26, - xkb::KEY_F27 => Key::F27, - xkb::KEY_F28 => Key::F28, - xkb::KEY_F29 => Key::F29, - xkb::KEY_F30 => Key::F30, - xkb::KEY_F31 => Key::F31, - xkb::KEY_F32 => Key::F32, - xkb::KEY_F33 => Key::F33, - xkb::KEY_F34 => Key::F34, - xkb::KEY_F35 => Key::F35, + keysyms::XKB_KEY_F1 => Key::F1, + keysyms::XKB_KEY_F2 => Key::F2, + keysyms::XKB_KEY_F3 => Key::F3, + keysyms::XKB_KEY_F4 => Key::F4, + keysyms::XKB_KEY_F5 => Key::F5, + keysyms::XKB_KEY_F6 => Key::F6, + keysyms::XKB_KEY_F7 => Key::F7, + keysyms::XKB_KEY_F8 => Key::F8, + keysyms::XKB_KEY_F9 => Key::F9, + keysyms::XKB_KEY_F10 => Key::F10, + keysyms::XKB_KEY_F11 => Key::F11, + keysyms::XKB_KEY_F12 => Key::F12, + keysyms::XKB_KEY_F13 => Key::F13, + keysyms::XKB_KEY_F14 => Key::F14, + keysyms::XKB_KEY_F15 => Key::F15, + keysyms::XKB_KEY_F16 => Key::F16, + keysyms::XKB_KEY_F17 => Key::F17, + keysyms::XKB_KEY_F18 => Key::F18, + keysyms::XKB_KEY_F19 => Key::F19, + keysyms::XKB_KEY_F20 => Key::F20, + keysyms::XKB_KEY_F21 => Key::F21, + keysyms::XKB_KEY_F22 => Key::F22, + keysyms::XKB_KEY_F23 => Key::F23, + keysyms::XKB_KEY_F24 => Key::F24, + keysyms::XKB_KEY_F25 => Key::F25, + keysyms::XKB_KEY_F26 => Key::F26, + keysyms::XKB_KEY_F27 => Key::F27, + keysyms::XKB_KEY_F28 => Key::F28, + keysyms::XKB_KEY_F29 => Key::F29, + keysyms::XKB_KEY_F30 => Key::F30, + keysyms::XKB_KEY_F31 => Key::F31, + keysyms::XKB_KEY_F32 => Key::F32, + keysyms::XKB_KEY_F33 => Key::F33, + keysyms::XKB_KEY_F34 => Key::F34, + keysyms::XKB_KEY_F35 => Key::F35, // Modifiers - xkb::KEY_Shift_L => Key::Shift, - xkb::KEY_Shift_R => Key::Shift, - xkb::KEY_Control_L => Key::Control, - xkb::KEY_Control_R => Key::Control, - xkb::KEY_Caps_Lock => Key::CapsLock, - // xkb::KEY_Shift_Lock => Key::ShiftLock, + keysyms::XKB_KEY_Shift_L => Key::Shift, + keysyms::XKB_KEY_Shift_R => Key::Shift, + keysyms::XKB_KEY_Control_L => Key::Control, + keysyms::XKB_KEY_Control_R => Key::Control, + keysyms::XKB_KEY_Caps_Lock => Key::CapsLock, + // keysyms::XKB_KEY_Shift_Lock => Key::ShiftLock, // NOTE: The key xkb calls "Meta" is called "Super" by Winit, and vice versa. // This is a tad confusing, but these keys have different names depending on who you ask. - xkb::KEY_Meta_L => Key::Super, - xkb::KEY_Meta_R => Key::Super, - xkb::KEY_Alt_L => Key::Alt, - xkb::KEY_Alt_R => Key::Alt, - xkb::KEY_Super_L => Key::Meta, - xkb::KEY_Super_R => Key::Meta, - xkb::KEY_Hyper_L => Key::Hyper, - xkb::KEY_Hyper_R => Key::Hyper, + keysyms::XKB_KEY_Meta_L => Key::Super, + keysyms::XKB_KEY_Meta_R => Key::Super, + keysyms::XKB_KEY_Alt_L => Key::Alt, + keysyms::XKB_KEY_Alt_R => Key::Alt, + keysyms::XKB_KEY_Super_L => Key::Meta, + keysyms::XKB_KEY_Super_R => Key::Meta, + keysyms::XKB_KEY_Hyper_L => Key::Hyper, + keysyms::XKB_KEY_Hyper_R => Key::Hyper, // XKB function and modifier keys - // xkb::KEY_ISO_Lock => Key::IsoLock, - // xkb::KEY_ISO_Level2_Latch => Key::IsoLevel2Latch, + // keysyms::XKB_KEY_ISO_Lock => Key::IsoLock, + // keysyms::XKB_KEY_ISO_Level2_Latch => Key::IsoLevel2Latch, // NOTE: I'm not quite certain if mapping the next 3 values to AltGraph is correct. - // xkb::KEY_ISO_Level3_Shift => Key::AltGraph, - // xkb::KEY_ISO_Level3_Latch => Key::AltGraph, - // xkb::KEY_ISO_Level3_Lock => Key::AltGraph, - // xkb::KEY_ISO_Level5_Shift => Key::IsoLevel5Shift, - // xkb::KEY_ISO_Level5_Latch => Key::IsoLevel5Latch, - // xkb::KEY_ISO_Level5_Lock => Key::IsoLevel5Lock, - // xkb::KEY_ISO_Group_Shift => Key::IsoGroupShift, - // xkb::KEY_ISO_Group_Latch => Key::IsoGroupLatch, - // xkb::KEY_ISO_Group_Lock => Key::IsoGroupLock, - xkb::KEY_ISO_Next_Group => Key::GroupNext, - // xkb::KEY_ISO_Next_Group_Lock => Key::GroupNextLock, - xkb::KEY_ISO_Prev_Group => Key::GroupPrevious, - // xkb::KEY_ISO_Prev_Group_Lock => Key::GroupPreviousLock, - xkb::KEY_ISO_First_Group => Key::GroupFirst, - // xkb::KEY_ISO_First_Group_Lock => Key::GroupFirstLock, - xkb::KEY_ISO_Last_Group => Key::GroupLast, - // xkb::KEY_ISO_Last_Group_Lock => Key::GroupLastLock, + // keysyms::XKB_KEY_ISO_Level3_Shift => Key::AltGraph, + // keysyms::XKB_KEY_ISO_Level3_Latch => Key::AltGraph, + // keysyms::XKB_KEY_ISO_Level3_Lock => Key::AltGraph, + // keysyms::XKB_KEY_ISO_Level5_Shift => Key::IsoLevel5Shift, + // keysyms::XKB_KEY_ISO_Level5_Latch => Key::IsoLevel5Latch, + // keysyms::XKB_KEY_ISO_Level5_Lock => Key::IsoLevel5Lock, + // keysyms::XKB_KEY_ISO_Group_Shift => Key::IsoGroupShift, + // keysyms::XKB_KEY_ISO_Group_Latch => Key::IsoGroupLatch, + // keysyms::XKB_KEY_ISO_Group_Lock => Key::IsoGroupLock, + keysyms::XKB_KEY_ISO_Next_Group => Key::GroupNext, + // keysyms::XKB_KEY_ISO_Next_Group_Lock => Key::GroupNextLock, + keysyms::XKB_KEY_ISO_Prev_Group => Key::GroupPrevious, + // keysyms::XKB_KEY_ISO_Prev_Group_Lock => Key::GroupPreviousLock, + keysyms::XKB_KEY_ISO_First_Group => Key::GroupFirst, + // keysyms::XKB_KEY_ISO_First_Group_Lock => Key::GroupFirstLock, + keysyms::XKB_KEY_ISO_Last_Group => Key::GroupLast, + // keysyms::XKB_KEY_ISO_Last_Group_Lock => Key::GroupLastLock, // - xkb::KEY_ISO_Left_Tab => Key::Tab, - // xkb::KEY_ISO_Move_Line_Up => Key::IsoMoveLineUp, - // xkb::KEY_ISO_Move_Line_Down => Key::IsoMoveLineDown, - // xkb::KEY_ISO_Partial_Line_Up => Key::IsoPartialLineUp, - // xkb::KEY_ISO_Partial_Line_Down => Key::IsoPartialLineDown, - // xkb::KEY_ISO_Partial_Space_Left => Key::IsoPartialSpaceLeft, - // xkb::KEY_ISO_Partial_Space_Right => Key::IsoPartialSpaceRight, - // xkb::KEY_ISO_Set_Margin_Left => Key::IsoSetMarginLeft, - // xkb::KEY_ISO_Set_Margin_Right => Key::IsoSetMarginRight, - // xkb::KEY_ISO_Release_Margin_Left => Key::IsoReleaseMarginLeft, - // xkb::KEY_ISO_Release_Margin_Right => Key::IsoReleaseMarginRight, - // xkb::KEY_ISO_Release_Both_Margins => Key::IsoReleaseBothMargins, - // xkb::KEY_ISO_Fast_Cursor_Left => Key::IsoFastCursorLeft, - // xkb::KEY_ISO_Fast_Cursor_Right => Key::IsoFastCursorRight, - // xkb::KEY_ISO_Fast_Cursor_Up => Key::IsoFastCursorUp, - // xkb::KEY_ISO_Fast_Cursor_Down => Key::IsoFastCursorDown, - // xkb::KEY_ISO_Continuous_Underline => Key::IsoContinuousUnderline, - // xkb::KEY_ISO_Discontinuous_Underline => Key::IsoDiscontinuousUnderline, - // xkb::KEY_ISO_Emphasize => Key::IsoEmphasize, - // xkb::KEY_ISO_Center_Object => Key::IsoCenterObject, - xkb::KEY_ISO_Enter => Key::Enter, + keysyms::XKB_KEY_ISO_Left_Tab => Key::Tab, + // keysyms::XKB_KEY_ISO_Move_Line_Up => Key::IsoMoveLineUp, + // keysyms::XKB_KEY_ISO_Move_Line_Down => Key::IsoMoveLineDown, + // keysyms::XKB_KEY_ISO_Partial_Line_Up => Key::IsoPartialLineUp, + // keysyms::XKB_KEY_ISO_Partial_Line_Down => Key::IsoPartialLineDown, + // keysyms::XKB_KEY_ISO_Partial_Space_Left => Key::IsoPartialSpaceLeft, + // keysyms::XKB_KEY_ISO_Partial_Space_Right => Key::IsoPartialSpaceRight, + // keysyms::XKB_KEY_ISO_Set_Margin_Left => Key::IsoSetMarginLeft, + // keysyms::XKB_KEY_ISO_Set_Margin_Right => Key::IsoSetMarginRight, + // keysyms::XKB_KEY_ISO_Release_Margin_Left => Key::IsoReleaseMarginLeft, + // keysyms::XKB_KEY_ISO_Release_Margin_Right => Key::IsoReleaseMarginRight, + // keysyms::XKB_KEY_ISO_Release_Both_Margins => Key::IsoReleaseBothMargins, + // keysyms::XKB_KEY_ISO_Fast_Cursor_Left => Key::IsoFastCursorLeft, + // keysyms::XKB_KEY_ISO_Fast_Cursor_Right => Key::IsoFastCursorRight, + // keysyms::XKB_KEY_ISO_Fast_Cursor_Up => Key::IsoFastCursorUp, + // keysyms::XKB_KEY_ISO_Fast_Cursor_Down => Key::IsoFastCursorDown, + // keysyms::XKB_KEY_ISO_Continuous_Underline => Key::IsoContinuousUnderline, + // keysyms::XKB_KEY_ISO_Discontinuous_Underline => Key::IsoDiscontinuousUnderline, + // keysyms::XKB_KEY_ISO_Emphasize => Key::IsoEmphasize, + // keysyms::XKB_KEY_ISO_Center_Object => Key::IsoCenterObject, + keysyms::XKB_KEY_ISO_Enter => Key::Enter, - // KEY_dead_grave..KEY_dead_currency + // XKB_KEY_dead_grave..XKB_KEY_dead_currency - // KEY_dead_lowline..KEY_dead_longsolidusoverlay + // XKB_KEY_dead_lowline..XKB_KEY_dead_longsolidusoverlay - // KEY_dead_a..KEY_dead_capital_schwa + // XKB_KEY_dead_a..XKB_KEY_dead_capital_schwa - // KEY_dead_greek + // XKB_KEY_dead_greek - // KEY_First_Virtual_Screen..KEY_Terminate_Server + // XKB_KEY_First_Virtual_Screen..XKB_KEY_Terminate_Server - // KEY_AccessX_Enable..KEY_AudibleBell_Enable + // XKB_KEY_AccessX_Enable..XKB_KEY_AudibleBell_Enable - // KEY_Pointer_Left..KEY_Pointer_Drag5 + // XKB_KEY_Pointer_Left..XKB_KEY_Pointer_Drag5 - // KEY_Pointer_EnableKeys..KEY_Pointer_DfltBtnPrev + // XKB_KEY_Pointer_EnableKeys..XKB_KEY_Pointer_DfltBtnPrev - // KEY_ch..KEY_C_H + // XKB_KEY_ch..XKB_KEY_C_H // 3270 terminal keys - // xkb::KEY_3270_Duplicate => Key::Duplicate, - // xkb::KEY_3270_FieldMark => Key::FieldMark, - // xkb::KEY_3270_Right2 => Key::Right2, - // xkb::KEY_3270_Left2 => Key::Left2, - // xkb::KEY_3270_BackTab => Key::BackTab, - xkb::KEY_3270_EraseEOF => Key::EraseEof, - // xkb::KEY_3270_EraseInput => Key::EraseInput, - // xkb::KEY_3270_Reset => Key::Reset, - // xkb::KEY_3270_Quit => Key::Quit, - // xkb::KEY_3270_PA1 => Key::Pa1, - // xkb::KEY_3270_PA2 => Key::Pa2, - // xkb::KEY_3270_PA3 => Key::Pa3, - // xkb::KEY_3270_Test => Key::Test, - xkb::KEY_3270_Attn => Key::Attn, - // xkb::KEY_3270_CursorBlink => Key::CursorBlink, - // xkb::KEY_3270_AltCursor => Key::AltCursor, - // xkb::KEY_3270_KeyClick => Key::KeyClick, - // xkb::KEY_3270_Jump => Key::Jump, - // xkb::KEY_3270_Ident => Key::Ident, - // xkb::KEY_3270_Rule => Key::Rule, - // xkb::KEY_3270_Copy => Key::Copy, - xkb::KEY_3270_Play => Key::Play, - // xkb::KEY_3270_Setup => Key::Setup, - // xkb::KEY_3270_Record => Key::Record, - // xkb::KEY_3270_ChangeScreen => Key::ChangeScreen, - // xkb::KEY_3270_DeleteWord => Key::DeleteWord, - xkb::KEY_3270_ExSelect => Key::ExSel, - xkb::KEY_3270_CursorSelect => Key::CrSel, - xkb::KEY_3270_PrintScreen => Key::PrintScreen, - xkb::KEY_3270_Enter => Key::Enter, - - xkb::KEY_space => Key::Space, - // KEY_exclam..KEY_Sinh_kunddaliya + // keysyms::XKB_KEY_3270_Duplicate => Key::Duplicate, + // keysyms::XKB_KEY_3270_FieldMark => Key::FieldMark, + // keysyms::XKB_KEY_3270_Right2 => Key::Right2, + // keysyms::XKB_KEY_3270_Left2 => Key::Left2, + // keysyms::XKB_KEY_3270_BackTab => Key::BackTab, + keysyms::XKB_KEY_3270_EraseEOF => Key::EraseEof, + // keysyms::XKB_KEY_3270_EraseInput => Key::EraseInput, + // keysyms::XKB_KEY_3270_Reset => Key::Reset, + // keysyms::XKB_KEY_3270_Quit => Key::Quit, + // keysyms::XKB_KEY_3270_PA1 => Key::Pa1, + // keysyms::XKB_KEY_3270_PA2 => Key::Pa2, + // keysyms::XKB_KEY_3270_PA3 => Key::Pa3, + // keysyms::XKB_KEY_3270_Test => Key::Test, + keysyms::XKB_KEY_3270_Attn => Key::Attn, + // keysyms::XKB_KEY_3270_CursorBlink => Key::CursorBlink, + // keysyms::XKB_KEY_3270_AltCursor => Key::AltCursor, + // keysyms::XKB_KEY_3270_KeyClick => Key::KeyClick, + // keysyms::XKB_KEY_3270_Jump => Key::Jump, + // keysyms::XKB_KEY_3270_Ident => Key::Ident, + // keysyms::XKB_KEY_3270_Rule => Key::Rule, + // keysyms::XKB_KEY_3270_Copy => Key::Copy, + keysyms::XKB_KEY_3270_Play => Key::Play, + // keysyms::XKB_KEY_3270_Setup => Key::Setup, + // keysyms::XKB_KEY_3270_Record => Key::Record, + // keysyms::XKB_KEY_3270_ChangeScreen => Key::ChangeScreen, + // keysyms::XKB_KEY_3270_DeleteWord => Key::DeleteWord, + keysyms::XKB_KEY_3270_ExSelect => Key::ExSel, + keysyms::XKB_KEY_3270_CursorSelect => Key::CrSel, + keysyms::XKB_KEY_3270_PrintScreen => Key::PrintScreen, + keysyms::XKB_KEY_3270_Enter => Key::Enter, + + keysyms::XKB_KEY_space => Key::Space, + // XKB_KEY_exclam..XKB_KEY_Sinh_kunddaliya // XFree86 - // xkb::KEY_XF86ModeLock => Key::ModeLock, + // keysyms::XKB_KEY_XF86ModeLock => Key::ModeLock, // XFree86 - Backlight controls - xkb::KEY_XF86MonBrightnessUp => Key::BrightnessUp, - xkb::KEY_XF86MonBrightnessDown => Key::BrightnessDown, - // xkb::KEY_XF86KbdLightOnOff => Key::LightOnOff, - // xkb::KEY_XF86KbdBrightnessUp => Key::KeyboardBrightnessUp, - // xkb::KEY_XF86KbdBrightnessDown => Key::KeyboardBrightnessDown, + keysyms::XKB_KEY_XF86MonBrightnessUp => Key::BrightnessUp, + keysyms::XKB_KEY_XF86MonBrightnessDown => Key::BrightnessDown, + // keysyms::XKB_KEY_XF86KbdLightOnOff => Key::LightOnOff, + // keysyms::XKB_KEY_XF86KbdBrightnessUp => Key::KeyboardBrightnessUp, + // keysyms::XKB_KEY_XF86KbdBrightnessDown => Key::KeyboardBrightnessDown, // XFree86 - "Internet" - xkb::KEY_XF86Standby => Key::Standby, - xkb::KEY_XF86AudioLowerVolume => Key::AudioVolumeDown, - xkb::KEY_XF86AudioRaiseVolume => Key::AudioVolumeUp, - xkb::KEY_XF86AudioPlay => Key::MediaPlay, - xkb::KEY_XF86AudioStop => Key::MediaStop, - xkb::KEY_XF86AudioPrev => Key::MediaTrackPrevious, - xkb::KEY_XF86AudioNext => Key::MediaTrackNext, - xkb::KEY_XF86HomePage => Key::BrowserHome, - xkb::KEY_XF86Mail => Key::LaunchMail, - // xkb::KEY_XF86Start => Key::Start, - xkb::KEY_XF86Search => Key::BrowserSearch, - xkb::KEY_XF86AudioRecord => Key::MediaRecord, + keysyms::XKB_KEY_XF86Standby => Key::Standby, + keysyms::XKB_KEY_XF86AudioLowerVolume => Key::AudioVolumeDown, + keysyms::XKB_KEY_XF86AudioRaiseVolume => Key::AudioVolumeUp, + keysyms::XKB_KEY_XF86AudioPlay => Key::MediaPlay, + keysyms::XKB_KEY_XF86AudioStop => Key::MediaStop, + keysyms::XKB_KEY_XF86AudioPrev => Key::MediaTrackPrevious, + keysyms::XKB_KEY_XF86AudioNext => Key::MediaTrackNext, + keysyms::XKB_KEY_XF86HomePage => Key::BrowserHome, + keysyms::XKB_KEY_XF86Mail => Key::LaunchMail, + // keysyms::XKB_KEY_XF86Start => Key::Start, + keysyms::XKB_KEY_XF86Search => Key::BrowserSearch, + keysyms::XKB_KEY_XF86AudioRecord => Key::MediaRecord, // XFree86 - PDA - xkb::KEY_XF86Calculator => Key::LaunchApplication2, - // xkb::KEY_XF86Memo => Key::Memo, - // xkb::KEY_XF86ToDoList => Key::ToDoList, - xkb::KEY_XF86Calendar => Key::LaunchCalendar, - xkb::KEY_XF86PowerDown => Key::Power, - // xkb::KEY_XF86ContrastAdjust => Key::AdjustContrast, - // xkb::KEY_XF86RockerUp => Key::RockerUp, // TODO: Use Key::ArrowUp? - // xkb::KEY_XF86RockerDown => Key::RockerDown, // TODO: Use Key::ArrowDown? - // xkb::KEY_XF86RockerEnter => Key::RockerEnter, // TODO: Use Key::Enter? + keysyms::XKB_KEY_XF86Calculator => Key::LaunchApplication2, + // keysyms::XKB_KEY_XF86Memo => Key::Memo, + // keysyms::XKB_KEY_XF86ToDoList => Key::ToDoList, + keysyms::XKB_KEY_XF86Calendar => Key::LaunchCalendar, + keysyms::XKB_KEY_XF86PowerDown => Key::Power, + // keysyms::XKB_KEY_XF86ContrastAdjust => Key::AdjustContrast, + // keysyms::XKB_KEY_XF86RockerUp => Key::RockerUp, // TODO: Use Key::ArrowUp? + // keysyms::XKB_KEY_XF86RockerDown => Key::RockerDown, // TODO: Use Key::ArrowDown? + // keysyms::XKB_KEY_XF86RockerEnter => Key::RockerEnter, // TODO: Use Key::Enter? // XFree86 - More "Internet" - xkb::KEY_XF86Back => Key::BrowserBack, - xkb::KEY_XF86Forward => Key::BrowserForward, - // xkb::KEY_XF86Stop => Key::Stop, - xkb::KEY_XF86Refresh => Key::BrowserRefresh, - xkb::KEY_XF86PowerOff => Key::Power, - xkb::KEY_XF86WakeUp => Key::WakeUp, - xkb::KEY_XF86Eject => Key::Eject, - xkb::KEY_XF86ScreenSaver => Key::LaunchScreenSaver, - xkb::KEY_XF86WWW => Key::LaunchWebBrowser, - xkb::KEY_XF86Sleep => Key::Standby, - xkb::KEY_XF86Favorites => Key::BrowserFavorites, - xkb::KEY_XF86AudioPause => Key::MediaPause, - // xkb::KEY_XF86AudioMedia => Key::AudioMedia, - xkb::KEY_XF86MyComputer => Key::LaunchApplication1, - // xkb::KEY_XF86VendorHome => Key::VendorHome, - // xkb::KEY_XF86LightBulb => Key::LightBulb, - // xkb::KEY_XF86Shop => Key::BrowserShop, - // xkb::KEY_XF86History => Key::BrowserHistory, - // xkb::KEY_XF86OpenURL => Key::OpenUrl, - // xkb::KEY_XF86AddFavorite => Key::AddFavorite, - // xkb::KEY_XF86HotLinks => Key::HotLinks, - // xkb::KEY_XF86BrightnessAdjust => Key::BrightnessAdjust, - // xkb::KEY_XF86Finance => Key::BrowserFinance, - // xkb::KEY_XF86Community => Key::BrowserCommunity, - xkb::KEY_XF86AudioRewind => Key::MediaRewind, - // xkb::KEY_XF86BackForward => Key::???, - // KEY_XF86Launch0..KEY_XF86LaunchF - - // KEY_XF86ApplicationLeft..KEY_XF86CD - xkb::KEY_XF86Calculater => Key::LaunchApplication2, // This must be a typo, right? - // KEY_XF86Clear - xkb::KEY_XF86Close => Key::Close, - xkb::KEY_XF86Copy => Key::Copy, - xkb::KEY_XF86Cut => Key::Cut, - // KEY_XF86Display..KEY_XF86Documents - xkb::KEY_XF86Excel => Key::LaunchSpreadsheet, - // KEY_XF86Explorer..KEY_XF86iTouch - xkb::KEY_XF86LogOff => Key::LogOff, - // KEY_XF86Market..KEY_XF86MenuPB - xkb::KEY_XF86MySites => Key::BrowserFavorites, - xkb::KEY_XF86New => Key::New, - // KEY_XF86News..KEY_XF86OfficeHome - xkb::KEY_XF86Open => Key::Open, - // KEY_XF86Option - xkb::KEY_XF86Paste => Key::Paste, - xkb::KEY_XF86Phone => Key::LaunchPhone, - // KEY_XF86Q - xkb::KEY_XF86Reply => Key::MailReply, - xkb::KEY_XF86Reload => Key::BrowserRefresh, - // KEY_XF86RotateWindows..KEY_XF86RotationKB - xkb::KEY_XF86Save => Key::Save, - // KEY_XF86ScrollUp..KEY_XF86ScrollClick - xkb::KEY_XF86Send => Key::MailSend, - xkb::KEY_XF86Spell => Key::SpellCheck, - xkb::KEY_XF86SplitScreen => Key::SplitScreenToggle, - // KEY_XF86Support..KEY_XF86User2KB - xkb::KEY_XF86Video => Key::LaunchMediaPlayer, - // KEY_XF86WheelButton - xkb::KEY_XF86Word => Key::LaunchWordProcessor, - // KEY_XF86Xfer - xkb::KEY_XF86ZoomIn => Key::ZoomIn, - xkb::KEY_XF86ZoomOut => Key::ZoomOut, - - // KEY_XF86Away..KEY_XF86Messenger - xkb::KEY_XF86WebCam => Key::LaunchWebCam, - xkb::KEY_XF86MailForward => Key::MailForward, - // KEY_XF86Pictures - xkb::KEY_XF86Music => Key::LaunchMusicPlayer, - - // KEY_XF86Battery..KEY_XF86UWB + keysyms::XKB_KEY_XF86Back => Key::BrowserBack, + keysyms::XKB_KEY_XF86Forward => Key::BrowserForward, + // keysyms::XKB_KEY_XF86Stop => Key::Stop, + keysyms::XKB_KEY_XF86Refresh => Key::BrowserRefresh, + keysyms::XKB_KEY_XF86PowerOff => Key::Power, + keysyms::XKB_KEY_XF86WakeUp => Key::WakeUp, + keysyms::XKB_KEY_XF86Eject => Key::Eject, + keysyms::XKB_KEY_XF86ScreenSaver => Key::LaunchScreenSaver, + keysyms::XKB_KEY_XF86WWW => Key::LaunchWebBrowser, + keysyms::XKB_KEY_XF86Sleep => Key::Standby, + keysyms::XKB_KEY_XF86Favorites => Key::BrowserFavorites, + keysyms::XKB_KEY_XF86AudioPause => Key::MediaPause, + // keysyms::XKB_KEY_XF86AudioMedia => Key::AudioMedia, + keysyms::XKB_KEY_XF86MyComputer => Key::LaunchApplication1, + // keysyms::XKB_KEY_XF86VendorHome => Key::VendorHome, + // keysyms::XKB_KEY_XF86LightBulb => Key::LightBulb, + // keysyms::XKB_KEY_XF86Shop => Key::BrowserShop, + // keysyms::XKB_KEY_XF86History => Key::BrowserHistory, + // keysyms::XKB_KEY_XF86OpenURL => Key::OpenUrl, + // keysyms::XKB_KEY_XF86AddFavorite => Key::AddFavorite, + // keysyms::XKB_KEY_XF86HotLinks => Key::HotLinks, + // keysyms::XKB_KEY_XF86BrightnessAdjust => Key::BrightnessAdjust, + // keysyms::XKB_KEY_XF86Finance => Key::BrowserFinance, + // keysyms::XKB_KEY_XF86Community => Key::BrowserCommunity, + keysyms::XKB_KEY_XF86AudioRewind => Key::MediaRewind, + // keysyms::XKB_KEY_XF86BackForward => Key::???, + // XKB_KEY_XF86Launch0..XKB_KEY_XF86LaunchF + + // XKB_KEY_XF86ApplicationLeft..XKB_KEY_XF86CD + keysyms::XKB_KEY_XF86Calculater => Key::LaunchApplication2, // This must be a typo, right? + // XKB_KEY_XF86Clear + keysyms::XKB_KEY_XF86Close => Key::Close, + keysyms::XKB_KEY_XF86Copy => Key::Copy, + keysyms::XKB_KEY_XF86Cut => Key::Cut, + // XKB_KEY_XF86Display..XKB_KEY_XF86Documents + keysyms::XKB_KEY_XF86Excel => Key::LaunchSpreadsheet, + // XKB_KEY_XF86Explorer..XKB_KEY_XF86iTouch + keysyms::XKB_KEY_XF86LogOff => Key::LogOff, + // XKB_KEY_XF86Market..XKB_KEY_XF86MenuPB + keysyms::XKB_KEY_XF86MySites => Key::BrowserFavorites, + keysyms::XKB_KEY_XF86New => Key::New, + // XKB_KEY_XF86News..XKB_KEY_XF86OfficeHome + keysyms::XKB_KEY_XF86Open => Key::Open, + // XKB_KEY_XF86Option + keysyms::XKB_KEY_XF86Paste => Key::Paste, + keysyms::XKB_KEY_XF86Phone => Key::LaunchPhone, + // XKB_KEY_XF86Q + keysyms::XKB_KEY_XF86Reply => Key::MailReply, + keysyms::XKB_KEY_XF86Reload => Key::BrowserRefresh, + // XKB_KEY_XF86RotateWindows..XKB_KEY_XF86RotationKB + keysyms::XKB_KEY_XF86Save => Key::Save, + // XKB_KEY_XF86ScrollUp..XKB_KEY_XF86ScrollClick + keysyms::XKB_KEY_XF86Send => Key::MailSend, + keysyms::XKB_KEY_XF86Spell => Key::SpellCheck, + keysyms::XKB_KEY_XF86SplitScreen => Key::SplitScreenToggle, + // XKB_KEY_XF86Support..XKB_KEY_XF86User2KB + keysyms::XKB_KEY_XF86Video => Key::LaunchMediaPlayer, + // XKB_KEY_XF86WheelButton + keysyms::XKB_KEY_XF86Word => Key::LaunchWordProcessor, + // XKB_KEY_XF86Xfer + keysyms::XKB_KEY_XF86ZoomIn => Key::ZoomIn, + keysyms::XKB_KEY_XF86ZoomOut => Key::ZoomOut, + + // XKB_KEY_XF86Away..XKB_KEY_XF86Messenger + keysyms::XKB_KEY_XF86WebCam => Key::LaunchWebCam, + keysyms::XKB_KEY_XF86MailForward => Key::MailForward, + // XKB_KEY_XF86Pictures + keysyms::XKB_KEY_XF86Music => Key::LaunchMusicPlayer, + + // XKB_KEY_XF86Battery..XKB_KEY_XF86UWB // - xkb::KEY_XF86AudioForward => Key::MediaFastForward, - // KEY_XF86AudioRepeat - xkb::KEY_XF86AudioRandomPlay => Key::RandomToggle, - xkb::KEY_XF86Subtitle => Key::Subtitle, - xkb::KEY_XF86AudioCycleTrack => Key::MediaAudioTrack, - // KEY_XF86CycleAngle..KEY_XF86Blue + keysyms::XKB_KEY_XF86AudioForward => Key::MediaFastForward, + // XKB_KEY_XF86AudioRepeat + keysyms::XKB_KEY_XF86AudioRandomPlay => Key::RandomToggle, + keysyms::XKB_KEY_XF86Subtitle => Key::Subtitle, + keysyms::XKB_KEY_XF86AudioCycleTrack => Key::MediaAudioTrack, + // XKB_KEY_XF86CycleAngle..XKB_KEY_XF86Blue // - xkb::KEY_XF86Suspend => Key::Standby, - xkb::KEY_XF86Hibernate => Key::Hibernate, - // KEY_XF86TouchpadToggle..KEY_XF86TouchpadOff + keysyms::XKB_KEY_XF86Suspend => Key::Standby, + keysyms::XKB_KEY_XF86Hibernate => Key::Hibernate, + // XKB_KEY_XF86TouchpadToggle..XKB_KEY_XF86TouchpadOff // - xkb::KEY_XF86AudioMute => Key::AudioVolumeMute, - - // KEY_XF86Switch_VT_1..KEY_XF86Switch_VT_12 - - // KEY_XF86Ungrab..KEY_XF86ClearGrab - xkb::KEY_XF86Next_VMode => Key::VideoModeNext, - // xkb::KEY_XF86Prev_VMode => Key::VideoModePrevious, - // KEY_XF86LogWindowTree..KEY_XF86LogGrabInfo - - // KEY_SunFA_Grave..KEY_SunFA_Cedilla - - // xkb::KEY_SunF36 => Key::F36 | Key::F11, - // xkb::KEY_SunF37 => Key::F37 | Key::F12, - - // xkb::KEY_SunSys_Req => Key::PrintScreen, - // The next couple of xkb (until KEY_SunStop) are already handled. - // KEY_SunPrint_Screen..KEY_SunPageDown - - // KEY_SunUndo..KEY_SunFront - xkb::KEY_SunCopy => Key::Copy, - xkb::KEY_SunOpen => Key::Open, - xkb::KEY_SunPaste => Key::Paste, - xkb::KEY_SunCut => Key::Cut, - - // KEY_SunPowerSwitch - xkb::KEY_SunAudioLowerVolume => Key::AudioVolumeDown, - xkb::KEY_SunAudioMute => Key::AudioVolumeMute, - xkb::KEY_SunAudioRaiseVolume => Key::AudioVolumeUp, - // KEY_SunVideoDegauss - xkb::KEY_SunVideoLowerBrightness => Key::BrightnessDown, - xkb::KEY_SunVideoRaiseBrightness => Key::BrightnessUp, - // KEY_SunPowerSwitchShift + keysyms::XKB_KEY_XF86AudioMute => Key::AudioVolumeMute, + + // XKB_KEY_XF86Switch_VT_1..XKB_KEY_XF86Switch_VT_12 + + // XKB_KEY_XF86Ungrab..XKB_KEY_XF86ClearGrab + keysyms::XKB_KEY_XF86Next_VMode => Key::VideoModeNext, + // keysyms::XKB_KEY_XF86Prev_VMode => Key::VideoModePrevious, + // XKB_KEY_XF86LogWindowTree..XKB_KEY_XF86LogGrabInfo + + // XKB_KEY_SunFA_Grave..XKB_KEY_SunFA_Cedilla + + // keysyms::XKB_KEY_SunF36 => Key::F36 | Key::F11, + // keysyms::XKB_KEY_SunF37 => Key::F37 | Key::F12, + + // keysyms::XKB_KEY_SunSys_Req => Key::PrintScreen, + // The next couple of xkb (until XKB_KEY_SunStop) are already handled. + // XKB_KEY_SunPrint_Screen..XKB_KEY_SunPageDown + + // XKB_KEY_SunUndo..XKB_KEY_SunFront + keysyms::XKB_KEY_SunCopy => Key::Copy, + keysyms::XKB_KEY_SunOpen => Key::Open, + keysyms::XKB_KEY_SunPaste => Key::Paste, + keysyms::XKB_KEY_SunCut => Key::Cut, + + // XKB_KEY_SunPowerSwitch + keysyms::XKB_KEY_SunAudioLowerVolume => Key::AudioVolumeDown, + keysyms::XKB_KEY_SunAudioMute => Key::AudioVolumeMute, + keysyms::XKB_KEY_SunAudioRaiseVolume => Key::AudioVolumeUp, + // XKB_KEY_SunVideoDegauss + keysyms::XKB_KEY_SunVideoLowerBrightness => Key::BrightnessDown, + keysyms::XKB_KEY_SunVideoRaiseBrightness => Key::BrightnessUp, + // XKB_KEY_SunPowerSwitchShift // _ => Key::Unidentified(NativeKeyCode::XKB(keysym)), } } pub fn keysym_location(keysym: u32) -> KeyLocation { - use xkbcommon::xkb; + use xkbcommon_dl::keysyms; match keysym { - xkb::KEY_Shift_L - | xkb::KEY_Control_L - | xkb::KEY_Meta_L - | xkb::KEY_Alt_L - | xkb::KEY_Super_L - | xkb::KEY_Hyper_L => KeyLocation::Left, - xkb::KEY_Shift_R - | xkb::KEY_Control_R - | xkb::KEY_Meta_R - | xkb::KEY_Alt_R - | xkb::KEY_Super_R - | xkb::KEY_Hyper_R => KeyLocation::Right, - xkb::KEY_KP_0 - | xkb::KEY_KP_1 - | xkb::KEY_KP_2 - | xkb::KEY_KP_3 - | xkb::KEY_KP_4 - | xkb::KEY_KP_5 - | xkb::KEY_KP_6 - | xkb::KEY_KP_7 - | xkb::KEY_KP_8 - | xkb::KEY_KP_9 - | xkb::KEY_KP_Space - | xkb::KEY_KP_Tab - | xkb::KEY_KP_Enter - | xkb::KEY_KP_F1 - | xkb::KEY_KP_F2 - | xkb::KEY_KP_F3 - | xkb::KEY_KP_F4 - | xkb::KEY_KP_Home - | xkb::KEY_KP_Left - | xkb::KEY_KP_Up - | xkb::KEY_KP_Right - | xkb::KEY_KP_Down - | xkb::KEY_KP_Page_Up - | xkb::KEY_KP_Page_Down - | xkb::KEY_KP_End - | xkb::KEY_KP_Begin - | xkb::KEY_KP_Insert - | xkb::KEY_KP_Delete - | xkb::KEY_KP_Equal - | xkb::KEY_KP_Multiply - | xkb::KEY_KP_Add - | xkb::KEY_KP_Separator - | xkb::KEY_KP_Subtract - | xkb::KEY_KP_Decimal - | xkb::KEY_KP_Divide => KeyLocation::Numpad, + keysyms::XKB_KEY_Shift_L + | keysyms::XKB_KEY_Control_L + | keysyms::XKB_KEY_Meta_L + | keysyms::XKB_KEY_Alt_L + | keysyms::XKB_KEY_Super_L + | keysyms::XKB_KEY_Hyper_L => KeyLocation::Left, + keysyms::XKB_KEY_Shift_R + | keysyms::XKB_KEY_Control_R + | keysyms::XKB_KEY_Meta_R + | keysyms::XKB_KEY_Alt_R + | keysyms::XKB_KEY_Super_R + | keysyms::XKB_KEY_Hyper_R => KeyLocation::Right, + keysyms::XKB_KEY_KP_0 + | keysyms::XKB_KEY_KP_1 + | keysyms::XKB_KEY_KP_2 + | keysyms::XKB_KEY_KP_3 + | keysyms::XKB_KEY_KP_4 + | keysyms::XKB_KEY_KP_5 + | keysyms::XKB_KEY_KP_6 + | keysyms::XKB_KEY_KP_7 + | keysyms::XKB_KEY_KP_8 + | keysyms::XKB_KEY_KP_9 + | keysyms::XKB_KEY_KP_Space + | keysyms::XKB_KEY_KP_Tab + | keysyms::XKB_KEY_KP_Enter + | keysyms::XKB_KEY_KP_F1 + | keysyms::XKB_KEY_KP_F2 + | keysyms::XKB_KEY_KP_F3 + | keysyms::XKB_KEY_KP_F4 + | keysyms::XKB_KEY_KP_Home + | keysyms::XKB_KEY_KP_Left + | keysyms::XKB_KEY_KP_Up + | keysyms::XKB_KEY_KP_Right + | keysyms::XKB_KEY_KP_Down + | keysyms::XKB_KEY_KP_Page_Up + | keysyms::XKB_KEY_KP_Page_Down + | keysyms::XKB_KEY_KP_End + | keysyms::XKB_KEY_KP_Begin + | keysyms::XKB_KEY_KP_Insert + | keysyms::XKB_KEY_KP_Delete + | keysyms::XKB_KEY_KP_Equal + | keysyms::XKB_KEY_KP_Multiply + | keysyms::XKB_KEY_KP_Add + | keysyms::XKB_KEY_KP_Separator + | keysyms::XKB_KEY_KP_Subtract + | keysyms::XKB_KEY_KP_Decimal + | keysyms::XKB_KEY_KP_Divide => KeyLocation::Numpad, _ => KeyLocation::Standard, } } From 2ee35f489c48c7b623f67ecb76b31484d5c4aab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Wed, 31 Mar 2021 04:31:56 +0200 Subject: [PATCH 09/53] Hoist keyboard handling code from sctk into Winit --- Cargo.toml | 5 +- src/platform_impl/linux/common/mod.rs | 1 + src/platform_impl/linux/common/xkb_state.rs | 383 +++++++++++ .../linux/wayland/seat/keyboard/handlers.rs | 601 +++++++++++++++++- .../linux/wayland/seat/keyboard/mod.rs | 30 +- 5 files changed, 992 insertions(+), 28 deletions(-) create mode 100644 src/platform_impl/linux/common/xkb_state.rs diff --git a/Cargo.toml b/Cargo.toml index ac3d76aab9..140ffcb2b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ targets = ["i686-pc-windows-msvc", "x86_64-pc-windows-msvc", "i686-unknown-linux [features] default = ["x11", "wayland", "wayland-dlopen"] x11 = ["x11-dl", "mio", "percent-encoding", "parking_lot"] -wayland = ["wayland-client", "wayland-protocols", "sctk"] +wayland = ["wayland-client", "wayland-protocols", "sctk", "memmap2"] wayland-dlopen = ["sctk/dlopen", "wayland-client/dlopen"] [dependencies] @@ -96,7 +96,8 @@ x11-dl = { version = "2.18.5", optional = true } percent-encoding = { version = "2.0", optional = true } parking_lot = { version = "0.11.0", optional = true } libc = "0.2.64" -xkbcommon-dl = { git = "https://github.com/maroider/xkbcommon-dl", rev = "224646a" } +memmap2 = { version = "0.2.1", optional = true } +xkbcommon-dl = { git = "https://github.com/maroider/xkbcommon-dl", rev = "e175ffe" } [target.'cfg(target_arch = "wasm32")'.dependencies.web_sys] package = "web-sys" diff --git a/src/platform_impl/linux/common/mod.rs b/src/platform_impl/linux/common/mod.rs index 32030aff05..fa23919676 100644 --- a/src/platform_impl/linux/common/mod.rs +++ b/src/platform_impl/linux/common/mod.rs @@ -1 +1,2 @@ pub mod keymap; +pub mod xkb_state; diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs new file mode 100644 index 0000000000..5bb3fd278c --- /dev/null +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -0,0 +1,383 @@ +use std::env; +use std::ffi::CString; +use std::fs::File; +use std::os::raw::c_char; +use std::os::unix::ffi::OsStringExt; +use std::ptr; + +use memmap2::MmapOptions; +use xkbcommon_dl::{ + self as ffi, xkb_state_component, XKBCOMMON_COMPOSE_HANDLE as XKBCH, XKBCOMMON_HANDLE as XKBH, +}; + +pub use sctk::seat::keyboard::RMLVO; + +pub(crate) struct KbState { + xkb_context: *mut ffi::xkb_context, + xkb_keymap: *mut ffi::xkb_keymap, + xkb_state: *mut ffi::xkb_state, + xkb_compose_table: *mut ffi::xkb_compose_table, + xkb_compose_state: *mut ffi::xkb_compose_state, + mods_state: ModifiersState, + locked: bool, +} + +/// Represents the current state of the keyboard modifiers +/// +/// Each field of this struct represents a modifier and is `true` if this modifier is active. +/// +/// For some modifiers, this means that the key is currently pressed, others are toggled +/// (like caps lock). +#[derive(Copy, Clone, Debug, Default)] +pub struct ModifiersState { + /// The "control" key + pub ctrl: bool, + /// The "alt" key + pub alt: bool, + /// The "shift" key + pub shift: bool, + /// The "Caps lock" key + pub caps_lock: bool, + /// The "logo" key + /// + /// Also known as the "windows" key on most keyboards + pub logo: bool, + /// The "Num lock" key + pub num_lock: bool, +} + +impl ModifiersState { + fn new() -> ModifiersState { + ModifiersState::default() + } + + fn update_with(&mut self, state: *mut ffi::xkb_state) { + self.ctrl = unsafe { + (XKBH.xkb_state_mod_name_is_active)( + state, + ffi::XKB_MOD_NAME_CTRL.as_ptr() as *const c_char, + xkb_state_component::XKB_STATE_MODS_EFFECTIVE, + ) > 0 + }; + self.alt = unsafe { + (XKBH.xkb_state_mod_name_is_active)( + state, + ffi::XKB_MOD_NAME_ALT.as_ptr() as *const c_char, + xkb_state_component::XKB_STATE_MODS_EFFECTIVE, + ) > 0 + }; + self.shift = unsafe { + (XKBH.xkb_state_mod_name_is_active)( + state, + ffi::XKB_MOD_NAME_SHIFT.as_ptr() as *const c_char, + xkb_state_component::XKB_STATE_MODS_EFFECTIVE, + ) > 0 + }; + self.caps_lock = unsafe { + (XKBH.xkb_state_mod_name_is_active)( + state, + ffi::XKB_MOD_NAME_CAPS.as_ptr() as *const c_char, + xkb_state_component::XKB_STATE_MODS_EFFECTIVE, + ) > 0 + }; + self.logo = unsafe { + (XKBH.xkb_state_mod_name_is_active)( + state, + ffi::XKB_MOD_NAME_LOGO.as_ptr() as *const c_char, + xkb_state_component::XKB_STATE_MODS_EFFECTIVE, + ) > 0 + }; + self.num_lock = unsafe { + (XKBH.xkb_state_mod_name_is_active)( + state, + ffi::XKB_MOD_NAME_NUM.as_ptr() as *const c_char, + xkb_state_component::XKB_STATE_MODS_EFFECTIVE, + ) > 0 + }; + } +} + +impl KbState { + pub(crate) fn update_modifiers( + &mut self, + mods_depressed: u32, + mods_latched: u32, + mods_locked: u32, + group: u32, + ) { + if !self.ready() { + return; + } + let mask = unsafe { + (XKBH.xkb_state_update_mask)( + self.xkb_state, + mods_depressed, + mods_latched, + mods_locked, + 0, + 0, + group, + ) + }; + if mask.contains(xkb_state_component::XKB_STATE_MODS_EFFECTIVE) { + // effective value of mods have changed, we need to update our state + self.mods_state.update_with(self.xkb_state); + } + } + + pub(crate) fn get_one_sym_raw(&mut self, keycode: u32) -> u32 { + if !self.ready() { + return 0; + } + unsafe { (XKBH.xkb_state_key_get_one_sym)(self.xkb_state, keycode + 8) } + } + + pub(crate) fn get_utf8_raw(&mut self, keycode: u32) -> Option { + if !self.ready() { + return None; + } + let size = unsafe { + (XKBH.xkb_state_key_get_utf8)(self.xkb_state, keycode + 8, ptr::null_mut(), 0) + } + 1; + if size <= 1 { + return None; + }; + let mut buffer = Vec::with_capacity(size as usize); + unsafe { + buffer.set_len(size as usize); + (XKBH.xkb_state_key_get_utf8)( + self.xkb_state, + keycode + 8, + buffer.as_mut_ptr() as *mut _, + size as usize, + ); + }; + // remove the final `\0` + buffer.pop(); + // libxkbcommon will always provide valid UTF8 + Some(unsafe { String::from_utf8_unchecked(buffer) }) + } + + pub(crate) fn compose_feed(&mut self, keysym: u32) -> Option { + if !self.ready() || self.xkb_compose_state.is_null() { + return None; + } + Some(unsafe { (XKBCH.xkb_compose_state_feed)(self.xkb_compose_state, keysym) }) + } + + pub(crate) fn compose_status(&mut self) -> Option { + if !self.ready() || self.xkb_compose_state.is_null() { + return None; + } + Some(unsafe { (XKBCH.xkb_compose_state_get_status)(self.xkb_compose_state) }) + } + + pub(crate) fn compose_get_utf8(&mut self) -> Option { + if !self.ready() || self.xkb_compose_state.is_null() { + return None; + } + let size = unsafe { + (XKBCH.xkb_compose_state_get_utf8)(self.xkb_compose_state, ptr::null_mut(), 0) + } + 1; + if size <= 1 { + return None; + }; + let mut buffer = Vec::with_capacity(size as usize); + unsafe { + buffer.set_len(size as usize); + (XKBCH.xkb_compose_state_get_utf8)( + self.xkb_compose_state, + buffer.as_mut_ptr() as *mut _, + size as usize, + ); + }; + // remove the final `\0` + buffer.pop(); + // libxkbcommon will always provide valid UTF8 + Some(unsafe { String::from_utf8_unchecked(buffer) }) + } + + pub(crate) fn new() -> Result { + { + if ffi::XKBCOMMON_OPTION.as_ref().is_none() { + return Err(Error::XKBNotFound); + } + } + let context = + unsafe { (XKBH.xkb_context_new)(ffi::xkb_context_flags::XKB_CONTEXT_NO_FLAGS) }; + if context.is_null() { + return Err(Error::XKBNotFound); + } + + let mut me = KbState { + xkb_context: context, + xkb_keymap: ptr::null_mut(), + xkb_state: ptr::null_mut(), + xkb_compose_table: ptr::null_mut(), + xkb_compose_state: ptr::null_mut(), + mods_state: ModifiersState::new(), + locked: false, + }; + + unsafe { + me.init_compose(); + } + + Ok(me) + } + + pub(crate) fn from_rmlvo(rmlvo: RMLVO) -> Result { + fn to_cstring(s: Option) -> Result, Error> { + s.map_or(Ok(None), |s| CString::new(s).map(Option::Some)) + .map_err(|_| Error::BadNames) + } + + let mut state = KbState::new()?; + + let rules = to_cstring(rmlvo.rules)?; + let model = to_cstring(rmlvo.model)?; + let layout = to_cstring(rmlvo.layout)?; + let variant = to_cstring(rmlvo.variant)?; + let options = to_cstring(rmlvo.options)?; + + let xkb_names = ffi::xkb_rule_names { + rules: rules.map_or(ptr::null(), |s| s.as_ptr()), + model: model.map_or(ptr::null(), |s| s.as_ptr()), + layout: layout.map_or(ptr::null(), |s| s.as_ptr()), + variant: variant.map_or(ptr::null(), |s| s.as_ptr()), + options: options.map_or(ptr::null(), |s| s.as_ptr()), + }; + + unsafe { + state.init_with_rmlvo(xkb_names)?; + } + + state.locked = true; + Ok(state) + } + + pub(crate) unsafe fn init_compose(&mut self) { + let locale = env::var_os("LC_ALL") + .and_then(|v| if v.is_empty() { None } else { Some(v) }) + .or_else(|| env::var_os("LC_CTYPE")) + .and_then(|v| if v.is_empty() { None } else { Some(v) }) + .or_else(|| env::var_os("LANG")) + .and_then(|v| if v.is_empty() { None } else { Some(v) }) + .unwrap_or_else(|| "C".into()); + let locale = CString::new(locale.into_vec()).unwrap(); + + let compose_table = (XKBCH.xkb_compose_table_new_from_locale)( + self.xkb_context, + locale.as_ptr(), + ffi::xkb_compose_compile_flags::XKB_COMPOSE_COMPILE_NO_FLAGS, + ); + + if compose_table.is_null() { + // init of compose table failed, continue without compose + return; + } + + let compose_state = (XKBCH.xkb_compose_state_new)( + compose_table, + ffi::xkb_compose_state_flags::XKB_COMPOSE_STATE_NO_FLAGS, + ); + + if compose_state.is_null() { + // init of compose state failed, continue without compose + (XKBCH.xkb_compose_table_unref)(compose_table); + return; + } + + self.xkb_compose_table = compose_table; + self.xkb_compose_state = compose_state; + } + + pub(crate) unsafe fn post_init(&mut self, keymap: *mut ffi::xkb_keymap) { + let state = (XKBH.xkb_state_new)(keymap); + self.xkb_keymap = keymap; + self.xkb_state = state; + self.mods_state.update_with(state); + } + + pub(crate) unsafe fn de_init(&mut self) { + (XKBH.xkb_state_unref)(self.xkb_state); + self.xkb_state = ptr::null_mut(); + (XKBH.xkb_keymap_unref)(self.xkb_keymap); + self.xkb_keymap = ptr::null_mut(); + } + + pub(crate) unsafe fn init_with_fd(&mut self, fd: File, size: usize) { + let map = MmapOptions::new().len(size).map(&fd).unwrap(); + + let keymap = (XKBH.xkb_keymap_new_from_string)( + self.xkb_context, + map.as_ptr() as *const _, + ffi::xkb_keymap_format::XKB_KEYMAP_FORMAT_TEXT_V1, + ffi::xkb_keymap_compile_flags::XKB_KEYMAP_COMPILE_NO_FLAGS, + ); + + if keymap.is_null() { + panic!("Received invalid keymap from compositor."); + } + + self.post_init(keymap); + } + + pub(crate) unsafe fn init_with_rmlvo( + &mut self, + names: ffi::xkb_rule_names, + ) -> Result<(), Error> { + let keymap = (XKBH.xkb_keymap_new_from_names)( + self.xkb_context, + &names, + ffi::xkb_keymap_compile_flags::XKB_KEYMAP_COMPILE_NO_FLAGS, + ); + + if keymap.is_null() { + return Err(Error::BadNames); + } + + self.post_init(keymap); + + Ok(()) + } + + pub(crate) unsafe fn key_repeats(&mut self, xkb_keycode_t: ffi::xkb_keycode_t) -> bool { + (XKBH.xkb_keymap_key_repeats)(self.xkb_keymap, xkb_keycode_t) == 1 + } + + #[inline] + pub(crate) fn ready(&self) -> bool { + !self.xkb_state.is_null() + } + + #[inline] + pub(crate) fn locked(&self) -> bool { + self.locked + } + + #[inline] + pub(crate) fn mods_state(&self) -> ModifiersState { + self.mods_state + } +} + +impl Drop for KbState { + fn drop(&mut self) { + unsafe { + (XKBCH.xkb_compose_state_unref)(self.xkb_compose_state); + (XKBCH.xkb_compose_table_unref)(self.xkb_compose_table); + (XKBH.xkb_state_unref)(self.xkb_state); + (XKBH.xkb_keymap_unref)(self.xkb_keymap); + (XKBH.xkb_context_unref)(self.xkb_context); + } + } +} + +#[derive(Debug)] +pub enum Error { + /// libxkbcommon is not available + XKBNotFound, + /// Provided RMLVO specified a keymap that would not be loaded + BadNames, +} diff --git a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs index 268beb6fa3..acb5dc1852 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs @@ -1,12 +1,13 @@ //! Handling of various keyboard events. +use sctk::reexports::calloop; +use sctk::reexports::client; use sctk::reexports::client::protocol::wl_keyboard::KeyState; -use sctk::seat::keyboard::Event as KeyboardEvent; - use crate::event::{ElementState, KeyEvent, WindowEvent}; use crate::keyboard::{Key, ModifiersState, NativeKeyCode}; use crate::platform_impl::platform::common::keymap; +use crate::platform_impl::platform::common::xkb_state::{self, RMLVO}; use crate::platform_impl::wayland::event_loop::WinitState; use crate::platform_impl::wayland::{self, DeviceId}; use crate::platform_impl::KeyEventExtra; @@ -15,13 +16,13 @@ use super::KeyboardInner; #[inline] pub(super) fn handle_keyboard( - event: KeyboardEvent<'_>, + event: Event<'_>, inner: &mut KeyboardInner, winit_state: &mut WinitState, ) { let event_sink = &mut winit_state.event_sink; match event { - KeyboardEvent::Enter { surface, .. } => { + Event::Enter { surface, .. } => { let window_id = wayland::make_wid(&surface); // Window gained focus. @@ -35,7 +36,7 @@ pub(super) fn handle_keyboard( inner.target_window_id = Some(window_id); } - KeyboardEvent::Leave { surface, .. } => { + Event::Leave { surface, .. } => { let window_id = wayland::make_wid(&surface); // Notify that no modifiers are being pressed. @@ -52,7 +53,7 @@ pub(super) fn handle_keyboard( // Reset the id. inner.target_window_id = None; } - KeyboardEvent::Key { + Event::Key { rawkey, keysym, state, @@ -107,7 +108,7 @@ pub(super) fn handle_keyboard( } } } - KeyboardEvent::Repeat { + Event::Repeat { rawkey, keysym, utf8, @@ -148,9 +149,7 @@ pub(super) fn handle_keyboard( for ch in txt.chars() { // event_sink.push_window_event(WindowEvent::ReceivedCharacter(ch), window_id); } - } - } - KeyboardEvent::Modifiers { modifiers } => { + Event::Modifiers { modifiers } => { let modifiers = ModifiersState::from(modifiers); if let Some(window_id) = inner.target_window_id { *inner.modifiers_state.borrow_mut() = modifiers; @@ -165,3 +164,585 @@ pub(super) fn handle_keyboard( } } } + +// ! ====================================================================================================== ! +// ! "INSPIRED" BY SCTK ! +// ! ====================================================================================================== ! + +use std::num::NonZeroU32; +use std::time::Duration; +use std::{ + cell::RefCell, + convert::TryInto, + fs::File, + os::unix::io::{FromRawFd, RawFd}, + rc::Rc, +}; + +use sctk::reexports::client::{ + protocol::{wl_keyboard, wl_seat, wl_surface}, + Attached, +}; +use xkbcommon_dl as ffi; + +use super::super::super::super::common::xkb_state::KbState; + +const MICROS_IN_SECOND: u32 = 1000000; + +/// Possible kinds of key repetition +pub enum RepeatKind { + /// keys will be repeated at a set rate and delay + Fixed { + /// The number of repetitions per second that should occur. + rate: u32, + /// delay (in milliseconds) between a key press and the start of repetition + delay: u32, + }, + /// keys will be repeated at a rate and delay set by the wayland server + System, +} + +#[derive(Debug)] +/// An error that occurred while trying to initialize a mapped keyboard +pub enum Error { + XkbState(xkb_state::Error), + /// The provided seat does not have the keyboard capability + NoKeyboard, + /// Failed to init timers for repetition + TimerError(std::io::Error), +} + +impl From for Error { + fn from(err: xkb_state::Error) -> Self { + Self::XkbState(err) + } +} + +/// Events received from a mapped keyboard +pub enum Event<'a> { + /// The keyboard focus has entered a surface + Enter { + /// serial number of the event + serial: u32, + /// surface that was entered + surface: wl_surface::WlSurface, + /// raw values of the currently pressed keys + rawkeys: &'a [u32], + /// interpreted symbols of the currently pressed keys + keysyms: &'a [u32], + }, + /// The keyboard focus has left a surface + Leave { + /// serial number of the event + serial: u32, + /// surface that was left + surface: wl_surface::WlSurface, + }, + /// The key modifiers have changed state + Modifiers { + /// current state of the modifiers + modifiers: xkb_state::ModifiersState, + }, + /// A key event occurred + Key { + /// serial number of the event + serial: u32, + /// time at which the keypress occurred + time: u32, + /// raw value of the key + rawkey: u32, + /// interpreted symbol of the key + keysym: u32, + /// new state of the key + state: KeyState, + /// utf8 interpretation of the entered text + /// + /// will always be `None` on key release events + utf8: Option, + }, + /// A key repetition event + Repeat { + /// time at which the repetition occured + time: u32, + /// raw value of the key + rawkey: u32, + /// interpreted symbol of the key + keysym: u32, + /// utf8 interpretation of the entered text + utf8: Option, + }, +} + +/// Implement a keyboard for keymap translation with key repetition +/// +/// This requires you to provide a callback to receive the events after they +/// have been interpreted with the keymap. +/// +/// The keymap will be loaded from the provided RMLVO rules, or from the compositor +/// provided keymap if `None`. +/// +/// Returns an error if xkbcommon could not be initialized, the RMLVO specification +/// contained invalid values, or if the provided seat does not have keyboard capability. +pub fn map_keyboard_repeat( + loop_handle: calloop::LoopHandle, + seat: &Attached, + rmlvo: Option, + repeatkind: RepeatKind, + callback: F, +) -> Result<(wl_keyboard::WlKeyboard, calloop::Source), Error> +where + F: FnMut(Event<'_>, wl_keyboard::WlKeyboard, wayland_client::DispatchData<'_>) + 'static, +{ + let has_kbd = sctk::seat::with_seat_data(seat, |data| data.has_keyboard).unwrap_or(false); + let keyboard = if has_kbd { + seat.get_keyboard() + } else { + return Err(Error::NoKeyboard); + }; + + let state = Rc::new(RefCell::new( + rmlvo + .map(KbState::from_rmlvo) + .unwrap_or_else(KbState::new)?, + )); + + let callback = Rc::new(RefCell::new(callback)); + + let repeat = match repeatkind { + RepeatKind::System => RepeatDetails { + locked: false, + gap: None, + delay: 200, + }, + RepeatKind::Fixed { rate, delay } => { + let gap = rate_to_gap(rate as i32); + RepeatDetails { + locked: true, + gap, + delay, + } + } + }; + + // Prepare the repetition handling. + let (mut kbd_handler, source) = { + let current_repeat = Rc::new(RefCell::new(None)); + + let source = RepeatSource { + timer: calloop::timer::Timer::new().map_err(Error::TimerError)?, + state: state.clone(), + current_repeat: current_repeat.clone(), + }; + + let timer_handle = source.timer.handle(); + + let handler = KbdHandler { + callback: callback.clone(), + state, + repeat: Some(KbdRepeat { + timer_handle, + current_repeat, + details: repeat, + }), + }; + (handler, source) + }; + + let source = loop_handle + .insert_source(source, move |event, kbd, ddata| { + (&mut *callback.borrow_mut())( + event, + kbd.clone(), + wayland_client::DispatchData::wrap(ddata), + ) + }) + .map_err(|e| Error::TimerError(e.error))?; + + keyboard.quick_assign(move |keyboard, event, data| { + kbd_handler.event(keyboard.detach(), event, data) + }); + + Ok((keyboard.detach(), source)) +} + +fn rate_to_gap(rate: i32) -> Option { + if rate <= 0 { + None + } else if MICROS_IN_SECOND < rate as u32 { + NonZeroU32::new(1) + } else { + NonZeroU32::new(MICROS_IN_SECOND / rate as u32) + } +} + +/* + * Classic handling + */ + +type KbdCallback = dyn FnMut(Event<'_>, wl_keyboard::WlKeyboard, wayland_client::DispatchData<'_>); + +struct RepeatDetails { + locked: bool, + /// Gap between key presses in microseconds. + /// + /// If the `gap` is `None`, it means that repeat is disabled. + gap: Option, + /// Delay before starting key repeat in milliseconds. + delay: u32, +} + +struct KbdHandler { + state: Rc>, + callback: Rc>, + repeat: Option, +} + +struct KbdRepeat { + timer_handle: calloop::timer::TimerHandle<()>, + current_repeat: Rc>>, + details: RepeatDetails, +} + +impl KbdRepeat { + fn start_repeat(&self, key: u32, keyboard: wl_keyboard::WlKeyboard, time: u32) { + // Start a new repetition, overwriting the previous ones + self.timer_handle.cancel_all_timeouts(); + + // Handle disabled repeat rate. + let gap = match self.details.gap { + Some(gap) => gap.get() as u64, + None => return, + }; + + *self.current_repeat.borrow_mut() = Some(RepeatData { + keyboard, + keycode: key, + gap, + time: (time + self.details.delay) as u64 * 1000, + }); + self.timer_handle + .add_timeout(Duration::from_micros(self.details.delay as u64 * 1000), ()); + } + + fn stop_repeat(&self, key: u32) { + // only cancel if the released key is the currently repeating key + let mut guard = self.current_repeat.borrow_mut(); + let stop = (*guard).as_ref().map(|d| d.keycode == key).unwrap_or(false); + if stop { + self.timer_handle.cancel_all_timeouts(); + *guard = None; + } + } + + fn stop_all_repeat(&self) { + self.timer_handle.cancel_all_timeouts(); + *self.current_repeat.borrow_mut() = None; + } +} + +impl KbdHandler { + fn event( + &mut self, + kbd: wl_keyboard::WlKeyboard, + event: wl_keyboard::Event, + dispatch_data: client::DispatchData<'_>, + ) { + use wl_keyboard::Event; + + match event { + Event::Keymap { format, fd, size } => self.keymap(kbd, format, fd, size), + Event::Enter { + serial, + surface, + keys, + } => self.enter(kbd, serial, surface, keys, dispatch_data), + Event::Leave { serial, surface } => self.leave(kbd, serial, surface, dispatch_data), + Event::Key { + serial, + time, + key, + state, + } => self.key(kbd, serial, time, key, state, dispatch_data), + Event::Modifiers { + mods_depressed, + mods_latched, + mods_locked, + group, + .. + } => self.modifiers( + kbd, + mods_depressed, + mods_latched, + mods_locked, + group, + dispatch_data, + ), + Event::RepeatInfo { rate, delay } => self.repeat_info(kbd, rate, delay), + _ => {} + } + } + + fn keymap( + &mut self, + _: wl_keyboard::WlKeyboard, + format: wl_keyboard::KeymapFormat, + fd: RawFd, + size: u32, + ) { + let fd = unsafe { File::from_raw_fd(fd) }; + let mut state = self.state.borrow_mut(); + if state.locked() { + // state is locked, ignore keymap updates + return; + } + if state.ready() { + // new keymap, we first deinit to free resources + unsafe { + state.de_init(); + } + } + match format { + wl_keyboard::KeymapFormat::XkbV1 => unsafe { + state.init_with_fd(fd, size as usize); + }, + wl_keyboard::KeymapFormat::NoKeymap => { + // TODO: how to handle this (hopefully never occuring) case? + } + _ => unreachable!(), + } + } + + fn enter( + &mut self, + object: wl_keyboard::WlKeyboard, + serial: u32, + surface: wl_surface::WlSurface, + keys: Vec, + dispatch_data: client::DispatchData<'_>, + ) { + let mut state = self.state.borrow_mut(); + let rawkeys = keys + .chunks_exact(4) + .map(|c| u32::from_ne_bytes(c.try_into().unwrap())) + .collect::>(); + let keys: Vec = rawkeys.iter().map(|k| state.get_one_sym_raw(*k)).collect(); + (&mut *self.callback.borrow_mut())( + Event::Enter { + serial, + surface, + rawkeys: &rawkeys, + keysyms: &keys, + }, + object, + dispatch_data, + ); + } + + fn leave( + &mut self, + object: wl_keyboard::WlKeyboard, + serial: u32, + surface: wl_surface::WlSurface, + dispatch_data: client::DispatchData<'_>, + ) { + { + if let Some(ref mut repeat) = self.repeat { + repeat.stop_all_repeat(); + } + } + (&mut *self.callback.borrow_mut())(Event::Leave { serial, surface }, object, dispatch_data); + } + + fn key( + &mut self, + object: wl_keyboard::WlKeyboard, + serial: u32, + time: u32, + key: u32, + key_state: wl_keyboard::KeyState, + dispatch_data: client::DispatchData<'_>, + ) { + let (sym, utf8, repeats) = { + let mut state = self.state.borrow_mut(); + // Get the values to generate a key event + let sym = state.get_one_sym_raw(key); + let utf8 = if key_state == wl_keyboard::KeyState::Pressed { + match state.compose_feed(sym) { + Some(ffi::xkb_compose_feed_result::XKB_COMPOSE_FEED_ACCEPTED) => { + if let Some(status) = state.compose_status() { + match status { + ffi::xkb_compose_status::XKB_COMPOSE_COMPOSED => { + state.compose_get_utf8() + } + ffi::xkb_compose_status::XKB_COMPOSE_NOTHING => { + state.get_utf8_raw(key) + } + _ => None, + } + } else { + state.get_utf8_raw(key) + } + } + Some(_) => { + // XKB_COMPOSE_FEED_IGNORED + None + } + None => { + // XKB COMPOSE is not initialized + state.get_utf8_raw(key) + } + } + } else { + None + }; + let repeats = unsafe { state.key_repeats(key + 8) }; + (sym, utf8, repeats) + }; + + { + if let Some(ref mut repeat_handle) = self.repeat { + if repeats { + if key_state == wl_keyboard::KeyState::Pressed { + repeat_handle.start_repeat(key, object.clone(), time); + } else { + repeat_handle.stop_repeat(key); + } + } + } + } + + (&mut *self.callback.borrow_mut())( + Event::Key { + serial, + time, + rawkey: key, + keysym: sym, + state: key_state, + utf8, + }, + object, + dispatch_data, + ); + } + + fn modifiers( + &mut self, + object: wl_keyboard::WlKeyboard, + mods_depressed: u32, + mods_latched: u32, + mods_locked: u32, + group: u32, + dispatch_data: client::DispatchData<'_>, + ) { + { + let mut state = self.state.borrow_mut(); + state.update_modifiers(mods_depressed, mods_latched, mods_locked, group); + (&mut *self.callback.borrow_mut())( + Event::Modifiers { + modifiers: state.mods_state(), + }, + object, + dispatch_data, + ); + } + } + + fn repeat_info(&mut self, _: wl_keyboard::WlKeyboard, rate: i32, delay: i32) { + { + if let Some(ref mut repeat_handle) = self.repeat { + if !repeat_handle.details.locked { + repeat_handle.details.gap = rate_to_gap(rate); + repeat_handle.details.delay = delay as u32; + } + } + } + } +} + +/* + * Repeat handling + */ + +struct RepeatData { + keyboard: wl_keyboard::WlKeyboard, + keycode: u32, + /// Gap between key presses in microseconds. + gap: u64, + /// Time of the last event in microseconds. + time: u64, +} + +/// An event source managing the key repetition of a keyboard +/// +/// It is given to you from [`map_keyboard`](fn.map_keyboard.html), and you need to +/// insert it in your calloop event loop if you want to have functionning key repetition. +/// +/// If don't want key repetition you can just drop it. +/// +/// This source will not directly generate calloop events, and the callback provided to +/// `EventLoopHandle::insert_source()` will be ignored. Instead it triggers the +/// callback you provided to [`map_keyboard`](fn.map_keyboard.html). +pub struct RepeatSource { + timer: calloop::timer::Timer<()>, + state: Rc>, + current_repeat: Rc>>, +} + +impl calloop::EventSource for RepeatSource { + type Event = Event<'static>; + type Metadata = wl_keyboard::WlKeyboard; + type Ret = (); + + fn process_events( + &mut self, + readiness: calloop::Readiness, + token: calloop::Token, + mut callback: F, + ) -> std::io::Result<()> + where + F: FnMut(Event<'static>, &mut wl_keyboard::WlKeyboard), + { + let current_repeat = &self.current_repeat; + let state = &self.state; + self.timer + .process_events(readiness, token, |(), timer_handle| { + if let Some(ref mut data) = *current_repeat.borrow_mut() { + // there is something to repeat + let mut state = state.borrow_mut(); + let keysym = state.get_one_sym_raw(data.keycode); + let utf8 = state.get_utf8_raw(data.keycode); + let new_time = data.gap + data.time; + // Notify the callback. + callback( + Event::Repeat { + time: (new_time / 1000) as u32, + rawkey: data.keycode, + keysym, + utf8, + }, + &mut data.keyboard, + ); + // Update the time of last event. + data.time = new_time; + // Schedule the next timeout. + timer_handle.add_timeout(Duration::from_micros(data.gap), ()); + } + }) + } + + fn register(&mut self, poll: &mut calloop::Poll, token: calloop::Token) -> std::io::Result<()> { + self.timer.register(poll, token) + } + + fn reregister( + &mut self, + poll: &mut calloop::Poll, + token: calloop::Token, + ) -> std::io::Result<()> { + self.timer.reregister(poll, token) + } + + fn unregister(&mut self, poll: &mut calloop::Poll) -> std::io::Result<()> { + self.timer.unregister(poll) + } +} diff --git a/src/platform_impl/linux/wayland/seat/keyboard/mod.rs b/src/platform_impl/linux/wayland/seat/keyboard/mod.rs index b63fe8bd9c..1a57b441b0 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/mod.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/mod.rs @@ -3,15 +3,13 @@ use std::cell::RefCell; use std::rc::Rc; +use sctk::reexports::calloop::{LoopHandle, Source}; use sctk::reexports::client::protocol::wl_keyboard::WlKeyboard; use sctk::reexports::client::protocol::wl_seat::WlSeat; use sctk::reexports::client::Attached; -use sctk::reexports::calloop::{LoopHandle, RegistrationToken}; - -use sctk::seat::keyboard; - use crate::keyboard::ModifiersState; +use crate::platform_impl::platform::common::xkb_state; use crate::platform_impl::wayland::event_loop::WinitState; use crate::platform_impl::wayland::WindowId; @@ -21,36 +19,36 @@ pub(crate) struct Keyboard { pub keyboard: WlKeyboard, /// The source for repeat keys. - pub repeat_token: Option, + pub repeat_source: Option>, /// LoopHandle to drop `RepeatSource`, when dropping the keyboard. - pub loop_handle: LoopHandle<'static, WinitState>, + pub loop_handle: LoopHandle, } impl Keyboard { pub fn new( seat: &Attached, - loop_handle: LoopHandle<'static, WinitState>, + loop_handle: LoopHandle, modifiers_state: Rc>, ) -> Option { let mut inner = KeyboardInner::new(modifiers_state); - let keyboard_data = keyboard::map_keyboard_repeat( + let keyboard_data = handlers::map_keyboard_repeat( loop_handle.clone(), - seat, + &seat, None, - keyboard::RepeatKind::System, + handlers::RepeatKind::System, move |event, _, mut dispatch_data| { let winit_state = dispatch_data.get::().unwrap(); handlers::handle_keyboard(event, &mut inner, winit_state); }, ); - let (keyboard, repeat_token) = keyboard_data.ok()?; + let (keyboard, repeat_source) = keyboard_data.ok()?; Some(Self { keyboard, loop_handle, - repeat_token: Some(repeat_token), + repeat_source: Some(repeat_source), }) } } @@ -61,8 +59,8 @@ impl Drop for Keyboard { self.keyboard.release(); } - if let Some(repeat_token) = self.repeat_token.take() { - self.loop_handle.remove(repeat_token); + if let Some(repeat_source) = self.repeat_source.take() { + self.loop_handle.remove(repeat_source); } } } @@ -92,8 +90,8 @@ impl KeyboardInner { } } -impl From for ModifiersState { - fn from(mods: keyboard::ModifiersState) -> ModifiersState { +impl From for ModifiersState { + fn from(mods: xkb_state::ModifiersState) -> ModifiersState { let mut wl_mods = ModifiersState::empty(); wl_mods.set(ModifiersState::SHIFT, mods.shift); wl_mods.set(ModifiersState::CONTROL, mods.ctrl); From cddf0f5ecbd9c1a2f7823bfde3ea699fe6cb3644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Mon, 10 Jan 2022 16:44:49 +0100 Subject: [PATCH 10/53] fixup! Hoist keyboard handling code from sctk into Winit --- .../linux/wayland/seat/keyboard/handlers.rs | 20 ++++++++++++------- .../linux/wayland/seat/keyboard/mod.rs | 8 ++++---- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs index acb5dc1852..99101f8cc2 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs @@ -149,6 +149,8 @@ pub(super) fn handle_keyboard( for ch in txt.chars() { // event_sink.push_window_event(WindowEvent::ReceivedCharacter(ch), window_id); } + } + } Event::Modifiers { modifiers } => { let modifiers = ModifiersState::from(modifiers); if let Some(window_id) = inner.target_window_id { @@ -284,12 +286,12 @@ pub enum Event<'a> { /// Returns an error if xkbcommon could not be initialized, the RMLVO specification /// contained invalid values, or if the provided seat does not have keyboard capability. pub fn map_keyboard_repeat( - loop_handle: calloop::LoopHandle, + loop_handle: calloop::LoopHandle<'static, Data>, seat: &Attached, rmlvo: Option, repeatkind: RepeatKind, callback: F, -) -> Result<(wl_keyboard::WlKeyboard, calloop::Source), Error> +) -> Result<(wl_keyboard::WlKeyboard, calloop::RegistrationToken), Error> where F: FnMut(Event<'_>, wl_keyboard::WlKeyboard, wayland_client::DispatchData<'_>) + 'static, { @@ -698,7 +700,7 @@ impl calloop::EventSource for RepeatSource { readiness: calloop::Readiness, token: calloop::Token, mut callback: F, - ) -> std::io::Result<()> + ) -> std::io::Result where F: FnMut(Event<'static>, &mut wl_keyboard::WlKeyboard), { @@ -730,16 +732,20 @@ impl calloop::EventSource for RepeatSource { }) } - fn register(&mut self, poll: &mut calloop::Poll, token: calloop::Token) -> std::io::Result<()> { - self.timer.register(poll, token) + fn register( + &mut self, + poll: &mut calloop::Poll, + token_factory: &mut calloop::TokenFactory, + ) -> std::io::Result<()> { + self.timer.register(poll, token_factory) } fn reregister( &mut self, poll: &mut calloop::Poll, - token: calloop::Token, + token_factory: &mut calloop::TokenFactory, ) -> std::io::Result<()> { - self.timer.reregister(poll, token) + self.timer.reregister(poll, token_factory) } fn unregister(&mut self, poll: &mut calloop::Poll) -> std::io::Result<()> { diff --git a/src/platform_impl/linux/wayland/seat/keyboard/mod.rs b/src/platform_impl/linux/wayland/seat/keyboard/mod.rs index 1a57b441b0..c5d9ef6c0b 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/mod.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/mod.rs @@ -3,7 +3,7 @@ use std::cell::RefCell; use std::rc::Rc; -use sctk::reexports::calloop::{LoopHandle, Source}; +use sctk::reexports::calloop::{LoopHandle, RegistrationToken}; use sctk::reexports::client::protocol::wl_keyboard::WlKeyboard; use sctk::reexports::client::protocol::wl_seat::WlSeat; use sctk::reexports::client::Attached; @@ -19,16 +19,16 @@ pub(crate) struct Keyboard { pub keyboard: WlKeyboard, /// The source for repeat keys. - pub repeat_source: Option>, + pub repeat_source: Option, /// LoopHandle to drop `RepeatSource`, when dropping the keyboard. - pub loop_handle: LoopHandle, + pub loop_handle: LoopHandle<'static, WinitState>, } impl Keyboard { pub fn new( seat: &Attached, - loop_handle: LoopHandle, + loop_handle: LoopHandle<'static, WinitState>, modifiers_state: Rc>, ) -> Option { let mut inner = KeyboardInner::new(modifiers_state); From e49feae1b504ece44f97b4265f841e01ca849a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 1 Apr 2021 05:40:02 +0200 Subject: [PATCH 11/53] Wire up the new events properly --- Cargo.toml | 2 +- src/platform/unix.rs | 2 +- src/platform_impl/linux/common/keymap.rs | 13 +- src/platform_impl/linux/common/xkb_state.rs | 144 +++++++++++++ src/platform_impl/linux/mod.rs | 2 +- .../linux/wayland/seat/keyboard/handlers.rs | 199 ++++++++---------- 6 files changed, 246 insertions(+), 116 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 140ffcb2b2..5bb6373e5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,7 +97,7 @@ percent-encoding = { version = "2.0", optional = true } parking_lot = { version = "0.11.0", optional = true } libc = "0.2.64" memmap2 = { version = "0.2.1", optional = true } -xkbcommon-dl = { git = "https://github.com/maroider/xkbcommon-dl", rev = "e175ffe" } +xkbcommon-dl = { git = "https://github.com/maroider/xkbcommon-dl", rev = "f335e626c" } [target.'cfg(target_arch = "wasm32")'.dependencies.web_sys] package = "web-sys" diff --git a/src/platform/unix.rs b/src/platform/unix.rs index f1cb903906..ae3b9659b4 100644 --- a/src/platform/unix.rs +++ b/src/platform/unix.rs @@ -469,7 +469,7 @@ impl MonitorHandleExtUnix for MonitorHandle { impl KeyEventExtModifierSupplement for KeyEvent { #[inline] fn text_with_all_modifiers(&self) -> Option<&str> { - self.platform_specific.text_with_all_modifers + self.platform_specific.text_with_all_modifiers } #[inline] diff --git a/src/platform_impl/linux/common/keymap.rs b/src/platform_impl/linux/common/keymap.rs index 3016851dd0..86bd90b840 100644 --- a/src/platform_impl/linux/common/keymap.rs +++ b/src/platform_impl/linux/common/keymap.rs @@ -421,15 +421,13 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { keysyms::XKB_KEY_Control_R => Key::Control, keysyms::XKB_KEY_Caps_Lock => Key::CapsLock, // keysyms::XKB_KEY_Shift_Lock => Key::ShiftLock, - - // NOTE: The key xkb calls "Meta" is called "Super" by Winit, and vice versa. - // This is a tad confusing, but these keys have different names depending on who you ask. - keysyms::XKB_KEY_Meta_L => Key::Super, - keysyms::XKB_KEY_Meta_R => Key::Super, + // + keysyms::XKB_KEY_Meta_L => Key::Meta, + keysyms::XKB_KEY_Meta_R => Key::Meta, keysyms::XKB_KEY_Alt_L => Key::Alt, keysyms::XKB_KEY_Alt_R => Key::Alt, - keysyms::XKB_KEY_Super_L => Key::Meta, - keysyms::XKB_KEY_Super_R => Key::Meta, + keysyms::XKB_KEY_Super_L => Key::Super, + keysyms::XKB_KEY_Super_R => Key::Super, keysyms::XKB_KEY_Hyper_L => Key::Hyper, keysyms::XKB_KEY_Hyper_R => Key::Hyper, @@ -681,6 +679,7 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { keysyms::XKB_KEY_SunVideoRaiseBrightness => Key::BrightnessUp, // XKB_KEY_SunPowerSwitchShift // + 0 => Key::Unidentified(NativeKeyCode::Unidentified), _ => Key::Unidentified(NativeKeyCode::XKB(keysym)), } } diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index 5bb3fd278c..1fa6f34a58 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -1,3 +1,5 @@ +use std::cell::RefCell; +use std::convert::TryInto; use std::env; use std::ffi::CString; use std::fs::File; @@ -12,6 +14,11 @@ use xkbcommon_dl::{ pub use sctk::seat::keyboard::RMLVO; +use crate::{ + event::ElementState, + keyboard::{Key, KeyCode, KeyLocation}, +}; + pub(crate) struct KbState { xkb_context: *mut ffi::xkb_context, xkb_keymap: *mut ffi::xkb_keymap, @@ -381,3 +388,140 @@ pub enum Error { /// Provided RMLVO specified a keymap that would not be loaded BadNames, } + +impl KbState { + pub fn process_key_event(&mut self, keycode: u32, state: ElementState) -> KeyEventResults<'_> { + KeyEventResults::new(self, keycode, state == ElementState::Pressed) + } + + pub fn process_key_repeat_event(&mut self, keycode: u32) -> KeyEventResults<'_> { + KeyEventResults::new(self, keycode, false) + } +} + +enum XkbCompose { + Accepted(ffi::xkb_compose_status), + Ignored, + Uninitialized, +} + +pub(crate) struct KeyEventResults<'a> { + state: RefCell<&'a mut KbState>, + keycode: u32, + keysym: u32, + compose: Option, +} + +impl<'a> KeyEventResults<'a> { + fn new(state: &'a mut KbState, keycode: u32, compose: bool) -> Self { + let keysym = state.get_one_sym_raw(keycode); + + let compose = if compose { + Some(match state.compose_feed(keysym) { + Some(ffi::xkb_compose_feed_result::XKB_COMPOSE_FEED_ACCEPTED) => { + // Unwrapping is safe here, as `compose_feed` returns `None` when composition is uninitialized. + XkbCompose::Accepted(state.compose_status().unwrap()) + } + Some(ffi::xkb_compose_feed_result::XKB_COMPOSE_FEED_IGNORED) => XkbCompose::Ignored, + None => XkbCompose::Uninitialized, + }) + } else { + None + }; + + KeyEventResults { + state: RefCell::new(state), + keycode, + keysym, + compose, + } + } + + pub fn keycode(&mut self) -> KeyCode { + super::keymap::rawkey_to_keycode(self.keycode) + } + + pub fn key(&mut self) -> (Key<'static>, KeyLocation) { + let location = super::keymap::keysym_location(self.keysym); + let mut key = super::keymap::keysym_to_key(self.keysym); + if matches!(key, Key::Unidentified(_)) { + if let Some(string) = self.state.borrow_mut().get_utf8_raw(self.keycode) { + key = Key::Character(cached_string(string)); + } + } + (key, location) + } + + pub fn key_without_modifiers(&mut self) -> (Key<'static>, KeyLocation) { + // This will become a pointer to an array which libxkbcommon owns, so we don't need to deallocate it. + let mut keysyms = ptr::null(); + let keysym_count = unsafe { + (XKBH.xkb_keymap_key_get_syms_by_level)( + self.state.borrow_mut().xkb_keymap, + self.keycode, + 0, + 0, + &mut keysyms, + ) + }; + let keysym = if keysym_count == 1 { + unsafe { *keysyms } + } else { + 0 + }; + let key = super::keymap::keysym_to_key(keysym); + let location = super::keymap::keysym_location(keysym); + (key, location) + } + + pub fn text(&mut self) -> Option<&'static str> { + let keysym = self.keysym; + self._text(|| keysym_to_utf8_raw(keysym)) + } + + pub fn text_with_all_modifiers(&mut self) -> Option<&'static str> { + // TODO: Should Ctrl override any attempts to compose text? + // gnome-terminal agrees, but konsole disagrees. + // Should it be configurable instead? + let keycode = self.keycode; + self._text(|| self.state.borrow_mut().get_utf8_raw(keycode)) + } + + fn _text(&self, fallback: F) -> Option<&'static str> + where + F: FnOnce() -> Option, + { + if let Some(compose) = &self.compose { + match compose { + XkbCompose::Accepted(status) => match status { + ffi::xkb_compose_status::XKB_COMPOSE_COMPOSED => { + self.state.borrow_mut().compose_get_utf8() + } + ffi::xkb_compose_status::XKB_COMPOSE_NOTHING => fallback(), + _ => None, + }, + XkbCompose::Ignored | XkbCompose::Uninitialized => fallback(), + } + } else { + fallback() + } + .map(cached_string) + } +} + +fn keysym_to_utf8_raw(keysym: u32) -> Option { + let size = unsafe { (XKBH.xkb_keysym_to_utf8)(keysym, ptr::null_mut(), 0) } + 1; + if size <= 1 { + return None; + } + let mut buffer: Vec = Vec::with_capacity(size.try_into().unwrap()); + unsafe { (XKBH.xkb_keysym_to_utf8)(keysym, buffer.as_mut_ptr().cast(), buffer.len()) }; + // remove the final `\0` + buffer.pop(); + // libxkbcommon will always provide valid UTF8 + Some(unsafe { String::from_utf8_unchecked(buffer) }) +} + +fn cached_string>(string: S) -> &'static str { + Box::leak(string.into().into_boxed_str()) +} diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 3e8997a4cc..73892f19a9 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -46,8 +46,8 @@ mod common; #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct KeyEventExtra { - pub text_with_all_modifers: Option<&'static str>, pub key_without_modifiers: Key<'static>, + pub text_with_all_modifiers: Option<&'static str>, } /// Environment variable specifying which backend should be used on unix platform. diff --git a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs index 99101f8cc2..23e658a305 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs @@ -2,15 +2,16 @@ use sctk::reexports::calloop; use sctk::reexports::client; -use sctk::reexports::client::protocol::wl_keyboard::KeyState; -use crate::event::{ElementState, KeyEvent, WindowEvent}; -use crate::keyboard::{Key, ModifiersState, NativeKeyCode}; -use crate::platform_impl::platform::common::keymap; +use crate::keyboard::{Key, KeyLocation, ModifiersState}; use crate::platform_impl::platform::common::xkb_state::{self, RMLVO}; use crate::platform_impl::wayland::event_loop::WinitState; use crate::platform_impl::wayland::{self, DeviceId}; use crate::platform_impl::KeyEventExtra; +use crate::{ + event::{ElementState, KeyEvent, WindowEvent}, + keyboard::KeyCode, +}; use super::KeyboardInner; @@ -54,10 +55,13 @@ pub(super) fn handle_keyboard( inner.target_window_id = None; } Event::Key { - rawkey, - keysym, + physical_key, + logical_key, + text, + location, state, - utf8, + key_without_modifiers, + text_with_all_modifiers, .. } => { let window_id = match inner.target_window_id { @@ -65,16 +69,6 @@ pub(super) fn handle_keyboard( None => return, }; - let state = match state { - KeyState::Pressed => ElementState::Pressed, - KeyState::Released => ElementState::Released, - _ => unreachable!(), - }; - - let physical_key = keymap::rawkey_to_keycode(rawkey); - let logical_key = keymap::keysym_to_key(keysym); - let location = keymap::keysym_location(keysym); - event_sink.push_window_event( WindowEvent::KeyboardInput { device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland( @@ -83,35 +77,27 @@ pub(super) fn handle_keyboard( event: KeyEvent { physical_key, logical_key, - text: None, + text, location, state, repeat: false, platform_specific: KeyEventExtra { - key_without_modifiers: Key::Unidentified(NativeKeyCode::Unidentified), - text_with_all_modifers: None, + key_without_modifiers, + text_with_all_modifiers, }, }, is_synthetic: false, }, window_id, ); - - // Send ReceivedCharacter event only on ElementState::Pressed. - if ElementState::Released == state { - return; - } - - if let Some(txt) = utf8 { - for ch in txt.chars() { - // event_sink.push_window_event(WindowEvent::ReceivedCharacter(ch), window_id); - } - } } Event::Repeat { - rawkey, - keysym, - utf8, + physical_key, + logical_key, + text, + location, + key_without_modifiers, + text_with_all_modifiers, .. } => { let window_id = match inner.target_window_id { @@ -119,10 +105,6 @@ pub(super) fn handle_keyboard( None => return, }; - let physical_key = keymap::rawkey_to_keycode(rawkey); - let logical_key = keymap::keysym_to_key(keysym); - let location = keymap::keysym_location(keysym); - event_sink.push_window_event( WindowEvent::KeyboardInput { device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland( @@ -131,25 +113,19 @@ pub(super) fn handle_keyboard( event: KeyEvent { physical_key, logical_key, - text: None, + text, location, state: ElementState::Pressed, repeat: true, platform_specific: KeyEventExtra { - key_without_modifiers: Key::Unidentified(NativeKeyCode::Unidentified), - text_with_all_modifers: None, + key_without_modifiers, + text_with_all_modifiers, }, }, is_synthetic: false, }, window_id, ); - - if let Some(txt) = utf8 { - for ch in txt.chars() { - // event_sink.push_window_event(WindowEvent::ReceivedCharacter(ch), window_id); - } - } } Event::Modifiers { modifiers } => { let modifiers = ModifiersState::from(modifiers); @@ -185,7 +161,6 @@ use sctk::reexports::client::{ protocol::{wl_keyboard, wl_seat, wl_surface}, Attached, }; -use xkbcommon_dl as ffi; use super::super::super::super::common::xkb_state::KbState; @@ -194,6 +169,7 @@ const MICROS_IN_SECOND: u32 = 1000000; /// Possible kinds of key repetition pub enum RepeatKind { /// keys will be repeated at a set rate and delay + #[allow(dead_code)] Fixed { /// The number of repetitions per second that should occur. rate: u32, @@ -251,27 +227,24 @@ pub enum Event<'a> { serial: u32, /// time at which the keypress occurred time: u32, - /// raw value of the key - rawkey: u32, - /// interpreted symbol of the key - keysym: u32, - /// new state of the key - state: KeyState, - /// utf8 interpretation of the entered text - /// - /// will always be `None` on key release events - utf8: Option, + physical_key: KeyCode, + logical_key: Key<'static>, + text: Option<&'static str>, + location: KeyLocation, + state: ElementState, + key_without_modifiers: Key<'static>, + text_with_all_modifiers: Option<&'static str>, }, /// A key repetition event Repeat { /// time at which the repetition occured time: u32, - /// raw value of the key - rawkey: u32, - /// interpreted symbol of the key - keysym: u32, - /// utf8 interpretation of the entered text - utf8: Option, + physical_key: KeyCode, + logical_key: Key<'static>, + text: Option<&'static str>, + location: KeyLocation, + key_without_modifiers: Key<'static>, + text_with_all_modifiers: Option<&'static str>, }, } @@ -564,47 +537,49 @@ impl KbdHandler { key_state: wl_keyboard::KeyState, dispatch_data: client::DispatchData<'_>, ) { - let (sym, utf8, repeats) = { + let ( + physical_key, + logical_key, + text, + location, + state, + key_without_modifiers, + text_with_all_modifiers, + repeats, + ) = { let mut state = self.state.borrow_mut(); - // Get the values to generate a key event - let sym = state.get_one_sym_raw(key); - let utf8 = if key_state == wl_keyboard::KeyState::Pressed { - match state.compose_feed(sym) { - Some(ffi::xkb_compose_feed_result::XKB_COMPOSE_FEED_ACCEPTED) => { - if let Some(status) = state.compose_status() { - match status { - ffi::xkb_compose_status::XKB_COMPOSE_COMPOSED => { - state.compose_get_utf8() - } - ffi::xkb_compose_status::XKB_COMPOSE_NOTHING => { - state.get_utf8_raw(key) - } - _ => None, - } - } else { - state.get_utf8_raw(key) - } - } - Some(_) => { - // XKB_COMPOSE_FEED_IGNORED - None - } - None => { - // XKB COMPOSE is not initialized - state.get_utf8_raw(key) - } - } - } else { - None + let key_state = match key_state { + wl_keyboard::KeyState::Pressed => ElementState::Pressed, + wl_keyboard::KeyState::Released => ElementState::Released, + _ => unreachable!(), }; + + let mut ker = state.process_key_event(key, key_state); + + let physical_key = ker.keycode(); + let (logical_key, location) = ker.key(); + let text = ker.text(); + let (key_without_modifiers, _) = ker.key_without_modifiers(); + let text_with_all_modifiers = ker.text_with_all_modifiers(); + let repeats = unsafe { state.key_repeats(key + 8) }; - (sym, utf8, repeats) + + ( + physical_key, + logical_key, + text, + location, + key_state, + key_without_modifiers, + text_with_all_modifiers, + repeats, + ) }; { if let Some(ref mut repeat_handle) = self.repeat { if repeats { - if key_state == wl_keyboard::KeyState::Pressed { + if state == ElementState::Pressed { repeat_handle.start_repeat(key, object.clone(), time); } else { repeat_handle.stop_repeat(key); @@ -617,10 +592,13 @@ impl KbdHandler { Event::Key { serial, time, - rawkey: key, - keysym: sym, - state: key_state, - utf8, + physical_key, + logical_key, + text, + location, + state, + key_without_modifiers, + text_with_all_modifiers, }, object, dispatch_data, @@ -711,16 +689,25 @@ impl calloop::EventSource for RepeatSource { if let Some(ref mut data) = *current_repeat.borrow_mut() { // there is something to repeat let mut state = state.borrow_mut(); - let keysym = state.get_one_sym_raw(data.keycode); - let utf8 = state.get_utf8_raw(data.keycode); + let mut ker = state.process_key_repeat_event(data.keycode); + + let physical_key = ker.keycode(); + let (logical_key, location) = ker.key(); + let text = ker.text(); + let (key_without_modifiers, _) = ker.key_without_modifiers(); + let text_with_all_modifiers = ker.text_with_all_modifiers(); + let new_time = data.gap + data.time; // Notify the callback. callback( Event::Repeat { time: (new_time / 1000) as u32, - rawkey: data.keycode, - keysym, - utf8, + physical_key, + logical_key, + text, + location, + key_without_modifiers, + text_with_all_modifiers, }, &mut data.keyboard, ); From a60af09464497803d33168ba5311e8014441a5f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 1 Apr 2021 06:03:36 +0200 Subject: [PATCH 12/53] Fix creation of key value strings Use `xkb_keysym_to_utf8` rather than `xkb_state_key_get_utf8` to create key value strings, as the latter performs keysym transformations, while the former doesn't. --- src/platform_impl/linux/common/xkb_state.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index 1fa6f34a58..2983a503cf 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -445,7 +445,7 @@ impl<'a> KeyEventResults<'a> { let location = super::keymap::keysym_location(self.keysym); let mut key = super::keymap::keysym_to_key(self.keysym); if matches!(key, Key::Unidentified(_)) { - if let Some(string) = self.state.borrow_mut().get_utf8_raw(self.keycode) { + if let Some(string) = keysym_to_utf8_raw(self.keysym) { key = Key::Character(cached_string(string)); } } @@ -510,12 +510,21 @@ impl<'a> KeyEventResults<'a> { } fn keysym_to_utf8_raw(keysym: u32) -> Option { - let size = unsafe { (XKBH.xkb_keysym_to_utf8)(keysym, ptr::null_mut(), 0) } + 1; - if size <= 1 { - return None; + let mut buffer: Vec = Vec::with_capacity(8); + loop { + let bytes_written = unsafe { + (XKBH.xkb_keysym_to_utf8)(keysym, buffer.as_mut_ptr().cast(), buffer.capacity()) + }; + if bytes_written == 0 { + return None; + } else if bytes_written == -1 { + buffer.reserve(8); + } else { + unsafe { buffer.set_len(bytes_written.try_into().unwrap()) }; + break; + } } - let mut buffer: Vec = Vec::with_capacity(size.try_into().unwrap()); - unsafe { (XKBH.xkb_keysym_to_utf8)(keysym, buffer.as_mut_ptr().cast(), buffer.len()) }; + // remove the final `\0` buffer.pop(); // libxkbcommon will always provide valid UTF8 From 142e435a8d3c7571b2b853783681949c1c9aad9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 1 Apr 2021 07:37:32 +0200 Subject: [PATCH 13/53] Add missing keysym mapping I accidentally skipped over `XKB_KEY_Page_Down` while initially mapping keysyms. --- src/platform_impl/linux/common/keymap.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platform_impl/linux/common/keymap.rs b/src/platform_impl/linux/common/keymap.rs index 86bd90b840..dbd0431679 100644 --- a/src/platform_impl/linux/common/keymap.rs +++ b/src/platform_impl/linux/common/keymap.rs @@ -318,6 +318,7 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { // keysyms::XKB_KEY_Prior => Key::PageUp, keysyms::XKB_KEY_Page_Up => Key::PageUp, // keysyms::XKB_KEY_Next => Key::PageDown, + keysyms::XKB_KEY_Page_Down => Key::PageDown, keysyms::XKB_KEY_End => Key::End, // keysyms::XKB_KEY_Begin => Key::Begin, From a9b5b362ec57da30b97af7cec76cea8f79d374d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 1 Apr 2021 08:18:20 +0200 Subject: [PATCH 14/53] Fix `key_without_modifiers` I forgot about the offset between evdev keycodes and xkb keycodes. --- src/platform_impl/linux/common/xkb_state.rs | 22 +++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index 2983a503cf..cc200c3a5d 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -442,14 +442,7 @@ impl<'a> KeyEventResults<'a> { } pub fn key(&mut self) -> (Key<'static>, KeyLocation) { - let location = super::keymap::keysym_location(self.keysym); - let mut key = super::keymap::keysym_to_key(self.keysym); - if matches!(key, Key::Unidentified(_)) { - if let Some(string) = keysym_to_utf8_raw(self.keysym) { - key = Key::Character(cached_string(string)); - } - } - (key, location) + Self::keysym_to_key(self.keysym) } pub fn key_without_modifiers(&mut self) -> (Key<'static>, KeyLocation) { @@ -458,7 +451,7 @@ impl<'a> KeyEventResults<'a> { let keysym_count = unsafe { (XKBH.xkb_keymap_key_get_syms_by_level)( self.state.borrow_mut().xkb_keymap, - self.keycode, + self.keycode + 8, 0, 0, &mut keysyms, @@ -469,8 +462,17 @@ impl<'a> KeyEventResults<'a> { } else { 0 }; - let key = super::keymap::keysym_to_key(keysym); + Self::keysym_to_key(keysym) + } + + fn keysym_to_key(keysym: u32) -> (Key<'static>, KeyLocation) { let location = super::keymap::keysym_location(keysym); + let mut key = super::keymap::keysym_to_key(keysym); + if matches!(key, Key::Unidentified(_)) { + if let Some(string) = keysym_to_utf8_raw(keysym) { + key = Key::Character(cached_string(string)); + } + } (key, location) } From e0367a9f3ebf38eab926402e205b86f8b4f9689c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 1 Apr 2021 08:42:24 +0200 Subject: [PATCH 15/53] Feature-gate things which depend on memmap2 --- src/platform_impl/linux/common/xkb_state.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index cc200c3a5d..147a009e31 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -7,6 +7,7 @@ use std::os::raw::c_char; use std::os::unix::ffi::OsStringExt; use std::ptr; +#[cfg(feature = "wayland")] use memmap2::MmapOptions; use xkbcommon_dl::{ self as ffi, xkb_state_component, XKBCOMMON_COMPOSE_HANDLE as XKBCH, XKBCOMMON_HANDLE as XKBH, @@ -313,6 +314,7 @@ impl KbState { self.xkb_keymap = ptr::null_mut(); } + #[cfg(feature = "wayland")] pub(crate) unsafe fn init_with_fd(&mut self, fd: File, size: usize) { let map = MmapOptions::new().len(size).map(&fd).unwrap(); From 16dd04417bd6af357f147964add309f57e01bbc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 1 Apr 2021 08:47:01 +0200 Subject: [PATCH 16/53] Be more consistent with what `keycode` means --- src/platform_impl/linux/common/xkb_state.rs | 4 ++-- src/platform_impl/linux/wayland/seat/keyboard/handlers.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index 147a009e31..fa1e3e4fda 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -351,8 +351,8 @@ impl KbState { Ok(()) } - pub(crate) unsafe fn key_repeats(&mut self, xkb_keycode_t: ffi::xkb_keycode_t) -> bool { - (XKBH.xkb_keymap_key_repeats)(self.xkb_keymap, xkb_keycode_t) == 1 + pub(crate) unsafe fn key_repeats(&mut self, keycode: ffi::xkb_keycode_t) -> bool { + (XKBH.xkb_keymap_key_repeats)(self.xkb_keymap, keycode + 8) == 1 } #[inline] diff --git a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs index 23e658a305..15bc1869d4 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs @@ -562,7 +562,7 @@ impl KbdHandler { let (key_without_modifiers, _) = ker.key_without_modifiers(); let text_with_all_modifiers = ker.text_with_all_modifiers(); - let repeats = unsafe { state.key_repeats(key + 8) }; + let repeats = unsafe { state.key_repeats(key) }; ( physical_key, From db30340c3111fe5c9c7008a71724c45c72173339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 1 Apr 2021 08:48:51 +0200 Subject: [PATCH 17/53] Wire up Wayland IME again --- src/platform_impl/linux/wayland/seat/text_input/handlers.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/platform_impl/linux/wayland/seat/text_input/handlers.rs b/src/platform_impl/linux/wayland/seat/text_input/handlers.rs index 26d56a3cb6..b57b5f58a3 100644 --- a/src/platform_impl/linux/wayland/seat/text_input/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/text_input/handlers.rs @@ -69,9 +69,7 @@ pub(super) fn handle_text_input( _ => return, }; - for ch in text.chars() { - // event_sink.push_window_event(WindowEvent::ReceivedCharacter(ch), window_id); - } + event_sink.push_window_event(WindowEvent::ReceivedImeText(text), window_id); } _ => (), } From afbb0776107a642aec11d38c870b25bfb1c4d95e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 1 Apr 2021 10:12:12 +0200 Subject: [PATCH 18/53] Improve key string handling --- src/platform_impl/linux/common/xkb_state.rs | 141 ++++++++++++-------- 1 file changed, 83 insertions(+), 58 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index fa1e3e4fda..ab957920f9 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -1,4 +1,3 @@ -use std::cell::RefCell; use std::convert::TryInto; use std::env; use std::ffi::CString; @@ -28,6 +27,7 @@ pub(crate) struct KbState { xkb_compose_state: *mut ffi::xkb_compose_state, mods_state: ModifiersState, locked: bool, + scratch_buffer: Vec, } /// Represents the current state of the keyboard modifiers @@ -140,7 +140,7 @@ impl KbState { unsafe { (XKBH.xkb_state_key_get_one_sym)(self.xkb_state, keycode + 8) } } - pub(crate) fn get_utf8_raw(&mut self, keycode: u32) -> Option { + pub(crate) fn get_utf8_raw(&mut self, keycode: u32) -> Option<&'static str> { if !self.ready() { return None; } @@ -150,20 +150,21 @@ impl KbState { if size <= 1 { return None; }; - let mut buffer = Vec::with_capacity(size as usize); + self.scratch_buffer.clear(); + let size = size.try_into().unwrap(); + self.scratch_buffer.reserve(size); unsafe { - buffer.set_len(size as usize); + self.scratch_buffer.set_len(size); (XKBH.xkb_state_key_get_utf8)( self.xkb_state, keycode + 8, - buffer.as_mut_ptr() as *mut _, - size as usize, + self.scratch_buffer.as_mut_ptr() as *mut _, + size, ); }; // remove the final `\0` - buffer.pop(); - // libxkbcommon will always provide valid UTF8 - Some(unsafe { String::from_utf8_unchecked(buffer) }) + self.scratch_buffer.pop(); + Some(byte_slice_to_cached_string(&self.scratch_buffer)) } pub(crate) fn compose_feed(&mut self, keysym: u32) -> Option { @@ -180,7 +181,7 @@ impl KbState { Some(unsafe { (XKBCH.xkb_compose_state_get_status)(self.xkb_compose_state) }) } - pub(crate) fn compose_get_utf8(&mut self) -> Option { + pub(crate) fn compose_get_utf8(&mut self) -> Option<&'static str> { if !self.ready() || self.xkb_compose_state.is_null() { return None; } @@ -190,19 +191,20 @@ impl KbState { if size <= 1 { return None; }; - let mut buffer = Vec::with_capacity(size as usize); + self.scratch_buffer.clear(); + let size = size.try_into().unwrap(); + self.scratch_buffer.reserve(size); unsafe { - buffer.set_len(size as usize); + self.scratch_buffer.set_len(size); (XKBCH.xkb_compose_state_get_utf8)( self.xkb_compose_state, - buffer.as_mut_ptr() as *mut _, + self.scratch_buffer.as_mut_ptr() as *mut _, size as usize, ); }; // remove the final `\0` - buffer.pop(); - // libxkbcommon will always provide valid UTF8 - Some(unsafe { String::from_utf8_unchecked(buffer) }) + self.scratch_buffer.pop(); + Some(byte_slice_to_cached_string(&self.scratch_buffer)) } pub(crate) fn new() -> Result { @@ -225,6 +227,7 @@ impl KbState { xkb_compose_state: ptr::null_mut(), mods_state: ModifiersState::new(), locked: false, + scratch_buffer: Vec::new(), }; unsafe { @@ -399,6 +402,36 @@ impl KbState { pub fn process_key_repeat_event(&mut self, keycode: u32) -> KeyEventResults<'_> { KeyEventResults::new(self, keycode, false) } + + fn keysym_to_utf8_raw(&mut self, keysym: u32) -> Option<&'static str> { + self.scratch_buffer.clear(); + self.scratch_buffer.reserve(8); + loop { + unsafe { self.scratch_buffer.set_len(8) }; + let bytes_written = unsafe { + (XKBH.xkb_keysym_to_utf8)( + keysym, + self.scratch_buffer.as_mut_ptr().cast(), + self.scratch_buffer.capacity(), + ) + }; + if bytes_written == 0 { + return None; + } else if bytes_written == -1 { + self.scratch_buffer.reserve(8); + } else { + unsafe { + self.scratch_buffer + .set_len(bytes_written.try_into().unwrap()) + }; + break; + } + } + + // remove the final `\0` + self.scratch_buffer.pop(); + Some(byte_slice_to_cached_string(&self.scratch_buffer)) + } } enum XkbCompose { @@ -408,7 +441,7 @@ enum XkbCompose { } pub(crate) struct KeyEventResults<'a> { - state: RefCell<&'a mut KbState>, + state: &'a mut KbState, keycode: u32, keysym: u32, compose: Option, @@ -432,7 +465,7 @@ impl<'a> KeyEventResults<'a> { }; KeyEventResults { - state: RefCell::new(state), + state, keycode, keysym, compose, @@ -444,7 +477,7 @@ impl<'a> KeyEventResults<'a> { } pub fn key(&mut self) -> (Key<'static>, KeyLocation) { - Self::keysym_to_key(self.keysym) + self.keysym_to_key(self.keysym) } pub fn key_without_modifiers(&mut self) -> (Key<'static>, KeyLocation) { @@ -452,7 +485,7 @@ impl<'a> KeyEventResults<'a> { let mut keysyms = ptr::null(); let keysym_count = unsafe { (XKBH.xkb_keymap_key_get_syms_by_level)( - self.state.borrow_mut().xkb_keymap, + self.state.xkb_keymap, self.keycode + 8, 0, 0, @@ -464,77 +497,69 @@ impl<'a> KeyEventResults<'a> { } else { 0 }; - Self::keysym_to_key(keysym) + self.keysym_to_key(keysym) } - fn keysym_to_key(keysym: u32) -> (Key<'static>, KeyLocation) { + fn keysym_to_key(&mut self, keysym: u32) -> (Key<'static>, KeyLocation) { let location = super::keymap::keysym_location(keysym); let mut key = super::keymap::keysym_to_key(keysym); if matches!(key, Key::Unidentified(_)) { - if let Some(string) = keysym_to_utf8_raw(keysym) { - key = Key::Character(cached_string(string)); + if let Some(string) = self.state.keysym_to_utf8_raw(keysym) { + key = Key::Character(string); } } (key, location) } pub fn text(&mut self) -> Option<&'static str> { - let keysym = self.keysym; - self._text(|| keysym_to_utf8_raw(keysym)) + self._text(|this| this.state.keysym_to_utf8_raw(this.keysym)) } pub fn text_with_all_modifiers(&mut self) -> Option<&'static str> { // TODO: Should Ctrl override any attempts to compose text? // gnome-terminal agrees, but konsole disagrees. // Should it be configurable instead? - let keycode = self.keycode; - self._text(|| self.state.borrow_mut().get_utf8_raw(keycode)) + self._text(|this| this.state.get_utf8_raw(this.keycode)) } - fn _text(&self, fallback: F) -> Option<&'static str> + fn _text(&mut self, fallback: F) -> Option<&'static str> where - F: FnOnce() -> Option, + F: FnOnce(&mut Self) -> Option<&'static str>, { if let Some(compose) = &self.compose { match compose { XkbCompose::Accepted(status) => match status { - ffi::xkb_compose_status::XKB_COMPOSE_COMPOSED => { - self.state.borrow_mut().compose_get_utf8() - } - ffi::xkb_compose_status::XKB_COMPOSE_NOTHING => fallback(), + ffi::xkb_compose_status::XKB_COMPOSE_COMPOSED => self.state.compose_get_utf8(), + ffi::xkb_compose_status::XKB_COMPOSE_NOTHING => fallback(self), _ => None, }, - XkbCompose::Ignored | XkbCompose::Uninitialized => fallback(), + XkbCompose::Ignored | XkbCompose::Uninitialized => fallback(self), } } else { - fallback() + fallback(self) } - .map(cached_string) } } -fn keysym_to_utf8_raw(keysym: u32) -> Option { - let mut buffer: Vec = Vec::with_capacity(8); - loop { - let bytes_written = unsafe { - (XKBH.xkb_keysym_to_utf8)(keysym, buffer.as_mut_ptr().cast(), buffer.capacity()) - }; - if bytes_written == 0 { - return None; - } else if bytes_written == -1 { - buffer.reserve(8); - } else { - unsafe { buffer.set_len(bytes_written.try_into().unwrap()) }; - break; - } +fn byte_slice_to_cached_string(bytes: &[u8]) -> &'static str { + use std::cell::RefCell; + use std::collections::HashSet; + + thread_local! { + static STRING_CACHE: RefCell> = RefCell::new(HashSet::new()); } - // remove the final `\0` - buffer.pop(); - // libxkbcommon will always provide valid UTF8 - Some(unsafe { String::from_utf8_unchecked(buffer) }) -} + let string = std::str::from_utf8(bytes).unwrap(); -fn cached_string>(string: S) -> &'static str { - Box::leak(string.into().into_boxed_str()) + STRING_CACHE.with(|cache| { + let mut cache = cache.borrow_mut(); + if let Some(string) = cache.get(string) { + *string + } else { + // borrowck couldn't quite figure out this one on its own + let string: &'static str = Box::leak(String::from(string).into_boxed_str()); + cache.insert(string); + string + } + }) } From ec028bae61edafcd53dc1eda4930101740694e6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Sat, 24 Apr 2021 18:06:34 +0200 Subject: [PATCH 19/53] Add initial X11 support --- src/platform_impl/linux/common/xkb_state.rs | 41 ++++++++++ .../linux/x11/event_processor.rs | 78 ++++++++++++------- src/platform_impl/linux/x11/mod.rs | 6 ++ 3 files changed, 96 insertions(+), 29 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index ab957920f9..59e03146f4 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -8,6 +8,11 @@ use std::ptr; #[cfg(feature = "wayland")] use memmap2::MmapOptions; +#[cfg(feature = "x11")] +use x11_dl::xlib_xcb::xcb_connection_t; +#[cfg(feature = "x11")] +use xkbcommon_dl::x11::XKBCOMMON_X11_HANDLE as XKBXH; + use xkbcommon_dl::{ self as ffi, xkb_state_component, XKBCOMMON_COMPOSE_HANDLE as XKBCH, XKBCOMMON_HANDLE as XKBH, }; @@ -237,6 +242,42 @@ impl KbState { Ok(me) } + #[cfg(feature = "x11")] + pub(crate) fn from_x11_xkb(connection: *mut xcb_connection_t) -> Result { + let mut me = Self::new()?; + + let result = unsafe { + (XKBXH.xkb_x11_setup_xkb_extension)( + connection, + 1, + 2, + xkbcommon_dl::x11::xkb_x11_setup_xkb_extension_flags::XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ) + }; + assert_eq!(result, 1, "Failed to initialize libxkbcommon"); + + // TODO: Support keyboards other than the "virtual core keyboard device". + let core_keyboard_id = unsafe { (XKBXH.xkb_x11_get_core_keyboard_device_id)(connection) }; + let keymap = unsafe { + (XKBXH.xkb_x11_keymap_new_from_device)( + me.xkb_context, + connection, + core_keyboard_id, + xkbcommon_dl::xkb_keymap_compile_flags::XKB_KEYMAP_COMPILE_NO_FLAGS, + ) + }; + assert_ne!(keymap, ptr::null_mut()); + me.xkb_keymap = keymap; + + unsafe { me.post_init(keymap) }; + + Ok(me) + } + pub(crate) fn from_rmlvo(rmlvo: RMLVO) -> Result { fn to_cstring(s: Option) -> Result, Error> { s.map_or(Ok(None), |s| CString::new(s).map(Option::Some)) diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 261ba15d76..45f9528ea5 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -1,13 +1,12 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc, slice, sync::Arc}; -use libc::{c_char, c_int, c_long, c_uint, c_ulong}; +use libc::{c_char, c_int, c_long, c_ulong}; use parking_lot::MutexGuard; use super::{ - events, ffi, get_xtarget, mkdid, mkwid, monitor, util, Device, DeviceId, DeviceInfo, Dnd, - DndState, GenericEventCookie, ImeReceiver, ScrollOrientation, UnownedWindow, WindowId, - XExtension, + ffi, get_xtarget, mkdid, mkwid, monitor, util, Device, DeviceId, DeviceInfo, Dnd, DndState, + GenericEventCookie, ImeReceiver, ScrollOrientation, UnownedWindow, WindowId, XExtension, }; use util::modifiers::{ModifierKeyState, ModifierKeymap}; @@ -17,6 +16,10 @@ use crate::{ event::{DeviceEvent, ElementState, Event, KeyEvent, RawKeyEvent, TouchPhase, WindowEvent}, event_loop::EventLoopWindowTarget as RootELW, keyboard::ModifiersState, + platform_impl::platform::{ + common::{keymap, xkb_state::KbState}, + KeyEventExtra, + }, }; /// The X11 documentation states: "Keycodes lie in the inclusive range [8,255]". @@ -29,6 +32,7 @@ pub(super) struct EventProcessor { pub(super) devices: RefCell>, pub(super) xi2ext: XExtension, pub(super) target: Rc>, + pub(super) kb_state: KbState, pub(super) mod_keymap: ModifierKeymap, pub(super) device_mod_state: ModifierKeyState, // Number of touch events currently in progress @@ -567,29 +571,34 @@ impl EventProcessor { // When a compose sequence or IME pre-edit is finished, it ends in a KeyPress with // a keycode of 0. if keycode != 0 { - let scancode = keycode - KEYCODE_OFFSET as u32; - let keysym = wt.xconn.lookup_keysym(xkev); - // let virtual_keycode = events::keysym_to_element(keysym as c_uint); + let keycode = keycode - KEYCODE_OFFSET as u32; + let mut ker = self.kb_state.process_key_event(keycode, state); + let physical_key = ker.keycode(); + let (logical_key, location) = ker.key(); + let text = ker.text(); + let (key_without_modifiers, _) = ker.key_without_modifiers(); + let text_with_all_modifiers = ker.text_with_all_modifiers(); update_modifiers!( ModifiersState::from_x11_mask(xkev.state), self.mod_keymap.get_modifier(xkev.keycode as ffi::KeyCode) ); - let modifiers = self.device_mod_state.modifiers(); - callback(Event::WindowEvent { window_id, event: WindowEvent::KeyboardInput { device_id, event: KeyEvent { - physical_key: todo!(), - logical_key: todo!(), - text: todo!(), - location: todo!(), + physical_key, + logical_key, + text, + location, state, - repeat: todo!(), - platform_specific: todo!(), + repeat: false, + platform_specific: KeyEventExtra { + key_without_modifiers, + text_with_all_modifiers, + }, }, is_synthetic: false, }, @@ -929,6 +938,7 @@ impl EventProcessor { wt, window_id, ElementState::Pressed, + &mut self.kb_state, &self.mod_keymap, &mut self.device_mod_state, &mut callback, @@ -953,6 +963,7 @@ impl EventProcessor { wt, window_id, ElementState::Released, + &mut self.kb_state, &self.mod_keymap, &mut self.device_mod_state, &mut callback, @@ -1095,18 +1106,19 @@ impl EventProcessor { if scancode < 0 { return; } - let keysym = wt.xconn.keycode_to_keysym(keycode as ffi::KeyCode); - // let virtual_keycode = events::keysym_to_element(keysym as c_uint); + let physical_key = keymap::rawkey_to_keycode(scancode as u32); let modifiers = self.device_mod_state.modifiers(); callback(Event::DeviceEvent { device_id, event: DeviceEvent::Key(RawKeyEvent { - physical_key: todo!(), - state: todo!(), + physical_key, + state, }), }); + // `ModifiersChanged` is dispatched here because we assume that every `KeyPress` is + // preceeded by a `RawKeyPress`. if let Some(modifier) = self.mod_keymap.get_modifier(keycode as ffi::KeyCode) { @@ -1227,6 +1239,7 @@ impl EventProcessor { wt: &super::EventLoopWindowTarget, window_id: crate::window::WindowId, state: ElementState, + kb_state: &mut KbState, mod_keymap: &ModifierKeymap, device_mod_state: &mut ModifierKeyState, callback: &mut F, @@ -1243,9 +1256,13 @@ impl EventProcessor { .into_iter() .filter(|k| *k >= KEYCODE_OFFSET) { - let scancode = (keycode - KEYCODE_OFFSET) as u32; - let keysym = wt.xconn.keycode_to_keysym(keycode); - // let virtual_keycode = events::keysym_to_element(keysym as c_uint); + let keycode = (keycode - KEYCODE_OFFSET) as u32; + let mut ker = kb_state.process_key_event(keycode, state); + let physical_key = ker.keycode(); + let (logical_key, location) = ker.key(); + let text = ker.text(); + let (key_without_modifiers, _) = ker.key_without_modifiers(); + let text_with_all_modifiers = ker.text_with_all_modifiers(); if let Some(modifier) = mod_keymap.get_modifier(keycode as ffi::KeyCode) { device_mod_state.key_event( @@ -1260,13 +1277,16 @@ impl EventProcessor { event: WindowEvent::KeyboardInput { device_id, event: KeyEvent { - physical_key: todo!(), - logical_key: todo!(), - text: todo!(), - location: todo!(), - state: todo!(), - repeat: todo!(), - platform_specific: todo!(), + physical_key, + logical_key, + text, + location, + state, + repeat: false, + platform_specific: KeyEventExtra { + key_without_modifiers, + text_with_all_modifiers, + }, }, is_synthetic: true, }, diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 27c92c46b3..03415d2538 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -47,6 +47,7 @@ use self::{ ime::{Ime, ImeCreationError, ImeReceiver, ImeSender}, util::modifiers::ModifierKeymap, }; +use super::common::xkb_state::KbState; use crate::{ error::OsError as RootOsError, event::{Event, StartCause}, @@ -195,6 +196,10 @@ impl EventLoop { let (user_sender, user_channel) = std::sync::mpsc::channel(); let (redraw_sender, redraw_channel) = std::sync::mpsc::channel(); + let kb_state = + KbState::from_x11_xkb(unsafe { (xconn.xlib_xcb.XGetXCBConnection)(xconn.display) }) + .unwrap(); + let target = Rc::new(RootELW { p: super::EventLoopWindowTarget::X(EventLoopWindowTarget { ime, @@ -220,6 +225,7 @@ impl EventLoop { randr_event_offset, ime_receiver, xi2ext, + kb_state, mod_keymap, device_mod_state: Default::default(), num_touch: 0, From 1a293b69abfe93272dca4711a5a029b9f11e0c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Sun, 25 Apr 2021 18:55:46 +0200 Subject: [PATCH 20/53] Address compilation errors --- Cargo.toml | 4 ++-- src/platform_impl/linux/common/keymap.rs | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5bb6373e5b..68a0c82846 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ targets = ["i686-pc-windows-msvc", "x86_64-pc-windows-msvc", "i686-unknown-linux [features] default = ["x11", "wayland", "wayland-dlopen"] -x11 = ["x11-dl", "mio", "percent-encoding", "parking_lot"] +x11 = ["x11-dl", "mio", "percent-encoding", "parking_lot", "xkbcommon-dl/x11"] wayland = ["wayland-client", "wayland-protocols", "sctk", "memmap2"] wayland-dlopen = ["sctk/dlopen", "wayland-client/dlopen"] @@ -97,7 +97,7 @@ percent-encoding = { version = "2.0", optional = true } parking_lot = { version = "0.11.0", optional = true } libc = "0.2.64" memmap2 = { version = "0.2.1", optional = true } -xkbcommon-dl = { git = "https://github.com/maroider/xkbcommon-dl", rev = "f335e626c" } +xkbcommon-dl = { git = "https://github.com/maroider/xkbcommon-dl", rev = "5307184" } [target.'cfg(target_arch = "wasm32")'.dependencies.web_sys] package = "web-sys" diff --git a/src/platform_impl/linux/common/keymap.rs b/src/platform_impl/linux/common/keymap.rs index dbd0431679..4f72adc8f9 100644 --- a/src/platform_impl/linux/common/keymap.rs +++ b/src/platform_impl/linux/common/keymap.rs @@ -423,8 +423,9 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { keysyms::XKB_KEY_Caps_Lock => Key::CapsLock, // keysyms::XKB_KEY_Shift_Lock => Key::ShiftLock, // - keysyms::XKB_KEY_Meta_L => Key::Meta, - keysyms::XKB_KEY_Meta_R => Key::Meta, + // TODO: Address how renaming `Meta` to `Super` affects this set of keys. + // keysyms::XKB_KEY_Meta_L => Key::Meta, + // keysyms::XKB_KEY_Meta_R => Key::Meta, keysyms::XKB_KEY_Alt_L => Key::Alt, keysyms::XKB_KEY_Alt_R => Key::Alt, keysyms::XKB_KEY_Super_L => Key::Super, From 68c95f741a56272f9a2ab2a0f838ce930dff4e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Sat, 24 Apr 2021 18:06:59 +0200 Subject: [PATCH 21/53] Improve debug printing of `NativeKeyCode` --- src/keyboard.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index 6329695fcf..80a5aa7922 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -195,7 +195,7 @@ impl std::fmt::Debug for NativeKeyCode { } XKB(v) => { debug_tuple = f.debug_tuple(name_of!(XKB)); - debug_tuple.field(v); + debug_tuple.field(&format_args!("0x{:04X}", v)); } } debug_tuple.finish() From ea646f779cd516e3d916a24bb429c0c49fef6e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Wed, 28 Apr 2021 17:33:41 +0200 Subject: [PATCH 22/53] Hook up X11 XKB modifier keys --- src/platform_impl/linux/common/xkb_state.rs | 10 +++--- .../linux/wayland/seat/keyboard/handlers.rs | 2 +- .../linux/x11/event_processor.rs | 24 +++++++++++++- src/platform_impl/linux/x11/mod.rs | 31 +++++++++++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index 59e03146f4..ce85501ee4 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -116,7 +116,9 @@ impl KbState { mods_depressed: u32, mods_latched: u32, mods_locked: u32, - group: u32, + depressed_group: u32, + latched_group: u32, + locked_group: u32, ) { if !self.ready() { return; @@ -127,9 +129,9 @@ impl KbState { mods_depressed, mods_latched, mods_locked, - 0, - 0, - group, + depressed_group, + latched_group, + locked_group, ) }; if mask.contains(xkb_state_component::XKB_STATE_MODS_EFFECTIVE) { diff --git a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs index 15bc1869d4..ee4188bde5 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs @@ -616,7 +616,7 @@ impl KbdHandler { ) { { let mut state = self.state.borrow_mut(); - state.update_modifiers(mods_depressed, mods_latched, mods_locked, group); + state.update_modifiers(mods_depressed, mods_latched, mods_locked, 0, 0, group); (&mut *self.callback.borrow_mut())( Event::Modifiers { modifiers: state.mods_state(), diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 45f9528ea5..4a56550ffe 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, collections::HashMap, rc::Rc, slice, sync::Arc}; +use std::{cell::RefCell, collections::HashMap, convert::identity, rc::Rc, slice, sync::Arc}; use libc::{c_char, c_int, c_long, c_ulong}; @@ -31,6 +31,7 @@ pub(super) struct EventProcessor { pub(super) randr_event_offset: c_int, pub(super) devices: RefCell>, pub(super) xi2ext: XExtension, + pub(super) xkbext: XExtension, pub(super) target: Rc>, pub(super) kb_state: KbState, pub(super) mod_keymap: ModifierKeymap, @@ -1168,6 +1169,27 @@ impl EventProcessor { } } _ => { + if event_type == self.xkbext.first_event_id { + let xev = unsafe { &*(identity(xev) as *const _ as *const ffi::XkbAnyEvent) }; + match xev.xkb_type { + ffi::XkbStateNotify => { + let xev = + unsafe { &*(xev as *const _ as *const ffi::XkbStateNotifyEvent) }; + if matches!(xev.event_type, 2 | 3) { + // TODO: Is `as u32` fine here? + self.kb_state.update_modifiers( + xev.base_mods, + xev.latched_mods, + xev.locked_mods, + u32::from_ne_bytes(xev.base_group.to_ne_bytes()), + u32::from_ne_bytes(xev.latched_group.to_ne_bytes()), + u32::from_ne_bytes(xev.locked_group.to_ne_bytes()), + ) + } + } + _ => {} + } + } if event_type == self.randr_event_offset { // In the future, it would be quite easy to emit monitor hotplug events. let prev_list = monitor::invalidate_cached_monitor_list(); diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 03415d2538..9632131d22 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -165,6 +165,27 @@ impl EventLoop { ext }; + let xkbext = { + let mut ext = XExtension::default(); + + let res = unsafe { + (xconn.xlib.XkbQueryExtension)( + xconn.display, + &mut ext.opcode, + &mut ext.first_event_id, + &mut ext.first_error_id, + &mut 1, + &mut 0, + ) + }; + + if res == ffi::False { + panic!("X server missing XKB extension"); + } + + ext + }; + unsafe { let mut xinput_major_ver = ffi::XI_2_Major; let mut xinput_minor_ver = ffi::XI_2_Minor; @@ -225,6 +246,7 @@ impl EventLoop { randr_event_offset, ime_receiver, xi2ext, + xkbext, kb_state, mod_keymap, device_mod_state: Default::default(), @@ -240,6 +262,15 @@ impl EventLoop { .select_xinput_events(root, ffi::XIAllDevices, ffi::XI_HierarchyChangedMask) .queue(); + get_xtarget(&target) + .xconn + .select_xkb_events( + 0x100, // Use the "core keyboard device" + ffi::XkbNewKeyboardNotifyMask | ffi::XkbMapNotifyMask | ffi::XkbStateNotifyMask, + ) + .unwrap() + .queue(); + event_processor.init_device(ffi::XIAllDevices); EventLoop { From d267299e57465150d74c2cfcd16c84c88937954e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Sat, 1 May 2021 19:56:51 +0200 Subject: [PATCH 23/53] Use XInput2 for regular key events --- .../linux/x11/event_processor.rs | 130 +++++++----------- src/platform_impl/linux/x11/mod.rs | 4 +- src/platform_impl/linux/x11/util/input.rs | 2 +- src/platform_impl/linux/x11/window.rs | 2 - 4 files changed, 56 insertions(+), 82 deletions(-) diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 4a56550ffe..e68edd7d36 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -548,81 +548,6 @@ impl EventProcessor { } } - ffi::KeyPress | ffi::KeyRelease => { - use crate::event::ElementState::{Pressed, Released}; - - // Note that in compose/pre-edit sequences, this will always be Released. - let state = if xev.get_type() == ffi::KeyPress { - Pressed - } else { - Released - }; - - let xkev: &mut ffi::XKeyEvent = xev.as_mut(); - - let window = xkev.window; - let window_id = mkwid(window); - - // Standard virtual core keyboard ID. XInput2 needs to be used to get a reliable - // value, though this should only be an issue under multiseat configurations. - let device = util::VIRTUAL_CORE_KEYBOARD; - let device_id = mkdid(device); - let keycode = xkev.keycode; - - // When a compose sequence or IME pre-edit is finished, it ends in a KeyPress with - // a keycode of 0. - if keycode != 0 { - let keycode = keycode - KEYCODE_OFFSET as u32; - let mut ker = self.kb_state.process_key_event(keycode, state); - let physical_key = ker.keycode(); - let (logical_key, location) = ker.key(); - let text = ker.text(); - let (key_without_modifiers, _) = ker.key_without_modifiers(); - let text_with_all_modifiers = ker.text_with_all_modifiers(); - - update_modifiers!( - ModifiersState::from_x11_mask(xkev.state), - self.mod_keymap.get_modifier(xkev.keycode as ffi::KeyCode) - ); - - callback(Event::WindowEvent { - window_id, - event: WindowEvent::KeyboardInput { - device_id, - event: KeyEvent { - physical_key, - logical_key, - text, - location, - state, - repeat: false, - platform_specific: KeyEventExtra { - key_without_modifiers, - text_with_all_modifiers, - }, - }, - is_synthetic: false, - }, - }); - } - - if state == Pressed { - let written = if let Some(ic) = wt.ime.borrow().get_context(window) { - wt.xconn.lookup_utf8(ic, xkev) - } else { - return; - }; - - for chr in written.chars() { - // let event = Event::WindowEvent { - // window_id, - // event: WindowEvent::ReceivedCharacter(chr), - // }; - // callback(event); - } - } - } - ffi::GenericEvent => { let guard = if let Some(e) = GenericEventCookie::from_event(&wt.xconn, *xev) { e @@ -1092,6 +1017,56 @@ impl EventProcessor { } } + // The regular KeyPress event has a problem where if you press a dead key, a KeyPress + // event won't be emitted. XInput 2 does not have this problem. + ffi::XI_KeyPress | ffi::XI_KeyRelease => { + if let Some(active_window) = self.active_window { + let state = if xev.evtype == ffi::XI_KeyPress { + Pressed + } else { + Released + }; + + let xkev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) }; + + // We use `self.active_window` here as `xkev.event` has a completely different + // value for some reason. + let window_id = mkwid(active_window); + + let device_id = mkdid(xkev.deviceid); + let keycode = xkev.detail as u32; + + let keycode = keycode - KEYCODE_OFFSET as u32; + let mut ker = self.kb_state.process_key_event(keycode, state); + let physical_key = ker.keycode(); + let (logical_key, location) = ker.key(); + let text = ker.text(); + let (key_without_modifiers, _) = ker.key_without_modifiers(); + let text_with_all_modifiers = ker.text_with_all_modifiers(); + let repeat = xkev.flags & ffi::XIKeyRepeat == ffi::XIKeyRepeat; + + callback(Event::WindowEvent { + window_id, + event: WindowEvent::KeyboardInput { + device_id, + event: KeyEvent { + physical_key, + logical_key, + text, + location, + state, + repeat, + platform_specific: KeyEventExtra { + key_without_modifiers, + text_with_all_modifiers, + }, + }, + is_synthetic: false, + }, + }); + } + } + ffi::XI_RawKeyPress | ffi::XI_RawKeyRelease => { let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) }; @@ -1118,8 +1093,8 @@ impl EventProcessor { }), }); - // `ModifiersChanged` is dispatched here because we assume that every `KeyPress` is - // preceeded by a `RawKeyPress`. + // `ModifiersChanged` is dispatched here because we assume that every `XI_KeyPress` + // is preceeded by a `XI_RawKeyPress`. if let Some(modifier) = self.mod_keymap.get_modifier(keycode as ffi::KeyCode) { @@ -1269,7 +1244,6 @@ impl EventProcessor { F: FnMut(Event<'_, T>), { let device_id = mkdid(util::VIRTUAL_CORE_KEYBOARD); - let modifiers = device_mod_state.modifiers(); // Update modifiers state and emit key events based on which keys are currently pressed. for keycode in wt diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 9632131d22..a8c8956075 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -662,7 +662,9 @@ impl Device { | ffi::XI_RawButtonPressMask | ffi::XI_RawButtonReleaseMask | ffi::XI_RawKeyPressMask - | ffi::XI_RawKeyReleaseMask; + | ffi::XI_RawKeyReleaseMask + | ffi::XI_KeyPressMask + | ffi::XI_KeyReleaseMask; // The request buffer is flushed when we poll for events wt.xconn .select_xinput_events(wt.root, info.deviceid, mask) diff --git a/src/platform_impl/linux/x11/util/input.rs b/src/platform_impl/linux/x11/util/input.rs index 6c7c651eed..db0f22eb03 100644 --- a/src/platform_impl/linux/x11/util/input.rs +++ b/src/platform_impl/linux/x11/util/input.rs @@ -81,12 +81,12 @@ impl XConnection { Flusher::new(self) } - #[allow(dead_code)] pub fn select_xkb_events(&self, device_id: c_uint, mask: c_ulong) -> Option> { let status = unsafe { (self.xlib.XkbSelectEvents)(self.display, device_id, mask, mask) }; if status == ffi::True { Some(Flusher::new(self)) } else { + // This should only happen if the XKB extension isn't initialized. None } } diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index 45759b05b2..7073a919d0 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -230,8 +230,6 @@ impl UnownedWindow { swa.event_mask = ffi::ExposureMask | ffi::StructureNotifyMask | ffi::VisibilityChangeMask - | ffi::KeyPressMask - | ffi::KeyReleaseMask | ffi::KeymapStateMask | ffi::ButtonPressMask | ffi::ButtonReleaseMask From 14dd7d39c4ece67d34117db58721fa0a4a54fd8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Fri, 7 May 2021 17:20:54 +0200 Subject: [PATCH 24/53] Implement dead-key handling --- src/platform_impl/linux/common/xkb_state.rs | 156 +++++++++++++++----- 1 file changed, 121 insertions(+), 35 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index ce85501ee4..7651d8370b 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -30,6 +30,7 @@ pub(crate) struct KbState { xkb_state: *mut ffi::xkb_state, xkb_compose_table: *mut ffi::xkb_compose_table, xkb_compose_state: *mut ffi::xkb_compose_state, + xkb_compose_state_2: *mut ffi::xkb_compose_state, mods_state: ModifiersState, locked: bool, scratch_buffer: Vec, @@ -174,27 +175,62 @@ impl KbState { Some(byte_slice_to_cached_string(&self.scratch_buffer)) } - pub(crate) fn compose_feed(&mut self, keysym: u32) -> Option { + fn compose_feed_normal(&mut self, keysym: u32) -> Option { + self.compose_feed(self.xkb_compose_state, keysym) + } + + fn compose_feed_2(&mut self, keysym: u32) -> Option { + self.compose_feed(self.xkb_compose_state_2, keysym) + } + + fn compose_feed( + &mut self, + xkb_compose_state: *mut ffi::xkb_compose_state, + keysym: u32, + ) -> Option { if !self.ready() || self.xkb_compose_state.is_null() { return None; } - Some(unsafe { (XKBCH.xkb_compose_state_feed)(self.xkb_compose_state, keysym) }) + Some(unsafe { (XKBCH.xkb_compose_state_feed)(xkb_compose_state, keysym) }) } - pub(crate) fn compose_status(&mut self) -> Option { - if !self.ready() || self.xkb_compose_state.is_null() { + fn compose_status_normal(&mut self) -> Option { + self.compose_status(self.xkb_compose_state) + } + + #[allow(dead_code)] + fn compose_status_2(&mut self) -> Option { + self.compose_status(self.xkb_compose_state_2) + } + + fn compose_status( + &mut self, + xkb_compose_state: *mut ffi::xkb_compose_state, + ) -> Option { + if !self.ready() || xkb_compose_state.is_null() { return None; } - Some(unsafe { (XKBCH.xkb_compose_state_get_status)(self.xkb_compose_state) }) + Some(unsafe { (XKBCH.xkb_compose_state_get_status)(xkb_compose_state) }) } - pub(crate) fn compose_get_utf8(&mut self) -> Option<&'static str> { - if !self.ready() || self.xkb_compose_state.is_null() { + fn compose_get_utf8_normal(&mut self) -> Option<&'static str> { + self.compose_get_utf8(self.xkb_compose_state) + } + + fn compose_get_utf8_2(&mut self) -> Option<&'static str> { + self.compose_get_utf8(self.xkb_compose_state_2) + } + + fn compose_get_utf8( + &mut self, + xkb_compose_state: *mut ffi::xkb_compose_state, + ) -> Option<&'static str> { + if !self.ready() || xkb_compose_state.is_null() { return None; } - let size = unsafe { - (XKBCH.xkb_compose_state_get_utf8)(self.xkb_compose_state, ptr::null_mut(), 0) - } + 1; + let size = + unsafe { (XKBCH.xkb_compose_state_get_utf8)(xkb_compose_state, ptr::null_mut(), 0) } + + 1; if size <= 1 { return None; }; @@ -204,7 +240,7 @@ impl KbState { unsafe { self.scratch_buffer.set_len(size); (XKBCH.xkb_compose_state_get_utf8)( - self.xkb_compose_state, + xkb_compose_state, self.scratch_buffer.as_mut_ptr() as *mut _, size as usize, ); @@ -232,18 +268,19 @@ impl KbState { xkb_state: ptr::null_mut(), xkb_compose_table: ptr::null_mut(), xkb_compose_state: ptr::null_mut(), + xkb_compose_state_2: ptr::null_mut(), mods_state: ModifiersState::new(), locked: false, scratch_buffer: Vec::new(), }; - unsafe { - me.init_compose(); - } + unsafe { me.init_compose() }; Ok(me) } +} +impl KbState { #[cfg(feature = "x11")] pub(crate) fn from_x11_xkb(connection: *mut xcb_connection_t) -> Result { let mut me = Self::new()?; @@ -310,7 +347,7 @@ impl KbState { Ok(state) } - pub(crate) unsafe fn init_compose(&mut self) { + unsafe fn init_compose(&mut self) { let locale = env::var_os("LC_ALL") .and_then(|v| if v.is_empty() { None } else { Some(v) }) .or_else(|| env::var_os("LC_CTYPE")) @@ -336,7 +373,12 @@ impl KbState { ffi::xkb_compose_state_flags::XKB_COMPOSE_STATE_NO_FLAGS, ); - if compose_state.is_null() { + let compose_state_2 = (XKBCH.xkb_compose_state_new)( + compose_table, + ffi::xkb_compose_state_flags::XKB_COMPOSE_STATE_NO_FLAGS, + ); + + if compose_state.is_null() || compose_state_2.is_null() { // init of compose state failed, continue without compose (XKBCH.xkb_compose_table_unref)(compose_table); return; @@ -344,6 +386,7 @@ impl KbState { self.xkb_compose_table = compose_table; self.xkb_compose_state = compose_state; + self.xkb_compose_state_2 = compose_state_2; } pub(crate) unsafe fn post_init(&mut self, keymap: *mut ffi::xkb_keymap) { @@ -396,7 +439,9 @@ impl KbState { Ok(()) } +} +impl KbState { pub(crate) unsafe fn key_repeats(&mut self, keycode: ffi::xkb_keycode_t) -> bool { (XKBH.xkb_keymap_key_repeats)(self.xkb_keymap, keycode + 8) == 1 } @@ -477,6 +522,7 @@ impl KbState { } } +#[derive(Copy, Clone, Debug)] enum XkbCompose { Accepted(ffi::xkb_compose_status), Ignored, @@ -495,10 +541,10 @@ impl<'a> KeyEventResults<'a> { let keysym = state.get_one_sym_raw(keycode); let compose = if compose { - Some(match state.compose_feed(keysym) { + Some(match state.compose_feed_normal(keysym) { Some(ffi::xkb_compose_feed_result::XKB_COMPOSE_FEED_ACCEPTED) => { // Unwrapping is safe here, as `compose_feed` returns `None` when composition is uninitialized. - XkbCompose::Accepted(state.compose_status().unwrap()) + XkbCompose::Accepted(state.compose_status_normal().unwrap()) } Some(ffi::xkb_compose_feed_result::XKB_COMPOSE_FEED_IGNORED) => XkbCompose::Ignored, None => XkbCompose::Uninitialized, @@ -521,6 +567,34 @@ impl<'a> KeyEventResults<'a> { pub fn key(&mut self) -> (Key<'static>, KeyLocation) { self.keysym_to_key(self.keysym) + .unwrap_or_else(|(key, location)| match self.compose { + Some(XkbCompose::Accepted(ffi::xkb_compose_status::XKB_COMPOSE_COMPOSING)) => { + // When pressing a dead key twice, the non-combining variant of that character will be + // produced. Since this function only concerns itself with a single keypress, we simulate + // this double press here by feeding the keysym to the compose state twice. + self.state.compose_feed_2(self.keysym); + match self.state.compose_feed_2(self.keysym) { + Some(ffi::xkb_compose_feed_result::XKB_COMPOSE_FEED_ACCEPTED) => ( + // Extracting only a single `char` here *should* be fine, assuming that no dead + // key's non-combining variant ever occupies more than one `char`. + Key::Dead( + self.state + .compose_get_utf8_2() + .map(|s| s.chars().nth(0).unwrap()), + ), + location, + ), + _ => (key, location), + } + } + _ => ( + self.composed_text() + .unwrap_or_else(|_| self.state.keysym_to_utf8_raw(self.keysym)) + .map(Key::Character) + .unwrap_or(key), + location, + ), + }) } pub fn key_without_modifiers(&mut self) -> (Key<'static>, KeyLocation) { @@ -541,45 +615,57 @@ impl<'a> KeyEventResults<'a> { 0 }; self.keysym_to_key(keysym) + .unwrap_or_else(|(key, location)| { + ( + self.state + .keysym_to_utf8_raw(keysym) + .map(Key::Character) + .unwrap_or(key), + location, + ) + }) } - fn keysym_to_key(&mut self, keysym: u32) -> (Key<'static>, KeyLocation) { + fn keysym_to_key( + &mut self, + keysym: u32, + ) -> Result<(Key<'static>, KeyLocation), (Key<'static>, KeyLocation)> { let location = super::keymap::keysym_location(keysym); - let mut key = super::keymap::keysym_to_key(keysym); + let key = super::keymap::keysym_to_key(keysym); if matches!(key, Key::Unidentified(_)) { - if let Some(string) = self.state.keysym_to_utf8_raw(keysym) { - key = Key::Character(string); - } + Err((key, location)) + } else { + Ok((key, location)) } - (key, location) } pub fn text(&mut self) -> Option<&'static str> { - self._text(|this| this.state.keysym_to_utf8_raw(this.keysym)) + self.composed_text() + .unwrap_or_else(|_| self.state.keysym_to_utf8_raw(self.keysym)) } pub fn text_with_all_modifiers(&mut self) -> Option<&'static str> { // TODO: Should Ctrl override any attempts to compose text? // gnome-terminal agrees, but konsole disagrees. // Should it be configurable instead? - self._text(|this| this.state.get_utf8_raw(this.keycode)) + self.composed_text() + .unwrap_or_else(|_| self.state.get_utf8_raw(self.keycode)) } - fn _text(&mut self, fallback: F) -> Option<&'static str> - where - F: FnOnce(&mut Self) -> Option<&'static str>, - { + fn composed_text(&mut self) -> Result, ()> { if let Some(compose) = &self.compose { match compose { XkbCompose::Accepted(status) => match status { - ffi::xkb_compose_status::XKB_COMPOSE_COMPOSED => self.state.compose_get_utf8(), - ffi::xkb_compose_status::XKB_COMPOSE_NOTHING => fallback(self), - _ => None, + ffi::xkb_compose_status::XKB_COMPOSE_COMPOSED => { + Ok(self.state.compose_get_utf8_normal()) + } + ffi::xkb_compose_status::XKB_COMPOSE_NOTHING => Err(()), + _ => Ok(None), }, - XkbCompose::Ignored | XkbCompose::Uninitialized => fallback(self), + XkbCompose::Ignored | XkbCompose::Uninitialized => Err(()), } } else { - fallback(self) + Err(()) } } } From fba2b1b9b7218ad9f6069c6c708ef4100bfbfff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Fri, 7 May 2021 17:21:39 +0200 Subject: [PATCH 25/53] Remove unused module --- src/platform_impl/linux/x11/events.rs | 1008 ------------------------- src/platform_impl/linux/x11/mod.rs | 2 +- 2 files changed, 1 insertion(+), 1009 deletions(-) delete mode 100644 src/platform_impl/linux/x11/events.rs diff --git a/src/platform_impl/linux/x11/events.rs b/src/platform_impl/linux/x11/events.rs deleted file mode 100644 index e721ab5922..0000000000 --- a/src/platform_impl/linux/x11/events.rs +++ /dev/null @@ -1,1008 +0,0 @@ -use super::ffi; -use crate::keyboard::KeyCode; -use libc; - -// pub fn keysym_to_element(keysym: libc::c_uint) -> Option { -// Some(match keysym { -// ffi::XK_BackSpace => VirtualKeyCode::Back, -// ffi::XK_Tab => VirtualKeyCode::Tab, -// //ffi::XK_Linefeed => VirtualKeyCode::Linefeed, -// //ffi::XK_Clear => VirtualKeyCode::Clear, -// ffi::XK_Return => VirtualKeyCode::Return, -// //ffi::XK_Pause => VirtualKeyCode::Pause, -// //ffi::XK_Scroll_Lock => VirtualKeyCode::Scroll_lock, -// //ffi::XK_Sys_Req => VirtualKeyCode::Sys_req, -// ffi::XK_Escape => VirtualKeyCode::Escape, -// ffi::XK_Delete => VirtualKeyCode::Delete, -// ffi::XK_Multi_key => VirtualKeyCode::Compose, -// //ffi::XK_Kanji => VirtualKeyCode::Kanji, -// //ffi::XK_Muhenkan => VirtualKeyCode::Muhenkan, -// //ffi::XK_Henkan_Mode => VirtualKeyCode::Henkan_mode, -// //ffi::XK_Henkan => VirtualKeyCode::Henkan, -// //ffi::XK_Romaji => VirtualKeyCode::Romaji, -// //ffi::XK_Hiragana => VirtualKeyCode::Hiragana, -// //ffi::XK_Katakana => VirtualKeyCode::Katakana, -// //ffi::XK_Hiragana_Katakana => VirtualKeyCode::Hiragana_katakana, -// //ffi::XK_Zenkaku => VirtualKeyCode::Zenkaku, -// //ffi::XK_Hankaku => VirtualKeyCode::Hankaku, -// //ffi::XK_Zenkaku_Hankaku => VirtualKeyCode::Zenkaku_hankaku, -// //ffi::XK_Touroku => VirtualKeyCode::Touroku, -// //ffi::XK_Massyo => VirtualKeyCode::Massyo, -// //ffi::XK_Kana_Lock => VirtualKeyCode::Kana_lock, -// //ffi::XK_Kana_Shift => VirtualKeyCode::Kana_shift, -// //ffi::XK_Eisu_Shift => VirtualKeyCode::Eisu_shift, -// //ffi::XK_Eisu_toggle => VirtualKeyCode::Eisu_toggle, -// ffi::XK_Home => VirtualKeyCode::Home, -// ffi::XK_Left => VirtualKeyCode::Left, -// ffi::XK_Up => VirtualKeyCode::Up, -// ffi::XK_Right => VirtualKeyCode::Right, -// ffi::XK_Down => VirtualKeyCode::Down, -// //ffi::XK_Prior => VirtualKeyCode::Prior, -// ffi::XK_Page_Up => VirtualKeyCode::PageUp, -// //ffi::XK_Next => VirtualKeyCode::Next, -// ffi::XK_Page_Down => VirtualKeyCode::PageDown, -// ffi::XK_End => VirtualKeyCode::End, -// //ffi::XK_Begin => VirtualKeyCode::Begin, -// //ffi::XK_Win_L => VirtualKeyCode::Win_l, -// //ffi::XK_Win_R => VirtualKeyCode::Win_r, -// //ffi::XK_App => VirtualKeyCode::App, -// //ffi::XK_Select => VirtualKeyCode::Select, -// //ffi::XK_Print => VirtualKeyCode::Print, -// //ffi::XK_Execute => VirtualKeyCode::Execute, -// ffi::XK_Insert => VirtualKeyCode::Insert, -// //ffi::XK_Undo => VirtualKeyCode::Undo, -// //ffi::XK_Redo => VirtualKeyCode::Redo, -// //ffi::XK_Menu => VirtualKeyCode::Menu, -// //ffi::XK_Find => VirtualKeyCode::Find, -// //ffi::XK_Cancel => VirtualKeyCode::Cancel, -// //ffi::XK_Help => VirtualKeyCode::Help, -// //ffi::XK_Break => VirtualKeyCode::Break, -// //ffi::XK_Mode_switch => VirtualKeyCode::Mode_switch, -// //ffi::XK_script_switch => VirtualKeyCode::Script_switch, -// //ffi::XK_Num_Lock => VirtualKeyCode::Num_lock, -// //ffi::XK_KP_Space => VirtualKeyCode::Kp_space, -// //ffi::XK_KP_Tab => VirtualKeyCode::Kp_tab, -// //ffi::XK_KP_Enter => VirtualKeyCode::Kp_enter, -// //ffi::XK_KP_F1 => VirtualKeyCode::Kp_f1, -// //ffi::XK_KP_F2 => VirtualKeyCode::Kp_f2, -// //ffi::XK_KP_F3 => VirtualKeyCode::Kp_f3, -// //ffi::XK_KP_F4 => VirtualKeyCode::Kp_f4, -// ffi::XK_KP_Home => VirtualKeyCode::Home, -// ffi::XK_KP_Left => VirtualKeyCode::Left, -// ffi::XK_KP_Up => VirtualKeyCode::Up, -// ffi::XK_KP_Right => VirtualKeyCode::Right, -// ffi::XK_KP_Down => VirtualKeyCode::Down, -// //ffi::XK_KP_Prior => VirtualKeyCode::Kp_prior, -// ffi::XK_KP_Page_Up => VirtualKeyCode::PageUp, -// //ffi::XK_KP_Next => VirtualKeyCode::Kp_next, -// ffi::XK_KP_Page_Down => VirtualKeyCode::PageDown, -// ffi::XK_KP_End => VirtualKeyCode::End, -// //ffi::XK_KP_Begin => VirtualKeyCode::Kp_begin, -// ffi::XK_KP_Insert => VirtualKeyCode::Insert, -// ffi::XK_KP_Delete => VirtualKeyCode::Delete, -// ffi::XK_KP_Equal => VirtualKeyCode::NumpadEquals, -// ffi::XK_KP_Multiply => VirtualKeyCode::NumpadMultiply, -// ffi::XK_KP_Add => VirtualKeyCode::NumpadAdd, -// //ffi::XK_KP_Separator => VirtualKeyCode::Kp_separator, -// ffi::XK_KP_Subtract => VirtualKeyCode::NumpadSubtract, -// ffi::XK_KP_Decimal => VirtualKeyCode::NumpadDecimal, -// ffi::XK_KP_Divide => VirtualKeyCode::NumpadDivide, -// ffi::XK_KP_0 => VirtualKeyCode::Numpad0, -// ffi::XK_KP_1 => VirtualKeyCode::Numpad1, -// ffi::XK_KP_2 => VirtualKeyCode::Numpad2, -// ffi::XK_KP_3 => VirtualKeyCode::Numpad3, -// ffi::XK_KP_4 => VirtualKeyCode::Numpad4, -// ffi::XK_KP_5 => VirtualKeyCode::Numpad5, -// ffi::XK_KP_6 => VirtualKeyCode::Numpad6, -// ffi::XK_KP_7 => VirtualKeyCode::Numpad7, -// ffi::XK_KP_8 => VirtualKeyCode::Numpad8, -// ffi::XK_KP_9 => VirtualKeyCode::Numpad9, -// ffi::XK_F1 => VirtualKeyCode::F1, -// ffi::XK_F2 => VirtualKeyCode::F2, -// ffi::XK_F3 => VirtualKeyCode::F3, -// ffi::XK_F4 => VirtualKeyCode::F4, -// ffi::XK_F5 => VirtualKeyCode::F5, -// ffi::XK_F6 => VirtualKeyCode::F6, -// ffi::XK_F7 => VirtualKeyCode::F7, -// ffi::XK_F8 => VirtualKeyCode::F8, -// ffi::XK_F9 => VirtualKeyCode::F9, -// ffi::XK_F10 => VirtualKeyCode::F10, -// ffi::XK_F11 => VirtualKeyCode::F11, -// //ffi::XK_L1 => VirtualKeyCode::L1, -// ffi::XK_F12 => VirtualKeyCode::F12, -// //ffi::XK_L2 => VirtualKeyCode::L2, -// ffi::XK_F13 => VirtualKeyCode::F13, -// //ffi::XK_L3 => VirtualKeyCode::L3, -// ffi::XK_F14 => VirtualKeyCode::F14, -// //ffi::XK_L4 => VirtualKeyCode::L4, -// ffi::XK_F15 => VirtualKeyCode::F15, -// //ffi::XK_L5 => VirtualKeyCode::L5, -// ffi::XK_F16 => VirtualKeyCode::F16, -// //ffi::XK_L6 => VirtualKeyCode::L6, -// ffi::XK_F17 => VirtualKeyCode::F17, -// //ffi::XK_L7 => VirtualKeyCode::L7, -// ffi::XK_F18 => VirtualKeyCode::F18, -// //ffi::XK_L8 => VirtualKeyCode::L8, -// ffi::XK_F19 => VirtualKeyCode::F19, -// //ffi::XK_L9 => VirtualKeyCode::L9, -// ffi::XK_F20 => VirtualKeyCode::F20, -// //ffi::XK_L10 => VirtualKeyCode::L10, -// ffi::XK_F21 => VirtualKeyCode::F21, -// //ffi::XK_R1 => VirtualKeyCode::R1, -// ffi::XK_F22 => VirtualKeyCode::F22, -// //ffi::XK_R2 => VirtualKeyCode::R2, -// ffi::XK_F23 => VirtualKeyCode::F23, -// //ffi::XK_R3 => VirtualKeyCode::R3, -// ffi::XK_F24 => VirtualKeyCode::F24, -// //ffi::XK_R4 => VirtualKeyCode::R4, -// //ffi::XK_F25 => VirtualKeyCode::F25, -// //ffi::XK_R5 => VirtualKeyCode::R5, -// //ffi::XK_F26 => VirtualKeyCode::F26, -// //ffi::XK_R6 => VirtualKeyCode::R6, -// //ffi::XK_F27 => VirtualKeyCode::F27, -// //ffi::XK_R7 => VirtualKeyCode::R7, -// //ffi::XK_F28 => VirtualKeyCode::F28, -// //ffi::XK_R8 => VirtualKeyCode::R8, -// //ffi::XK_F29 => VirtualKeyCode::F29, -// //ffi::XK_R9 => VirtualKeyCode::R9, -// //ffi::XK_F30 => VirtualKeyCode::F30, -// //ffi::XK_R10 => VirtualKeyCode::R10, -// //ffi::XK_F31 => VirtualKeyCode::F31, -// //ffi::XK_R11 => VirtualKeyCode::R11, -// //ffi::XK_F32 => VirtualKeyCode::F32, -// //ffi::XK_R12 => VirtualKeyCode::R12, -// //ffi::XK_F33 => VirtualKeyCode::F33, -// //ffi::XK_R13 => VirtualKeyCode::R13, -// //ffi::XK_F34 => VirtualKeyCode::F34, -// //ffi::XK_R14 => VirtualKeyCode::R14, -// //ffi::XK_F35 => VirtualKeyCode::F35, -// //ffi::XK_R15 => VirtualKeyCode::R15, -// ffi::XK_Shift_L => VirtualKeyCode::LShift, -// ffi::XK_Shift_R => VirtualKeyCode::RShift, -// ffi::XK_Control_L => VirtualKeyCode::LControl, -// ffi::XK_Control_R => VirtualKeyCode::RControl, -// //ffi::XK_Caps_Lock => VirtualKeyCode::Caps_lock, -// //ffi::XK_Shift_Lock => VirtualKeyCode::Shift_lock, -// //ffi::XK_Meta_L => VirtualKeyCode::Meta_l, -// //ffi::XK_Meta_R => VirtualKeyCode::Meta_r, -// ffi::XK_Alt_L => VirtualKeyCode::LAlt, -// ffi::XK_Alt_R => VirtualKeyCode::RAlt, -// //ffi::XK_Super_L => VirtualKeyCode::Super_l, -// //ffi::XK_Super_R => VirtualKeyCode::Super_r, -// //ffi::XK_Hyper_L => VirtualKeyCode::Hyper_l, -// //ffi::XK_Hyper_R => VirtualKeyCode::Hyper_r, -// ffi::XK_ISO_Left_Tab => VirtualKeyCode::Tab, -// ffi::XK_space => VirtualKeyCode::Space, -// //ffi::XK_exclam => VirtualKeyCode::Exclam, -// //ffi::XK_quotedbl => VirtualKeyCode::Quotedbl, -// //ffi::XK_numbersign => VirtualKeyCode::Numbersign, -// //ffi::XK_dollar => VirtualKeyCode::Dollar, -// //ffi::XK_percent => VirtualKeyCode::Percent, -// //ffi::XK_ampersand => VirtualKeyCode::Ampersand, -// ffi::XK_apostrophe => VirtualKeyCode::Apostrophe, -// //ffi::XK_quoteright => VirtualKeyCode::Quoteright, -// //ffi::XK_parenleft => VirtualKeyCode::Parenleft, -// //ffi::XK_parenright => VirtualKeyCode::Parenright, -// ffi::XK_asterisk => VirtualKeyCode::Asterisk, -// ffi::XK_plus => VirtualKeyCode::Plus, -// ffi::XK_comma => VirtualKeyCode::Comma, -// ffi::XK_minus => VirtualKeyCode::Minus, -// ffi::XK_period => VirtualKeyCode::Period, -// ffi::XK_slash => VirtualKeyCode::Slash, -// ffi::XK_0 => VirtualKeyCode::Key0, -// ffi::XK_1 => VirtualKeyCode::Key1, -// ffi::XK_2 => VirtualKeyCode::Key2, -// ffi::XK_3 => VirtualKeyCode::Key3, -// ffi::XK_4 => VirtualKeyCode::Key4, -// ffi::XK_5 => VirtualKeyCode::Key5, -// ffi::XK_6 => VirtualKeyCode::Key6, -// ffi::XK_7 => VirtualKeyCode::Key7, -// ffi::XK_8 => VirtualKeyCode::Key8, -// ffi::XK_9 => VirtualKeyCode::Key9, -// ffi::XK_colon => VirtualKeyCode::Colon, -// ffi::XK_semicolon => VirtualKeyCode::Semicolon, -// //ffi::XK_less => VirtualKeyCode::Less, -// ffi::XK_equal => VirtualKeyCode::Equals, -// //ffi::XK_greater => VirtualKeyCode::Greater, -// //ffi::XK_question => VirtualKeyCode::Question, -// ffi::XK_at => VirtualKeyCode::At, -// ffi::XK_A => VirtualKeyCode::A, -// ffi::XK_B => VirtualKeyCode::B, -// ffi::XK_C => VirtualKeyCode::C, -// ffi::XK_D => VirtualKeyCode::D, -// ffi::XK_E => VirtualKeyCode::E, -// ffi::XK_F => VirtualKeyCode::F, -// ffi::XK_G => VirtualKeyCode::G, -// ffi::XK_H => VirtualKeyCode::H, -// ffi::XK_I => VirtualKeyCode::I, -// ffi::XK_J => VirtualKeyCode::J, -// ffi::XK_K => VirtualKeyCode::K, -// ffi::XK_L => VirtualKeyCode::L, -// ffi::XK_M => VirtualKeyCode::M, -// ffi::XK_N => VirtualKeyCode::N, -// ffi::XK_O => VirtualKeyCode::O, -// ffi::XK_P => VirtualKeyCode::P, -// ffi::XK_Q => VirtualKeyCode::Q, -// ffi::XK_R => VirtualKeyCode::R, -// ffi::XK_S => VirtualKeyCode::S, -// ffi::XK_T => VirtualKeyCode::T, -// ffi::XK_U => VirtualKeyCode::U, -// ffi::XK_V => VirtualKeyCode::V, -// ffi::XK_W => VirtualKeyCode::W, -// ffi::XK_X => VirtualKeyCode::X, -// ffi::XK_Y => VirtualKeyCode::Y, -// ffi::XK_Z => VirtualKeyCode::Z, -// ffi::XK_bracketleft => VirtualKeyCode::LBracket, -// ffi::XK_backslash => VirtualKeyCode::Backslash, -// ffi::XK_bracketright => VirtualKeyCode::RBracket, -// //ffi::XK_asciicircum => VirtualKeyCode::Asciicircum, -// //ffi::XK_underscore => VirtualKeyCode::Underscore, -// ffi::XK_grave => VirtualKeyCode::Grave, -// //ffi::XK_quoteleft => VirtualKeyCode::Quoteleft, -// ffi::XK_a => VirtualKeyCode::A, -// ffi::XK_b => VirtualKeyCode::B, -// ffi::XK_c => VirtualKeyCode::C, -// ffi::XK_d => VirtualKeyCode::D, -// ffi::XK_e => VirtualKeyCode::E, -// ffi::XK_f => VirtualKeyCode::F, -// ffi::XK_g => VirtualKeyCode::G, -// ffi::XK_h => VirtualKeyCode::H, -// ffi::XK_i => VirtualKeyCode::I, -// ffi::XK_j => VirtualKeyCode::J, -// ffi::XK_k => VirtualKeyCode::K, -// ffi::XK_l => VirtualKeyCode::L, -// ffi::XK_m => VirtualKeyCode::M, -// ffi::XK_n => VirtualKeyCode::N, -// ffi::XK_o => VirtualKeyCode::O, -// ffi::XK_p => VirtualKeyCode::P, -// ffi::XK_q => VirtualKeyCode::Q, -// ffi::XK_r => VirtualKeyCode::R, -// ffi::XK_s => VirtualKeyCode::S, -// ffi::XK_t => VirtualKeyCode::T, -// ffi::XK_u => VirtualKeyCode::U, -// ffi::XK_v => VirtualKeyCode::V, -// ffi::XK_w => VirtualKeyCode::W, -// ffi::XK_x => VirtualKeyCode::X, -// ffi::XK_y => VirtualKeyCode::Y, -// ffi::XK_z => VirtualKeyCode::Z, -// //ffi::XK_braceleft => VirtualKeyCode::Braceleft, -// //ffi::XK_bar => VirtualKeyCode::Bar, -// //ffi::XK_braceright => VirtualKeyCode::Braceright, -// //ffi::XK_asciitilde => VirtualKeyCode::Asciitilde, -// //ffi::XK_nobreakspace => VirtualKeyCode::Nobreakspace, -// //ffi::XK_exclamdown => VirtualKeyCode::Exclamdown, -// //ffi::XK_cent => VirtualKeyCode::Cent, -// //ffi::XK_sterling => VirtualKeyCode::Sterling, -// //ffi::XK_currency => VirtualKeyCode::Currency, -// //ffi::XK_yen => VirtualKeyCode::Yen, -// //ffi::XK_brokenbar => VirtualKeyCode::Brokenbar, -// //ffi::XK_section => VirtualKeyCode::Section, -// //ffi::XK_diaeresis => VirtualKeyCode::Diaeresis, -// //ffi::XK_copyright => VirtualKeyCode::Copyright, -// //ffi::XK_ordfeminine => VirtualKeyCode::Ordfeminine, -// //ffi::XK_guillemotleft => VirtualKeyCode::Guillemotleft, -// //ffi::XK_notsign => VirtualKeyCode::Notsign, -// //ffi::XK_hyphen => VirtualKeyCode::Hyphen, -// //ffi::XK_registered => VirtualKeyCode::Registered, -// //ffi::XK_macron => VirtualKeyCode::Macron, -// //ffi::XK_degree => VirtualKeyCode::Degree, -// //ffi::XK_plusminus => VirtualKeyCode::Plusminus, -// //ffi::XK_twosuperior => VirtualKeyCode::Twosuperior, -// //ffi::XK_threesuperior => VirtualKeyCode::Threesuperior, -// //ffi::XK_acute => VirtualKeyCode::Acute, -// //ffi::XK_mu => VirtualKeyCode::Mu, -// //ffi::XK_paragraph => VirtualKeyCode::Paragraph, -// //ffi::XK_periodcentered => VirtualKeyCode::Periodcentered, -// //ffi::XK_cedilla => VirtualKeyCode::Cedilla, -// //ffi::XK_onesuperior => VirtualKeyCode::Onesuperior, -// //ffi::XK_masculine => VirtualKeyCode::Masculine, -// //ffi::XK_guillemotright => VirtualKeyCode::Guillemotright, -// //ffi::XK_onequarter => VirtualKeyCode::Onequarter, -// //ffi::XK_onehalf => VirtualKeyCode::Onehalf, -// //ffi::XK_threequarters => VirtualKeyCode::Threequarters, -// //ffi::XK_questiondown => VirtualKeyCode::Questiondown, -// //ffi::XK_Agrave => VirtualKeyCode::Agrave, -// //ffi::XK_Aacute => VirtualKeyCode::Aacute, -// //ffi::XK_Acircumflex => VirtualKeyCode::Acircumflex, -// //ffi::XK_Atilde => VirtualKeyCode::Atilde, -// //ffi::XK_Adiaeresis => VirtualKeyCode::Adiaeresis, -// //ffi::XK_Aring => VirtualKeyCode::Aring, -// //ffi::XK_AE => VirtualKeyCode::Ae, -// //ffi::XK_Ccedilla => VirtualKeyCode::Ccedilla, -// //ffi::XK_Egrave => VirtualKeyCode::Egrave, -// //ffi::XK_Eacute => VirtualKeyCode::Eacute, -// //ffi::XK_Ecircumflex => VirtualKeyCode::Ecircumflex, -// //ffi::XK_Ediaeresis => VirtualKeyCode::Ediaeresis, -// //ffi::XK_Igrave => VirtualKeyCode::Igrave, -// //ffi::XK_Iacute => VirtualKeyCode::Iacute, -// //ffi::XK_Icircumflex => VirtualKeyCode::Icircumflex, -// //ffi::XK_Idiaeresis => VirtualKeyCode::Idiaeresis, -// //ffi::XK_ETH => VirtualKeyCode::Eth, -// //ffi::XK_Eth => VirtualKeyCode::Eth, -// //ffi::XK_Ntilde => VirtualKeyCode::Ntilde, -// //ffi::XK_Ograve => VirtualKeyCode::Ograve, -// //ffi::XK_Oacute => VirtualKeyCode::Oacute, -// //ffi::XK_Ocircumflex => VirtualKeyCode::Ocircumflex, -// //ffi::XK_Otilde => VirtualKeyCode::Otilde, -// //ffi::XK_Odiaeresis => VirtualKeyCode::Odiaeresis, -// //ffi::XK_multiply => VirtualKeyCode::Multiply, -// //ffi::XK_Ooblique => VirtualKeyCode::Ooblique, -// //ffi::XK_Ugrave => VirtualKeyCode::Ugrave, -// //ffi::XK_Uacute => VirtualKeyCode::Uacute, -// //ffi::XK_Ucircumflex => VirtualKeyCode::Ucircumflex, -// //ffi::XK_Udiaeresis => VirtualKeyCode::Udiaeresis, -// //ffi::XK_Yacute => VirtualKeyCode::Yacute, -// //ffi::XK_THORN => VirtualKeyCode::Thorn, -// //ffi::XK_Thorn => VirtualKeyCode::Thorn, -// //ffi::XK_ssharp => VirtualKeyCode::Ssharp, -// //ffi::XK_agrave => VirtualKeyCode::Agrave, -// //ffi::XK_aacute => VirtualKeyCode::Aacute, -// //ffi::XK_acircumflex => VirtualKeyCode::Acircumflex, -// //ffi::XK_atilde => VirtualKeyCode::Atilde, -// //ffi::XK_adiaeresis => VirtualKeyCode::Adiaeresis, -// //ffi::XK_aring => VirtualKeyCode::Aring, -// //ffi::XK_ae => VirtualKeyCode::Ae, -// //ffi::XK_ccedilla => VirtualKeyCode::Ccedilla, -// //ffi::XK_egrave => VirtualKeyCode::Egrave, -// //ffi::XK_eacute => VirtualKeyCode::Eacute, -// //ffi::XK_ecircumflex => VirtualKeyCode::Ecircumflex, -// //ffi::XK_ediaeresis => VirtualKeyCode::Ediaeresis, -// //ffi::XK_igrave => VirtualKeyCode::Igrave, -// //ffi::XK_iacute => VirtualKeyCode::Iacute, -// //ffi::XK_icircumflex => VirtualKeyCode::Icircumflex, -// //ffi::XK_idiaeresis => VirtualKeyCode::Idiaeresis, -// //ffi::XK_eth => VirtualKeyCode::Eth, -// //ffi::XK_ntilde => VirtualKeyCode::Ntilde, -// //ffi::XK_ograve => VirtualKeyCode::Ograve, -// //ffi::XK_oacute => VirtualKeyCode::Oacute, -// //ffi::XK_ocircumflex => VirtualKeyCode::Ocircumflex, -// //ffi::XK_otilde => VirtualKeyCode::Otilde, -// //ffi::XK_odiaeresis => VirtualKeyCode::Odiaeresis, -// //ffi::XK_division => VirtualKeyCode::Division, -// //ffi::XK_oslash => VirtualKeyCode::Oslash, -// //ffi::XK_ugrave => VirtualKeyCode::Ugrave, -// //ffi::XK_uacute => VirtualKeyCode::Uacute, -// //ffi::XK_ucircumflex => VirtualKeyCode::Ucircumflex, -// //ffi::XK_udiaeresis => VirtualKeyCode::Udiaeresis, -// //ffi::XK_yacute => VirtualKeyCode::Yacute, -// //ffi::XK_thorn => VirtualKeyCode::Thorn, -// //ffi::XK_ydiaeresis => VirtualKeyCode::Ydiaeresis, -// //ffi::XK_Aogonek => VirtualKeyCode::Aogonek, -// //ffi::XK_breve => VirtualKeyCode::Breve, -// //ffi::XK_Lstroke => VirtualKeyCode::Lstroke, -// //ffi::XK_Lcaron => VirtualKeyCode::Lcaron, -// //ffi::XK_Sacute => VirtualKeyCode::Sacute, -// //ffi::XK_Scaron => VirtualKeyCode::Scaron, -// //ffi::XK_Scedilla => VirtualKeyCode::Scedilla, -// //ffi::XK_Tcaron => VirtualKeyCode::Tcaron, -// //ffi::XK_Zacute => VirtualKeyCode::Zacute, -// //ffi::XK_Zcaron => VirtualKeyCode::Zcaron, -// //ffi::XK_Zabovedot => VirtualKeyCode::Zabovedot, -// //ffi::XK_aogonek => VirtualKeyCode::Aogonek, -// //ffi::XK_ogonek => VirtualKeyCode::Ogonek, -// //ffi::XK_lstroke => VirtualKeyCode::Lstroke, -// //ffi::XK_lcaron => VirtualKeyCode::Lcaron, -// //ffi::XK_sacute => VirtualKeyCode::Sacute, -// //ffi::XK_caron => VirtualKeyCode::Caron, -// //ffi::XK_scaron => VirtualKeyCode::Scaron, -// //ffi::XK_scedilla => VirtualKeyCode::Scedilla, -// //ffi::XK_tcaron => VirtualKeyCode::Tcaron, -// //ffi::XK_zacute => VirtualKeyCode::Zacute, -// //ffi::XK_doubleacute => VirtualKeyCode::Doubleacute, -// //ffi::XK_zcaron => VirtualKeyCode::Zcaron, -// //ffi::XK_zabovedot => VirtualKeyCode::Zabovedot, -// //ffi::XK_Racute => VirtualKeyCode::Racute, -// //ffi::XK_Abreve => VirtualKeyCode::Abreve, -// //ffi::XK_Lacute => VirtualKeyCode::Lacute, -// //ffi::XK_Cacute => VirtualKeyCode::Cacute, -// //ffi::XK_Ccaron => VirtualKeyCode::Ccaron, -// //ffi::XK_Eogonek => VirtualKeyCode::Eogonek, -// //ffi::XK_Ecaron => VirtualKeyCode::Ecaron, -// //ffi::XK_Dcaron => VirtualKeyCode::Dcaron, -// //ffi::XK_Dstroke => VirtualKeyCode::Dstroke, -// //ffi::XK_Nacute => VirtualKeyCode::Nacute, -// //ffi::XK_Ncaron => VirtualKeyCode::Ncaron, -// //ffi::XK_Odoubleacute => VirtualKeyCode::Odoubleacute, -// //ffi::XK_Rcaron => VirtualKeyCode::Rcaron, -// //ffi::XK_Uring => VirtualKeyCode::Uring, -// //ffi::XK_Udoubleacute => VirtualKeyCode::Udoubleacute, -// //ffi::XK_Tcedilla => VirtualKeyCode::Tcedilla, -// //ffi::XK_racute => VirtualKeyCode::Racute, -// //ffi::XK_abreve => VirtualKeyCode::Abreve, -// //ffi::XK_lacute => VirtualKeyCode::Lacute, -// //ffi::XK_cacute => VirtualKeyCode::Cacute, -// //ffi::XK_ccaron => VirtualKeyCode::Ccaron, -// //ffi::XK_eogonek => VirtualKeyCode::Eogonek, -// //ffi::XK_ecaron => VirtualKeyCode::Ecaron, -// //ffi::XK_dcaron => VirtualKeyCode::Dcaron, -// //ffi::XK_dstroke => VirtualKeyCode::Dstroke, -// //ffi::XK_nacute => VirtualKeyCode::Nacute, -// //ffi::XK_ncaron => VirtualKeyCode::Ncaron, -// //ffi::XK_odoubleacute => VirtualKeyCode::Odoubleacute, -// //ffi::XK_udoubleacute => VirtualKeyCode::Udoubleacute, -// //ffi::XK_rcaron => VirtualKeyCode::Rcaron, -// //ffi::XK_uring => VirtualKeyCode::Uring, -// //ffi::XK_tcedilla => VirtualKeyCode::Tcedilla, -// //ffi::XK_abovedot => VirtualKeyCode::Abovedot, -// //ffi::XK_Hstroke => VirtualKeyCode::Hstroke, -// //ffi::XK_Hcircumflex => VirtualKeyCode::Hcircumflex, -// //ffi::XK_Iabovedot => VirtualKeyCode::Iabovedot, -// //ffi::XK_Gbreve => VirtualKeyCode::Gbreve, -// //ffi::XK_Jcircumflex => VirtualKeyCode::Jcircumflex, -// //ffi::XK_hstroke => VirtualKeyCode::Hstroke, -// //ffi::XK_hcircumflex => VirtualKeyCode::Hcircumflex, -// //ffi::XK_idotless => VirtualKeyCode::Idotless, -// //ffi::XK_gbreve => VirtualKeyCode::Gbreve, -// //ffi::XK_jcircumflex => VirtualKeyCode::Jcircumflex, -// //ffi::XK_Cabovedot => VirtualKeyCode::Cabovedot, -// //ffi::XK_Ccircumflex => VirtualKeyCode::Ccircumflex, -// //ffi::XK_Gabovedot => VirtualKeyCode::Gabovedot, -// //ffi::XK_Gcircumflex => VirtualKeyCode::Gcircumflex, -// //ffi::XK_Ubreve => VirtualKeyCode::Ubreve, -// //ffi::XK_Scircumflex => VirtualKeyCode::Scircumflex, -// //ffi::XK_cabovedot => VirtualKeyCode::Cabovedot, -// //ffi::XK_ccircumflex => VirtualKeyCode::Ccircumflex, -// //ffi::XK_gabovedot => VirtualKeyCode::Gabovedot, -// //ffi::XK_gcircumflex => VirtualKeyCode::Gcircumflex, -// //ffi::XK_ubreve => VirtualKeyCode::Ubreve, -// //ffi::XK_scircumflex => VirtualKeyCode::Scircumflex, -// //ffi::XK_kra => VirtualKeyCode::Kra, -// //ffi::XK_kappa => VirtualKeyCode::Kappa, -// //ffi::XK_Rcedilla => VirtualKeyCode::Rcedilla, -// //ffi::XK_Itilde => VirtualKeyCode::Itilde, -// //ffi::XK_Lcedilla => VirtualKeyCode::Lcedilla, -// //ffi::XK_Emacron => VirtualKeyCode::Emacron, -// //ffi::XK_Gcedilla => VirtualKeyCode::Gcedilla, -// //ffi::XK_Tslash => VirtualKeyCode::Tslash, -// //ffi::XK_rcedilla => VirtualKeyCode::Rcedilla, -// //ffi::XK_itilde => VirtualKeyCode::Itilde, -// //ffi::XK_lcedilla => VirtualKeyCode::Lcedilla, -// //ffi::XK_emacron => VirtualKeyCode::Emacron, -// //ffi::XK_gcedilla => VirtualKeyCode::Gcedilla, -// //ffi::XK_tslash => VirtualKeyCode::Tslash, -// //ffi::XK_ENG => VirtualKeyCode::Eng, -// //ffi::XK_eng => VirtualKeyCode::Eng, -// //ffi::XK_Amacron => VirtualKeyCode::Amacron, -// //ffi::XK_Iogonek => VirtualKeyCode::Iogonek, -// //ffi::XK_Eabovedot => VirtualKeyCode::Eabovedot, -// //ffi::XK_Imacron => VirtualKeyCode::Imacron, -// //ffi::XK_Ncedilla => VirtualKeyCode::Ncedilla, -// //ffi::XK_Omacron => VirtualKeyCode::Omacron, -// //ffi::XK_Kcedilla => VirtualKeyCode::Kcedilla, -// //ffi::XK_Uogonek => VirtualKeyCode::Uogonek, -// //ffi::XK_Utilde => VirtualKeyCode::Utilde, -// //ffi::XK_Umacron => VirtualKeyCode::Umacron, -// //ffi::XK_amacron => VirtualKeyCode::Amacron, -// //ffi::XK_iogonek => VirtualKeyCode::Iogonek, -// //ffi::XK_eabovedot => VirtualKeyCode::Eabovedot, -// //ffi::XK_imacron => VirtualKeyCode::Imacron, -// //ffi::XK_ncedilla => VirtualKeyCode::Ncedilla, -// //ffi::XK_omacron => VirtualKeyCode::Omacron, -// //ffi::XK_kcedilla => VirtualKeyCode::Kcedilla, -// //ffi::XK_uogonek => VirtualKeyCode::Uogonek, -// //ffi::XK_utilde => VirtualKeyCode::Utilde, -// //ffi::XK_umacron => VirtualKeyCode::Umacron, -// //ffi::XK_overline => VirtualKeyCode::Overline, -// //ffi::XK_kana_fullstop => VirtualKeyCode::Kana_fullstop, -// //ffi::XK_kana_openingbracket => VirtualKeyCode::Kana_openingbracket, -// //ffi::XK_kana_closingbracket => VirtualKeyCode::Kana_closingbracket, -// //ffi::XK_kana_comma => VirtualKeyCode::Kana_comma, -// //ffi::XK_kana_conjunctive => VirtualKeyCode::Kana_conjunctive, -// //ffi::XK_kana_middledot => VirtualKeyCode::Kana_middledot, -// //ffi::XK_kana_WO => VirtualKeyCode::Kana_wo, -// //ffi::XK_kana_a => VirtualKeyCode::Kana_a, -// //ffi::XK_kana_i => VirtualKeyCode::Kana_i, -// //ffi::XK_kana_u => VirtualKeyCode::Kana_u, -// //ffi::XK_kana_e => VirtualKeyCode::Kana_e, -// //ffi::XK_kana_o => VirtualKeyCode::Kana_o, -// //ffi::XK_kana_ya => VirtualKeyCode::Kana_ya, -// //ffi::XK_kana_yu => VirtualKeyCode::Kana_yu, -// //ffi::XK_kana_yo => VirtualKeyCode::Kana_yo, -// //ffi::XK_kana_tsu => VirtualKeyCode::Kana_tsu, -// //ffi::XK_kana_tu => VirtualKeyCode::Kana_tu, -// //ffi::XK_prolongedsound => VirtualKeyCode::Prolongedsound, -// //ffi::XK_kana_A => VirtualKeyCode::Kana_a, -// //ffi::XK_kana_I => VirtualKeyCode::Kana_i, -// //ffi::XK_kana_U => VirtualKeyCode::Kana_u, -// //ffi::XK_kana_E => VirtualKeyCode::Kana_e, -// //ffi::XK_kana_O => VirtualKeyCode::Kana_o, -// //ffi::XK_kana_KA => VirtualKeyCode::Kana_ka, -// //ffi::XK_kana_KI => VirtualKeyCode::Kana_ki, -// //ffi::XK_kana_KU => VirtualKeyCode::Kana_ku, -// //ffi::XK_kana_KE => VirtualKeyCode::Kana_ke, -// //ffi::XK_kana_KO => VirtualKeyCode::Kana_ko, -// //ffi::XK_kana_SA => VirtualKeyCode::Kana_sa, -// //ffi::XK_kana_SHI => VirtualKeyCode::Kana_shi, -// //ffi::XK_kana_SU => VirtualKeyCode::Kana_su, -// //ffi::XK_kana_SE => VirtualKeyCode::Kana_se, -// //ffi::XK_kana_SO => VirtualKeyCode::Kana_so, -// //ffi::XK_kana_TA => VirtualKeyCode::Kana_ta, -// //ffi::XK_kana_CHI => VirtualKeyCode::Kana_chi, -// //ffi::XK_kana_TI => VirtualKeyCode::Kana_ti, -// //ffi::XK_kana_TSU => VirtualKeyCode::Kana_tsu, -// //ffi::XK_kana_TU => VirtualKeyCode::Kana_tu, -// //ffi::XK_kana_TE => VirtualKeyCode::Kana_te, -// //ffi::XK_kana_TO => VirtualKeyCode::Kana_to, -// //ffi::XK_kana_NA => VirtualKeyCode::Kana_na, -// //ffi::XK_kana_NI => VirtualKeyCode::Kana_ni, -// //ffi::XK_kana_NU => VirtualKeyCode::Kana_nu, -// //ffi::XK_kana_NE => VirtualKeyCode::Kana_ne, -// //ffi::XK_kana_NO => VirtualKeyCode::Kana_no, -// //ffi::XK_kana_HA => VirtualKeyCode::Kana_ha, -// //ffi::XK_kana_HI => VirtualKeyCode::Kana_hi, -// //ffi::XK_kana_FU => VirtualKeyCode::Kana_fu, -// //ffi::XK_kana_HU => VirtualKeyCode::Kana_hu, -// //ffi::XK_kana_HE => VirtualKeyCode::Kana_he, -// //ffi::XK_kana_HO => VirtualKeyCode::Kana_ho, -// //ffi::XK_kana_MA => VirtualKeyCode::Kana_ma, -// //ffi::XK_kana_MI => VirtualKeyCode::Kana_mi, -// //ffi::XK_kana_MU => VirtualKeyCode::Kana_mu, -// //ffi::XK_kana_ME => VirtualKeyCode::Kana_me, -// //ffi::XK_kana_MO => VirtualKeyCode::Kana_mo, -// //ffi::XK_kana_YA => VirtualKeyCode::Kana_ya, -// //ffi::XK_kana_YU => VirtualKeyCode::Kana_yu, -// //ffi::XK_kana_YO => VirtualKeyCode::Kana_yo, -// //ffi::XK_kana_RA => VirtualKeyCode::Kana_ra, -// //ffi::XK_kana_RI => VirtualKeyCode::Kana_ri, -// //ffi::XK_kana_RU => VirtualKeyCode::Kana_ru, -// //ffi::XK_kana_RE => VirtualKeyCode::Kana_re, -// //ffi::XK_kana_RO => VirtualKeyCode::Kana_ro, -// //ffi::XK_kana_WA => VirtualKeyCode::Kana_wa, -// //ffi::XK_kana_N => VirtualKeyCode::Kana_n, -// //ffi::XK_voicedsound => VirtualKeyCode::Voicedsound, -// //ffi::XK_semivoicedsound => VirtualKeyCode::Semivoicedsound, -// //ffi::XK_kana_switch => VirtualKeyCode::Kana_switch, -// //ffi::XK_Arabic_comma => VirtualKeyCode::Arabic_comma, -// //ffi::XK_Arabic_semicolon => VirtualKeyCode::Arabic_semicolon, -// //ffi::XK_Arabic_question_mark => VirtualKeyCode::Arabic_question_mark, -// //ffi::XK_Arabic_hamza => VirtualKeyCode::Arabic_hamza, -// //ffi::XK_Arabic_maddaonalef => VirtualKeyCode::Arabic_maddaonalef, -// //ffi::XK_Arabic_hamzaonalef => VirtualKeyCode::Arabic_hamzaonalef, -// //ffi::XK_Arabic_hamzaonwaw => VirtualKeyCode::Arabic_hamzaonwaw, -// //ffi::XK_Arabic_hamzaunderalef => VirtualKeyCode::Arabic_hamzaunderalef, -// //ffi::XK_Arabic_hamzaonyeh => VirtualKeyCode::Arabic_hamzaonyeh, -// //ffi::XK_Arabic_alef => VirtualKeyCode::Arabic_alef, -// //ffi::XK_Arabic_beh => VirtualKeyCode::Arabic_beh, -// //ffi::XK_Arabic_tehmarbuta => VirtualKeyCode::Arabic_tehmarbuta, -// //ffi::XK_Arabic_teh => VirtualKeyCode::Arabic_teh, -// //ffi::XK_Arabic_theh => VirtualKeyCode::Arabic_theh, -// //ffi::XK_Arabic_jeem => VirtualKeyCode::Arabic_jeem, -// //ffi::XK_Arabic_hah => VirtualKeyCode::Arabic_hah, -// //ffi::XK_Arabic_khah => VirtualKeyCode::Arabic_khah, -// //ffi::XK_Arabic_dal => VirtualKeyCode::Arabic_dal, -// //ffi::XK_Arabic_thal => VirtualKeyCode::Arabic_thal, -// //ffi::XK_Arabic_ra => VirtualKeyCode::Arabic_ra, -// //ffi::XK_Arabic_zain => VirtualKeyCode::Arabic_zain, -// //ffi::XK_Arabic_seen => VirtualKeyCode::Arabic_seen, -// //ffi::XK_Arabic_sheen => VirtualKeyCode::Arabic_sheen, -// //ffi::XK_Arabic_sad => VirtualKeyCode::Arabic_sad, -// //ffi::XK_Arabic_dad => VirtualKeyCode::Arabic_dad, -// //ffi::XK_Arabic_tah => VirtualKeyCode::Arabic_tah, -// //ffi::XK_Arabic_zah => VirtualKeyCode::Arabic_zah, -// //ffi::XK_Arabic_ain => VirtualKeyCode::Arabic_ain, -// //ffi::XK_Arabic_ghain => VirtualKeyCode::Arabic_ghain, -// //ffi::XK_Arabic_tatweel => VirtualKeyCode::Arabic_tatweel, -// //ffi::XK_Arabic_feh => VirtualKeyCode::Arabic_feh, -// //ffi::XK_Arabic_qaf => VirtualKeyCode::Arabic_qaf, -// //ffi::XK_Arabic_kaf => VirtualKeyCode::Arabic_kaf, -// //ffi::XK_Arabic_lam => VirtualKeyCode::Arabic_lam, -// //ffi::XK_Arabic_meem => VirtualKeyCode::Arabic_meem, -// //ffi::XK_Arabic_noon => VirtualKeyCode::Arabic_noon, -// //ffi::XK_Arabic_ha => VirtualKeyCode::Arabic_ha, -// //ffi::XK_Arabic_heh => VirtualKeyCode::Arabic_heh, -// //ffi::XK_Arabic_waw => VirtualKeyCode::Arabic_waw, -// //ffi::XK_Arabic_alefmaksura => VirtualKeyCode::Arabic_alefmaksura, -// //ffi::XK_Arabic_yeh => VirtualKeyCode::Arabic_yeh, -// //ffi::XK_Arabic_fathatan => VirtualKeyCode::Arabic_fathatan, -// //ffi::XK_Arabic_dammatan => VirtualKeyCode::Arabic_dammatan, -// //ffi::XK_Arabic_kasratan => VirtualKeyCode::Arabic_kasratan, -// //ffi::XK_Arabic_fatha => VirtualKeyCode::Arabic_fatha, -// //ffi::XK_Arabic_damma => VirtualKeyCode::Arabic_damma, -// //ffi::XK_Arabic_kasra => VirtualKeyCode::Arabic_kasra, -// //ffi::XK_Arabic_shadda => VirtualKeyCode::Arabic_shadda, -// //ffi::XK_Arabic_sukun => VirtualKeyCode::Arabic_sukun, -// //ffi::XK_Arabic_switch => VirtualKeyCode::Arabic_switch, -// //ffi::XK_Serbian_dje => VirtualKeyCode::Serbian_dje, -// //ffi::XK_Macedonia_gje => VirtualKeyCode::Macedonia_gje, -// //ffi::XK_Cyrillic_io => VirtualKeyCode::Cyrillic_io, -// //ffi::XK_Ukrainian_ie => VirtualKeyCode::Ukrainian_ie, -// //ffi::XK_Ukranian_je => VirtualKeyCode::Ukranian_je, -// //ffi::XK_Macedonia_dse => VirtualKeyCode::Macedonia_dse, -// //ffi::XK_Ukrainian_i => VirtualKeyCode::Ukrainian_i, -// //ffi::XK_Ukranian_i => VirtualKeyCode::Ukranian_i, -// //ffi::XK_Ukrainian_yi => VirtualKeyCode::Ukrainian_yi, -// //ffi::XK_Ukranian_yi => VirtualKeyCode::Ukranian_yi, -// //ffi::XK_Cyrillic_je => VirtualKeyCode::Cyrillic_je, -// //ffi::XK_Serbian_je => VirtualKeyCode::Serbian_je, -// //ffi::XK_Cyrillic_lje => VirtualKeyCode::Cyrillic_lje, -// //ffi::XK_Serbian_lje => VirtualKeyCode::Serbian_lje, -// //ffi::XK_Cyrillic_nje => VirtualKeyCode::Cyrillic_nje, -// //ffi::XK_Serbian_nje => VirtualKeyCode::Serbian_nje, -// //ffi::XK_Serbian_tshe => VirtualKeyCode::Serbian_tshe, -// //ffi::XK_Macedonia_kje => VirtualKeyCode::Macedonia_kje, -// //ffi::XK_Byelorussian_shortu => VirtualKeyCode::Byelorussian_shortu, -// //ffi::XK_Cyrillic_dzhe => VirtualKeyCode::Cyrillic_dzhe, -// //ffi::XK_Serbian_dze => VirtualKeyCode::Serbian_dze, -// //ffi::XK_numerosign => VirtualKeyCode::Numerosign, -// //ffi::XK_Serbian_DJE => VirtualKeyCode::Serbian_dje, -// //ffi::XK_Macedonia_GJE => VirtualKeyCode::Macedonia_gje, -// //ffi::XK_Cyrillic_IO => VirtualKeyCode::Cyrillic_io, -// //ffi::XK_Ukrainian_IE => VirtualKeyCode::Ukrainian_ie, -// //ffi::XK_Ukranian_JE => VirtualKeyCode::Ukranian_je, -// //ffi::XK_Macedonia_DSE => VirtualKeyCode::Macedonia_dse, -// //ffi::XK_Ukrainian_I => VirtualKeyCode::Ukrainian_i, -// //ffi::XK_Ukranian_I => VirtualKeyCode::Ukranian_i, -// //ffi::XK_Ukrainian_YI => VirtualKeyCode::Ukrainian_yi, -// //ffi::XK_Ukranian_YI => VirtualKeyCode::Ukranian_yi, -// //ffi::XK_Cyrillic_JE => VirtualKeyCode::Cyrillic_je, -// //ffi::XK_Serbian_JE => VirtualKeyCode::Serbian_je, -// //ffi::XK_Cyrillic_LJE => VirtualKeyCode::Cyrillic_lje, -// //ffi::XK_Serbian_LJE => VirtualKeyCode::Serbian_lje, -// //ffi::XK_Cyrillic_NJE => VirtualKeyCode::Cyrillic_nje, -// //ffi::XK_Serbian_NJE => VirtualKeyCode::Serbian_nje, -// //ffi::XK_Serbian_TSHE => VirtualKeyCode::Serbian_tshe, -// //ffi::XK_Macedonia_KJE => VirtualKeyCode::Macedonia_kje, -// //ffi::XK_Byelorussian_SHORTU => VirtualKeyCode::Byelorussian_shortu, -// //ffi::XK_Cyrillic_DZHE => VirtualKeyCode::Cyrillic_dzhe, -// //ffi::XK_Serbian_DZE => VirtualKeyCode::Serbian_dze, -// //ffi::XK_Cyrillic_yu => VirtualKeyCode::Cyrillic_yu, -// //ffi::XK_Cyrillic_a => VirtualKeyCode::Cyrillic_a, -// //ffi::XK_Cyrillic_be => VirtualKeyCode::Cyrillic_be, -// //ffi::XK_Cyrillic_tse => VirtualKeyCode::Cyrillic_tse, -// //ffi::XK_Cyrillic_de => VirtualKeyCode::Cyrillic_de, -// //ffi::XK_Cyrillic_ie => VirtualKeyCode::Cyrillic_ie, -// //ffi::XK_Cyrillic_ef => VirtualKeyCode::Cyrillic_ef, -// //ffi::XK_Cyrillic_ghe => VirtualKeyCode::Cyrillic_ghe, -// //ffi::XK_Cyrillic_ha => VirtualKeyCode::Cyrillic_ha, -// //ffi::XK_Cyrillic_i => VirtualKeyCode::Cyrillic_i, -// //ffi::XK_Cyrillic_shorti => VirtualKeyCode::Cyrillic_shorti, -// //ffi::XK_Cyrillic_ka => VirtualKeyCode::Cyrillic_ka, -// //ffi::XK_Cyrillic_el => VirtualKeyCode::Cyrillic_el, -// //ffi::XK_Cyrillic_em => VirtualKeyCode::Cyrillic_em, -// //ffi::XK_Cyrillic_en => VirtualKeyCode::Cyrillic_en, -// //ffi::XK_Cyrillic_o => VirtualKeyCode::Cyrillic_o, -// //ffi::XK_Cyrillic_pe => VirtualKeyCode::Cyrillic_pe, -// //ffi::XK_Cyrillic_ya => VirtualKeyCode::Cyrillic_ya, -// //ffi::XK_Cyrillic_er => VirtualKeyCode::Cyrillic_er, -// //ffi::XK_Cyrillic_es => VirtualKeyCode::Cyrillic_es, -// //ffi::XK_Cyrillic_te => VirtualKeyCode::Cyrillic_te, -// //ffi::XK_Cyrillic_u => VirtualKeyCode::Cyrillic_u, -// //ffi::XK_Cyrillic_zhe => VirtualKeyCode::Cyrillic_zhe, -// //ffi::XK_Cyrillic_ve => VirtualKeyCode::Cyrillic_ve, -// //ffi::XK_Cyrillic_softsign => VirtualKeyCode::Cyrillic_softsign, -// //ffi::XK_Cyrillic_yeru => VirtualKeyCode::Cyrillic_yeru, -// //ffi::XK_Cyrillic_ze => VirtualKeyCode::Cyrillic_ze, -// //ffi::XK_Cyrillic_sha => VirtualKeyCode::Cyrillic_sha, -// //ffi::XK_Cyrillic_e => VirtualKeyCode::Cyrillic_e, -// //ffi::XK_Cyrillic_shcha => VirtualKeyCode::Cyrillic_shcha, -// //ffi::XK_Cyrillic_che => VirtualKeyCode::Cyrillic_che, -// //ffi::XK_Cyrillic_hardsign => VirtualKeyCode::Cyrillic_hardsign, -// //ffi::XK_Cyrillic_YU => VirtualKeyCode::Cyrillic_yu, -// //ffi::XK_Cyrillic_A => VirtualKeyCode::Cyrillic_a, -// //ffi::XK_Cyrillic_BE => VirtualKeyCode::Cyrillic_be, -// //ffi::XK_Cyrillic_TSE => VirtualKeyCode::Cyrillic_tse, -// //ffi::XK_Cyrillic_DE => VirtualKeyCode::Cyrillic_de, -// //ffi::XK_Cyrillic_IE => VirtualKeyCode::Cyrillic_ie, -// //ffi::XK_Cyrillic_EF => VirtualKeyCode::Cyrillic_ef, -// //ffi::XK_Cyrillic_GHE => VirtualKeyCode::Cyrillic_ghe, -// //ffi::XK_Cyrillic_HA => VirtualKeyCode::Cyrillic_ha, -// //ffi::XK_Cyrillic_I => VirtualKeyCode::Cyrillic_i, -// //ffi::XK_Cyrillic_SHORTI => VirtualKeyCode::Cyrillic_shorti, -// //ffi::XK_Cyrillic_KA => VirtualKeyCode::Cyrillic_ka, -// //ffi::XK_Cyrillic_EL => VirtualKeyCode::Cyrillic_el, -// //ffi::XK_Cyrillic_EM => VirtualKeyCode::Cyrillic_em, -// //ffi::XK_Cyrillic_EN => VirtualKeyCode::Cyrillic_en, -// //ffi::XK_Cyrillic_O => VirtualKeyCode::Cyrillic_o, -// //ffi::XK_Cyrillic_PE => VirtualKeyCode::Cyrillic_pe, -// //ffi::XK_Cyrillic_YA => VirtualKeyCode::Cyrillic_ya, -// //ffi::XK_Cyrillic_ER => VirtualKeyCode::Cyrillic_er, -// //ffi::XK_Cyrillic_ES => VirtualKeyCode::Cyrillic_es, -// //ffi::XK_Cyrillic_TE => VirtualKeyCode::Cyrillic_te, -// //ffi::XK_Cyrillic_U => VirtualKeyCode::Cyrillic_u, -// //ffi::XK_Cyrillic_ZHE => VirtualKeyCode::Cyrillic_zhe, -// //ffi::XK_Cyrillic_VE => VirtualKeyCode::Cyrillic_ve, -// //ffi::XK_Cyrillic_SOFTSIGN => VirtualKeyCode::Cyrillic_softsign, -// //ffi::XK_Cyrillic_YERU => VirtualKeyCode::Cyrillic_yeru, -// //ffi::XK_Cyrillic_ZE => VirtualKeyCode::Cyrillic_ze, -// //ffi::XK_Cyrillic_SHA => VirtualKeyCode::Cyrillic_sha, -// //ffi::XK_Cyrillic_E => VirtualKeyCode::Cyrillic_e, -// //ffi::XK_Cyrillic_SHCHA => VirtualKeyCode::Cyrillic_shcha, -// //ffi::XK_Cyrillic_CHE => VirtualKeyCode::Cyrillic_che, -// //ffi::XK_Cyrillic_HARDSIGN => VirtualKeyCode::Cyrillic_hardsign, -// //ffi::XK_Greek_ALPHAaccent => VirtualKeyCode::Greek_alphaaccent, -// //ffi::XK_Greek_EPSILONaccent => VirtualKeyCode::Greek_epsilonaccent, -// //ffi::XK_Greek_ETAaccent => VirtualKeyCode::Greek_etaaccent, -// //ffi::XK_Greek_IOTAaccent => VirtualKeyCode::Greek_iotaaccent, -// //ffi::XK_Greek_IOTAdiaeresis => VirtualKeyCode::Greek_iotadiaeresis, -// //ffi::XK_Greek_OMICRONaccent => VirtualKeyCode::Greek_omicronaccent, -// //ffi::XK_Greek_UPSILONaccent => VirtualKeyCode::Greek_upsilonaccent, -// //ffi::XK_Greek_UPSILONdieresis => VirtualKeyCode::Greek_upsilondieresis, -// //ffi::XK_Greek_OMEGAaccent => VirtualKeyCode::Greek_omegaaccent, -// //ffi::XK_Greek_accentdieresis => VirtualKeyCode::Greek_accentdieresis, -// //ffi::XK_Greek_horizbar => VirtualKeyCode::Greek_horizbar, -// //ffi::XK_Greek_alphaaccent => VirtualKeyCode::Greek_alphaaccent, -// //ffi::XK_Greek_epsilonaccent => VirtualKeyCode::Greek_epsilonaccent, -// //ffi::XK_Greek_etaaccent => VirtualKeyCode::Greek_etaaccent, -// //ffi::XK_Greek_iotaaccent => VirtualKeyCode::Greek_iotaaccent, -// //ffi::XK_Greek_iotadieresis => VirtualKeyCode::Greek_iotadieresis, -// //ffi::XK_Greek_iotaaccentdieresis => VirtualKeyCode::Greek_iotaaccentdieresis, -// //ffi::XK_Greek_omicronaccent => VirtualKeyCode::Greek_omicronaccent, -// //ffi::XK_Greek_upsilonaccent => VirtualKeyCode::Greek_upsilonaccent, -// //ffi::XK_Greek_upsilondieresis => VirtualKeyCode::Greek_upsilondieresis, -// //ffi::XK_Greek_upsilonaccentdieresis => VirtualKeyCode::Greek_upsilonaccentdieresis, -// //ffi::XK_Greek_omegaaccent => VirtualKeyCode::Greek_omegaaccent, -// //ffi::XK_Greek_ALPHA => VirtualKeyCode::Greek_alpha, -// //ffi::XK_Greek_BETA => VirtualKeyCode::Greek_beta, -// //ffi::XK_Greek_GAMMA => VirtualKeyCode::Greek_gamma, -// //ffi::XK_Greek_DELTA => VirtualKeyCode::Greek_delta, -// //ffi::XK_Greek_EPSILON => VirtualKeyCode::Greek_epsilon, -// //ffi::XK_Greek_ZETA => VirtualKeyCode::Greek_zeta, -// //ffi::XK_Greek_ETA => VirtualKeyCode::Greek_eta, -// //ffi::XK_Greek_THETA => VirtualKeyCode::Greek_theta, -// //ffi::XK_Greek_IOTA => VirtualKeyCode::Greek_iota, -// //ffi::XK_Greek_KAPPA => VirtualKeyCode::Greek_kappa, -// //ffi::XK_Greek_LAMDA => VirtualKeyCode::Greek_lamda, -// //ffi::XK_Greek_LAMBDA => VirtualKeyCode::Greek_lambda, -// //ffi::XK_Greek_MU => VirtualKeyCode::Greek_mu, -// //ffi::XK_Greek_NU => VirtualKeyCode::Greek_nu, -// //ffi::XK_Greek_XI => VirtualKeyCode::Greek_xi, -// //ffi::XK_Greek_OMICRON => VirtualKeyCode::Greek_omicron, -// //ffi::XK_Greek_PI => VirtualKeyCode::Greek_pi, -// //ffi::XK_Greek_RHO => VirtualKeyCode::Greek_rho, -// //ffi::XK_Greek_SIGMA => VirtualKeyCode::Greek_sigma, -// //ffi::XK_Greek_TAU => VirtualKeyCode::Greek_tau, -// //ffi::XK_Greek_UPSILON => VirtualKeyCode::Greek_upsilon, -// //ffi::XK_Greek_PHI => VirtualKeyCode::Greek_phi, -// //ffi::XK_Greek_CHI => VirtualKeyCode::Greek_chi, -// //ffi::XK_Greek_PSI => VirtualKeyCode::Greek_psi, -// //ffi::XK_Greek_OMEGA => VirtualKeyCode::Greek_omega, -// //ffi::XK_Greek_alpha => VirtualKeyCode::Greek_alpha, -// //ffi::XK_Greek_beta => VirtualKeyCode::Greek_beta, -// //ffi::XK_Greek_gamma => VirtualKeyCode::Greek_gamma, -// //ffi::XK_Greek_delta => VirtualKeyCode::Greek_delta, -// //ffi::XK_Greek_epsilon => VirtualKeyCode::Greek_epsilon, -// //ffi::XK_Greek_zeta => VirtualKeyCode::Greek_zeta, -// //ffi::XK_Greek_eta => VirtualKeyCode::Greek_eta, -// //ffi::XK_Greek_theta => VirtualKeyCode::Greek_theta, -// //ffi::XK_Greek_iota => VirtualKeyCode::Greek_iota, -// //ffi::XK_Greek_kappa => VirtualKeyCode::Greek_kappa, -// //ffi::XK_Greek_lamda => VirtualKeyCode::Greek_lamda, -// //ffi::XK_Greek_lambda => VirtualKeyCode::Greek_lambda, -// //ffi::XK_Greek_mu => VirtualKeyCode::Greek_mu, -// //ffi::XK_Greek_nu => VirtualKeyCode::Greek_nu, -// //ffi::XK_Greek_xi => VirtualKeyCode::Greek_xi, -// //ffi::XK_Greek_omicron => VirtualKeyCode::Greek_omicron, -// //ffi::XK_Greek_pi => VirtualKeyCode::Greek_pi, -// //ffi::XK_Greek_rho => VirtualKeyCode::Greek_rho, -// //ffi::XK_Greek_sigma => VirtualKeyCode::Greek_sigma, -// //ffi::XK_Greek_finalsmallsigma => VirtualKeyCode::Greek_finalsmallsigma, -// //ffi::XK_Greek_tau => VirtualKeyCode::Greek_tau, -// //ffi::XK_Greek_upsilon => VirtualKeyCode::Greek_upsilon, -// //ffi::XK_Greek_phi => VirtualKeyCode::Greek_phi, -// //ffi::XK_Greek_chi => VirtualKeyCode::Greek_chi, -// //ffi::XK_Greek_psi => VirtualKeyCode::Greek_psi, -// //ffi::XK_Greek_omega => VirtualKeyCode::Greek_omega, -// //ffi::XK_Greek_switch => VirtualKeyCode::Greek_switch, -// //ffi::XK_leftradical => VirtualKeyCode::Leftradical, -// //ffi::XK_topleftradical => VirtualKeyCode::Topleftradical, -// //ffi::XK_horizconnector => VirtualKeyCode::Horizconnector, -// //ffi::XK_topintegral => VirtualKeyCode::Topintegral, -// //ffi::XK_botintegral => VirtualKeyCode::Botintegral, -// //ffi::XK_vertconnector => VirtualKeyCode::Vertconnector, -// //ffi::XK_topleftsqbracket => VirtualKeyCode::Topleftsqbracket, -// //ffi::XK_botleftsqbracket => VirtualKeyCode::Botleftsqbracket, -// //ffi::XK_toprightsqbracket => VirtualKeyCode::Toprightsqbracket, -// //ffi::XK_botrightsqbracket => VirtualKeyCode::Botrightsqbracket, -// //ffi::XK_topleftparens => VirtualKeyCode::Topleftparens, -// //ffi::XK_botleftparens => VirtualKeyCode::Botleftparens, -// //ffi::XK_toprightparens => VirtualKeyCode::Toprightparens, -// //ffi::XK_botrightparens => VirtualKeyCode::Botrightparens, -// //ffi::XK_leftmiddlecurlybrace => VirtualKeyCode::Leftmiddlecurlybrace, -// //ffi::XK_rightmiddlecurlybrace => VirtualKeyCode::Rightmiddlecurlybrace, -// //ffi::XK_topleftsummation => VirtualKeyCode::Topleftsummation, -// //ffi::XK_botleftsummation => VirtualKeyCode::Botleftsummation, -// //ffi::XK_topvertsummationconnector => VirtualKeyCode::Topvertsummationconnector, -// //ffi::XK_botvertsummationconnector => VirtualKeyCode::Botvertsummationconnector, -// //ffi::XK_toprightsummation => VirtualKeyCode::Toprightsummation, -// //ffi::XK_botrightsummation => VirtualKeyCode::Botrightsummation, -// //ffi::XK_rightmiddlesummation => VirtualKeyCode::Rightmiddlesummation, -// //ffi::XK_lessthanequal => VirtualKeyCode::Lessthanequal, -// //ffi::XK_notequal => VirtualKeyCode::Notequal, -// //ffi::XK_greaterthanequal => VirtualKeyCode::Greaterthanequal, -// //ffi::XK_integral => VirtualKeyCode::Integral, -// //ffi::XK_therefore => VirtualKeyCode::Therefore, -// //ffi::XK_variation => VirtualKeyCode::Variation, -// //ffi::XK_infinity => VirtualKeyCode::Infinity, -// //ffi::XK_nabla => VirtualKeyCode::Nabla, -// //ffi::XK_approximate => VirtualKeyCode::Approximate, -// //ffi::XK_similarequal => VirtualKeyCode::Similarequal, -// //ffi::XK_ifonlyif => VirtualKeyCode::Ifonlyif, -// //ffi::XK_implies => VirtualKeyCode::Implies, -// //ffi::XK_identical => VirtualKeyCode::Identical, -// //ffi::XK_radical => VirtualKeyCode::Radical, -// //ffi::XK_includedin => VirtualKeyCode::Includedin, -// //ffi::XK_includes => VirtualKeyCode::Includes, -// //ffi::XK_intersection => VirtualKeyCode::Intersection, -// //ffi::XK_union => VirtualKeyCode::Union, -// //ffi::XK_logicaland => VirtualKeyCode::Logicaland, -// //ffi::XK_logicalor => VirtualKeyCode::Logicalor, -// //ffi::XK_partialderivative => VirtualKeyCode::Partialderivative, -// //ffi::XK_function => VirtualKeyCode::Function, -// //ffi::XK_leftarrow => VirtualKeyCode::Leftarrow, -// //ffi::XK_uparrow => VirtualKeyCode::Uparrow, -// //ffi::XK_rightarrow => VirtualKeyCode::Rightarrow, -// //ffi::XK_downarrow => VirtualKeyCode::Downarrow, -// //ffi::XK_blank => VirtualKeyCode::Blank, -// //ffi::XK_soliddiamond => VirtualKeyCode::Soliddiamond, -// //ffi::XK_checkerboard => VirtualKeyCode::Checkerboard, -// //ffi::XK_ht => VirtualKeyCode::Ht, -// //ffi::XK_ff => VirtualKeyCode::Ff, -// //ffi::XK_cr => VirtualKeyCode::Cr, -// //ffi::XK_lf => VirtualKeyCode::Lf, -// //ffi::XK_nl => VirtualKeyCode::Nl, -// //ffi::XK_vt => VirtualKeyCode::Vt, -// //ffi::XK_lowrightcorner => VirtualKeyCode::Lowrightcorner, -// //ffi::XK_uprightcorner => VirtualKeyCode::Uprightcorner, -// //ffi::XK_upleftcorner => VirtualKeyCode::Upleftcorner, -// //ffi::XK_lowleftcorner => VirtualKeyCode::Lowleftcorner, -// //ffi::XK_crossinglines => VirtualKeyCode::Crossinglines, -// //ffi::XK_horizlinescan1 => VirtualKeyCode::Horizlinescan1, -// //ffi::XK_horizlinescan3 => VirtualKeyCode::Horizlinescan3, -// //ffi::XK_horizlinescan5 => VirtualKeyCode::Horizlinescan5, -// //ffi::XK_horizlinescan7 => VirtualKeyCode::Horizlinescan7, -// //ffi::XK_horizlinescan9 => VirtualKeyCode::Horizlinescan9, -// //ffi::XK_leftt => VirtualKeyCode::Leftt, -// //ffi::XK_rightt => VirtualKeyCode::Rightt, -// //ffi::XK_bott => VirtualKeyCode::Bott, -// //ffi::XK_topt => VirtualKeyCode::Topt, -// //ffi::XK_vertbar => VirtualKeyCode::Vertbar, -// //ffi::XK_emspace => VirtualKeyCode::Emspace, -// //ffi::XK_enspace => VirtualKeyCode::Enspace, -// //ffi::XK_em3space => VirtualKeyCode::Em3space, -// //ffi::XK_em4space => VirtualKeyCode::Em4space, -// //ffi::XK_digitspace => VirtualKeyCode::Digitspace, -// //ffi::XK_punctspace => VirtualKeyCode::Punctspace, -// //ffi::XK_thinspace => VirtualKeyCode::Thinspace, -// //ffi::XK_hairspace => VirtualKeyCode::Hairspace, -// //ffi::XK_emdash => VirtualKeyCode::Emdash, -// //ffi::XK_endash => VirtualKeyCode::Endash, -// //ffi::XK_signifblank => VirtualKeyCode::Signifblank, -// //ffi::XK_ellipsis => VirtualKeyCode::Ellipsis, -// //ffi::XK_doubbaselinedot => VirtualKeyCode::Doubbaselinedot, -// //ffi::XK_onethird => VirtualKeyCode::Onethird, -// //ffi::XK_twothirds => VirtualKeyCode::Twothirds, -// //ffi::XK_onefifth => VirtualKeyCode::Onefifth, -// //ffi::XK_twofifths => VirtualKeyCode::Twofifths, -// //ffi::XK_threefifths => VirtualKeyCode::Threefifths, -// //ffi::XK_fourfifths => VirtualKeyCode::Fourfifths, -// //ffi::XK_onesixth => VirtualKeyCode::Onesixth, -// //ffi::XK_fivesixths => VirtualKeyCode::Fivesixths, -// //ffi::XK_careof => VirtualKeyCode::Careof, -// //ffi::XK_figdash => VirtualKeyCode::Figdash, -// //ffi::XK_leftanglebracket => VirtualKeyCode::Leftanglebracket, -// //ffi::XK_decimalpoint => VirtualKeyCode::Decimalpoint, -// //ffi::XK_rightanglebracket => VirtualKeyCode::Rightanglebracket, -// //ffi::XK_marker => VirtualKeyCode::Marker, -// //ffi::XK_oneeighth => VirtualKeyCode::Oneeighth, -// //ffi::XK_threeeighths => VirtualKeyCode::Threeeighths, -// //ffi::XK_fiveeighths => VirtualKeyCode::Fiveeighths, -// //ffi::XK_seveneighths => VirtualKeyCode::Seveneighths, -// //ffi::XK_trademark => VirtualKeyCode::Trademark, -// //ffi::XK_signaturemark => VirtualKeyCode::Signaturemark, -// //ffi::XK_trademarkincircle => VirtualKeyCode::Trademarkincircle, -// //ffi::XK_leftopentriangle => VirtualKeyCode::Leftopentriangle, -// //ffi::XK_rightopentriangle => VirtualKeyCode::Rightopentriangle, -// //ffi::XK_emopencircle => VirtualKeyCode::Emopencircle, -// //ffi::XK_emopenrectangle => VirtualKeyCode::Emopenrectangle, -// //ffi::XK_leftsinglequotemark => VirtualKeyCode::Leftsinglequotemark, -// //ffi::XK_rightsinglequotemark => VirtualKeyCode::Rightsinglequotemark, -// //ffi::XK_leftdoublequotemark => VirtualKeyCode::Leftdoublequotemark, -// //ffi::XK_rightdoublequotemark => VirtualKeyCode::Rightdoublequotemark, -// //ffi::XK_prescription => VirtualKeyCode::Prescription, -// //ffi::XK_minutes => VirtualKeyCode::Minutes, -// //ffi::XK_seconds => VirtualKeyCode::Seconds, -// //ffi::XK_latincross => VirtualKeyCode::Latincross, -// //ffi::XK_hexagram => VirtualKeyCode::Hexagram, -// //ffi::XK_filledrectbullet => VirtualKeyCode::Filledrectbullet, -// //ffi::XK_filledlefttribullet => VirtualKeyCode::Filledlefttribullet, -// //ffi::XK_filledrighttribullet => VirtualKeyCode::Filledrighttribullet, -// //ffi::XK_emfilledcircle => VirtualKeyCode::Emfilledcircle, -// //ffi::XK_emfilledrect => VirtualKeyCode::Emfilledrect, -// //ffi::XK_enopencircbullet => VirtualKeyCode::Enopencircbullet, -// //ffi::XK_enopensquarebullet => VirtualKeyCode::Enopensquarebullet, -// //ffi::XK_openrectbullet => VirtualKeyCode::Openrectbullet, -// //ffi::XK_opentribulletup => VirtualKeyCode::Opentribulletup, -// //ffi::XK_opentribulletdown => VirtualKeyCode::Opentribulletdown, -// //ffi::XK_openstar => VirtualKeyCode::Openstar, -// //ffi::XK_enfilledcircbullet => VirtualKeyCode::Enfilledcircbullet, -// //ffi::XK_enfilledsqbullet => VirtualKeyCode::Enfilledsqbullet, -// //ffi::XK_filledtribulletup => VirtualKeyCode::Filledtribulletup, -// //ffi::XK_filledtribulletdown => VirtualKeyCode::Filledtribulletdown, -// //ffi::XK_leftpointer => VirtualKeyCode::Leftpointer, -// //ffi::XK_rightpointer => VirtualKeyCode::Rightpointer, -// //ffi::XK_club => VirtualKeyCode::Club, -// //ffi::XK_diamond => VirtualKeyCode::Diamond, -// //ffi::XK_heart => VirtualKeyCode::Heart, -// //ffi::XK_maltesecross => VirtualKeyCode::Maltesecross, -// //ffi::XK_dagger => VirtualKeyCode::Dagger, -// //ffi::XK_doubledagger => VirtualKeyCode::Doubledagger, -// //ffi::XK_checkmark => VirtualKeyCode::Checkmark, -// //ffi::XK_ballotcross => VirtualKeyCode::Ballotcross, -// //ffi::XK_musicalsharp => VirtualKeyCode::Musicalsharp, -// //ffi::XK_musicalflat => VirtualKeyCode::Musicalflat, -// //ffi::XK_malesymbol => VirtualKeyCode::Malesymbol, -// //ffi::XK_femalesymbol => VirtualKeyCode::Femalesymbol, -// //ffi::XK_telephone => VirtualKeyCode::Telephone, -// //ffi::XK_telephonerecorder => VirtualKeyCode::Telephonerecorder, -// //ffi::XK_phonographcopyright => VirtualKeyCode::Phonographcopyright, -// //ffi::XK_caret => VirtualKeyCode::Caret, -// //ffi::XK_singlelowquotemark => VirtualKeyCode::Singlelowquotemark, -// //ffi::XK_doublelowquotemark => VirtualKeyCode::Doublelowquotemark, -// //ffi::XK_cursor => VirtualKeyCode::Cursor, -// //ffi::XK_leftcaret => VirtualKeyCode::Leftcaret, -// //ffi::XK_rightcaret => VirtualKeyCode::Rightcaret, -// //ffi::XK_downcaret => VirtualKeyCode::Downcaret, -// //ffi::XK_upcaret => VirtualKeyCode::Upcaret, -// //ffi::XK_overbar => VirtualKeyCode::Overbar, -// //ffi::XK_downtack => VirtualKeyCode::Downtack, -// //ffi::XK_upshoe => VirtualKeyCode::Upshoe, -// //ffi::XK_downstile => VirtualKeyCode::Downstile, -// //ffi::XK_underbar => VirtualKeyCode::Underbar, -// //ffi::XK_jot => VirtualKeyCode::Jot, -// //ffi::XK_quad => VirtualKeyCode::Quad, -// //ffi::XK_uptack => VirtualKeyCode::Uptack, -// //ffi::XK_circle => VirtualKeyCode::Circle, -// //ffi::XK_upstile => VirtualKeyCode::Upstile, -// //ffi::XK_downshoe => VirtualKeyCode::Downshoe, -// //ffi::XK_rightshoe => VirtualKeyCode::Rightshoe, -// //ffi::XK_leftshoe => VirtualKeyCode::Leftshoe, -// //ffi::XK_lefttack => VirtualKeyCode::Lefttack, -// //ffi::XK_righttack => VirtualKeyCode::Righttack, -// //ffi::XK_hebrew_doublelowline => VirtualKeyCode::Hebrew_doublelowline, -// //ffi::XK_hebrew_aleph => VirtualKeyCode::Hebrew_aleph, -// //ffi::XK_hebrew_bet => VirtualKeyCode::Hebrew_bet, -// //ffi::XK_hebrew_beth => VirtualKeyCode::Hebrew_beth, -// //ffi::XK_hebrew_gimel => VirtualKeyCode::Hebrew_gimel, -// //ffi::XK_hebrew_gimmel => VirtualKeyCode::Hebrew_gimmel, -// //ffi::XK_hebrew_dalet => VirtualKeyCode::Hebrew_dalet, -// //ffi::XK_hebrew_daleth => VirtualKeyCode::Hebrew_daleth, -// //ffi::XK_hebrew_he => VirtualKeyCode::Hebrew_he, -// //ffi::XK_hebrew_waw => VirtualKeyCode::Hebrew_waw, -// //ffi::XK_hebrew_zain => VirtualKeyCode::Hebrew_zain, -// //ffi::XK_hebrew_zayin => VirtualKeyCode::Hebrew_zayin, -// //ffi::XK_hebrew_chet => VirtualKeyCode::Hebrew_chet, -// //ffi::XK_hebrew_het => VirtualKeyCode::Hebrew_het, -// //ffi::XK_hebrew_tet => VirtualKeyCode::Hebrew_tet, -// //ffi::XK_hebrew_teth => VirtualKeyCode::Hebrew_teth, -// //ffi::XK_hebrew_yod => VirtualKeyCode::Hebrew_yod, -// //ffi::XK_hebrew_finalkaph => VirtualKeyCode::Hebrew_finalkaph, -// //ffi::XK_hebrew_kaph => VirtualKeyCode::Hebrew_kaph, -// //ffi::XK_hebrew_lamed => VirtualKeyCode::Hebrew_lamed, -// //ffi::XK_hebrew_finalmem => VirtualKeyCode::Hebrew_finalmem, -// //ffi::XK_hebrew_mem => VirtualKeyCode::Hebrew_mem, -// //ffi::XK_hebrew_finalnun => VirtualKeyCode::Hebrew_finalnun, -// //ffi::XK_hebrew_nun => VirtualKeyCode::Hebrew_nun, -// //ffi::XK_hebrew_samech => VirtualKeyCode::Hebrew_samech, -// //ffi::XK_hebrew_samekh => VirtualKeyCode::Hebrew_samekh, -// //ffi::XK_hebrew_ayin => VirtualKeyCode::Hebrew_ayin, -// //ffi::XK_hebrew_finalpe => VirtualKeyCode::Hebrew_finalpe, -// //ffi::XK_hebrew_pe => VirtualKeyCode::Hebrew_pe, -// //ffi::XK_hebrew_finalzade => VirtualKeyCode::Hebrew_finalzade, -// //ffi::XK_hebrew_finalzadi => VirtualKeyCode::Hebrew_finalzadi, -// //ffi::XK_hebrew_zade => VirtualKeyCode::Hebrew_zade, -// //ffi::XK_hebrew_zadi => VirtualKeyCode::Hebrew_zadi, -// //ffi::XK_hebrew_qoph => VirtualKeyCode::Hebrew_qoph, -// //ffi::XK_hebrew_kuf => VirtualKeyCode::Hebrew_kuf, -// //ffi::XK_hebrew_resh => VirtualKeyCode::Hebrew_resh, -// //ffi::XK_hebrew_shin => VirtualKeyCode::Hebrew_shin, -// //ffi::XK_hebrew_taw => VirtualKeyCode::Hebrew_taw, -// //ffi::XK_hebrew_taf => VirtualKeyCode::Hebrew_taf, -// //ffi::XK_Hebrew_switch => VirtualKeyCode::Hebrew_switch, -// ffi::XF86XK_Back => VirtualKeyCode::NavigateBackward, -// ffi::XF86XK_Forward => VirtualKeyCode::NavigateForward, -// ffi::XF86XK_Copy => VirtualKeyCode::Copy, -// ffi::XF86XK_Paste => VirtualKeyCode::Paste, -// ffi::XF86XK_Cut => VirtualKeyCode::Cut, -// _ => return None, -// }) -// } diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index a8c8956075..d074e35256 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -5,10 +5,10 @@ target_os = "netbsd", target_os = "openbsd" ))] +#![allow(non_fmt_panic)] mod dnd; mod event_processor; -mod events; pub mod ffi; mod ime; mod monitor; From 8e6860b0e68c87ead19e62fbd642023fd30ddd13 Mon Sep 17 00:00:00 2001 From: Artur Kovacs Date: Mon, 10 May 2021 19:45:39 +0200 Subject: [PATCH 26/53] Update xkbcommon-dl --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 68a0c82846..d131c193d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,7 +97,7 @@ percent-encoding = { version = "2.0", optional = true } parking_lot = { version = "0.11.0", optional = true } libc = "0.2.64" memmap2 = { version = "0.2.1", optional = true } -xkbcommon-dl = { git = "https://github.com/maroider/xkbcommon-dl", rev = "5307184" } +xkbcommon-dl = { git = "https://github.com/maroider/xkbcommon-dl", rev = "802388064d0e5775fa09578bcad45842874f08e0" } [target.'cfg(target_arch = "wasm32")'.dependencies.web_sys] package = "web-sys" From ed47b6be268005d0071ca49235966a7cbf7c5167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Sun, 16 May 2021 23:20:45 +0200 Subject: [PATCH 27/53] Update xkbcommon-dl again --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d131c193d7..1e9d45a81e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,7 +97,7 @@ percent-encoding = { version = "2.0", optional = true } parking_lot = { version = "0.11.0", optional = true } libc = "0.2.64" memmap2 = { version = "0.2.1", optional = true } -xkbcommon-dl = { git = "https://github.com/maroider/xkbcommon-dl", rev = "802388064d0e5775fa09578bcad45842874f08e0" } +xkbcommon-dl = { git = "https://github.com/maroider/xkbcommon-dl", rev = "900832888ad6f11011d1369befb344a9aa8a9610" } [target.'cfg(target_arch = "wasm32")'.dependencies.web_sys] package = "web-sys" From ec7e9f1af5fa65bf01dbd508bc46964a6edfc40f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Sun, 16 May 2021 23:23:18 +0200 Subject: [PATCH 28/53] Remove accidentally included attribute --- src/platform_impl/linux/x11/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index d074e35256..d57ef3ce01 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -5,7 +5,6 @@ target_os = "netbsd", target_os = "openbsd" ))] -#![allow(non_fmt_panic)] mod dnd; mod event_processor; From 906721766f0a8c930c195dd8ee246a9d5230201d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Sun, 16 May 2021 23:26:51 +0200 Subject: [PATCH 29/53] Use `as u32` to cast `i32`s to `u32`s --- src/platform_impl/linux/x11/event_processor.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index e68edd7d36..e313fdf4ed 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -1151,14 +1151,13 @@ impl EventProcessor { let xev = unsafe { &*(xev as *const _ as *const ffi::XkbStateNotifyEvent) }; if matches!(xev.event_type, 2 | 3) { - // TODO: Is `as u32` fine here? self.kb_state.update_modifiers( xev.base_mods, xev.latched_mods, xev.locked_mods, - u32::from_ne_bytes(xev.base_group.to_ne_bytes()), - u32::from_ne_bytes(xev.latched_group.to_ne_bytes()), - u32::from_ne_bytes(xev.locked_group.to_ne_bytes()), + xev.base_group as u32, + xev.latched_group as u32, + xev.locked_group as u32, ) } } From 141d7ad382f6be7d1fcffa09d88b84024b4c820f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Sun, 16 May 2021 23:55:48 +0200 Subject: [PATCH 30/53] Put more things behind the "wayland" feature --- src/platform_impl/linux/common/xkb_state.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index 7651d8370b..e3e187a388 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -8,6 +8,9 @@ use std::ptr; #[cfg(feature = "wayland")] use memmap2::MmapOptions; +#[cfg(feature = "wayland")] +pub use sctk::seat::keyboard::RMLVO; + #[cfg(feature = "x11")] use x11_dl::xlib_xcb::xcb_connection_t; #[cfg(feature = "x11")] @@ -17,8 +20,6 @@ use xkbcommon_dl::{ self as ffi, xkb_state_component, XKBCOMMON_COMPOSE_HANDLE as XKBCH, XKBCOMMON_HANDLE as XKBH, }; -pub use sctk::seat::keyboard::RMLVO; - use crate::{ event::ElementState, keyboard::{Key, KeyCode, KeyLocation}, @@ -317,6 +318,7 @@ impl KbState { Ok(me) } + #[cfg(feature = "wayland")] pub(crate) fn from_rmlvo(rmlvo: RMLVO) -> Result { fn to_cstring(s: Option) -> Result, Error> { s.map_or(Ok(None), |s| CString::new(s).map(Option::Some)) @@ -421,6 +423,7 @@ impl KbState { self.post_init(keymap); } + #[cfg(feature = "wayland")] pub(crate) unsafe fn init_with_rmlvo( &mut self, names: ffi::xkb_rule_names, From df0fd07b435e2d08a3db7b6c642f0bcc1fe1d573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Sun, 16 May 2021 23:58:48 +0200 Subject: [PATCH 31/53] Remove superfluous scope --- src/platform_impl/linux/common/xkb_state.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index e3e187a388..bc1a388c10 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -252,11 +252,10 @@ impl KbState { } pub(crate) fn new() -> Result { - { - if ffi::XKBCOMMON_OPTION.as_ref().is_none() { - return Err(Error::XKBNotFound); - } + if ffi::XKBCOMMON_OPTION.as_ref().is_none() { + return Err(Error::XKBNotFound); } + let context = unsafe { (XKBH.xkb_context_new)(ffi::xkb_context_flags::XKB_CONTEXT_NO_FLAGS) }; if context.is_null() { From 167b40c6fe062c848f58bf63d62b6c0b19f59e95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Wed, 16 Jun 2021 03:46:22 +0200 Subject: [PATCH 32/53] Separate out loading of the X11 keymap --- src/platform_impl/linux/common/xkb_state.rs | 38 ++++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index bc1a388c10..446975c6de 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -26,6 +26,8 @@ use crate::{ }; pub(crate) struct KbState { + #[cfg(feature = "x11")] + xcb_connection: *mut xcb_connection_t, xkb_context: *mut ffi::xkb_context, xkb_keymap: *mut ffi::xkb_keymap, xkb_state: *mut ffi::xkb_state, @@ -263,6 +265,8 @@ impl KbState { } let mut me = KbState { + #[cfg(feature = "x11")] + xcb_connection: ptr::null_mut(), xkb_context: context, xkb_keymap: ptr::null_mut(), xkb_state: ptr::null_mut(), @@ -284,6 +288,7 @@ impl KbState { #[cfg(feature = "x11")] pub(crate) fn from_x11_xkb(connection: *mut xcb_connection_t) -> Result { let mut me = Self::new()?; + me.xcb_connection = connection; let result = unsafe { (XKBXH.xkb_x11_setup_xkb_extension)( @@ -299,22 +304,29 @@ impl KbState { }; assert_eq!(result, 1, "Failed to initialize libxkbcommon"); + unsafe { me.load_x11_keymap() }; + + Ok(me) + } + + #[cfg(feature = "x11")] + pub(crate) unsafe fn load_x11_keymap(&mut self) { + if !self.xkb_keymap.is_null() { + self.de_init(); + } + // TODO: Support keyboards other than the "virtual core keyboard device". - let core_keyboard_id = unsafe { (XKBXH.xkb_x11_get_core_keyboard_device_id)(connection) }; - let keymap = unsafe { - (XKBXH.xkb_x11_keymap_new_from_device)( - me.xkb_context, - connection, - core_keyboard_id, - xkbcommon_dl::xkb_keymap_compile_flags::XKB_KEYMAP_COMPILE_NO_FLAGS, - ) - }; + let core_keyboard_id = (XKBXH.xkb_x11_get_core_keyboard_device_id)(self.xcb_connection); + let keymap = (XKBXH.xkb_x11_keymap_new_from_device)( + self.xkb_context, + self.xcb_connection, + core_keyboard_id, + xkbcommon_dl::xkb_keymap_compile_flags::XKB_KEYMAP_COMPILE_NO_FLAGS, + ); assert_ne!(keymap, ptr::null_mut()); - me.xkb_keymap = keymap; - - unsafe { me.post_init(keymap) }; + self.xkb_keymap = keymap; - Ok(me) + self.post_init(keymap); } #[cfg(feature = "wayland")] From 47099081b8da9e8880e14a6ca1789df5d107d11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Wed, 16 Jun 2021 05:41:04 +0200 Subject: [PATCH 33/53] Wire up X11 IME support --- .../linux/x11/event_processor.rs | 19 +++++++++++++++++++ src/platform_impl/linux/x11/window.rs | 1 + 2 files changed, 20 insertions(+) diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index e313fdf4ed..539b5a52fb 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -548,6 +548,25 @@ impl EventProcessor { } } + ffi::KeyPress => { + // TODO: Is it possible to exclusively use XInput2 events here? + let xkev: &mut ffi::XKeyEvent = xev.as_mut(); + + let window = xkev.window; + let window_id = mkwid(window); + + let written = if let Some(ic) = wt.ime.borrow().get_context(window) { + wt.xconn.lookup_utf8(ic, xkev) + } else { + return; + }; + let event = Event::WindowEvent { + window_id, + event: WindowEvent::ReceivedImeText(written), + }; + callback(event); + } + ffi::GenericEvent => { let guard = if let Some(e) = GenericEventCookie::from_event(&wt.xconn, *xev) { e diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index 7073a919d0..e3525ef521 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -230,6 +230,7 @@ impl UnownedWindow { swa.event_mask = ffi::ExposureMask | ffi::StructureNotifyMask | ffi::VisibilityChangeMask + | ffi::KeyPressMask | ffi::KeymapStateMask | ffi::ButtonPressMask | ffi::ButtonReleaseMask From 75d1ceeea89674af177ba4e9d1e1be25f5958e04 Mon Sep 17 00:00:00 2001 From: Artur Kovacs Date: Sun, 4 Jul 2021 21:46:04 +0200 Subject: [PATCH 34/53] Use the currently active keyboard layout on X11 --- src/platform_impl/linux/common/xkb_state.rs | 13 +++++++++++-- src/platform_impl/linux/x11/event_processor.rs | 18 +++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index 446975c6de..8c82f2df06 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -325,8 +325,9 @@ impl KbState { ); assert_ne!(keymap, ptr::null_mut()); self.xkb_keymap = keymap; - - self.post_init(keymap); + self.xkb_state = + (XKBXH.xkb_x11_state_new_from_device)(keymap, self.xcb_connection, core_keyboard_id); + self.mods_state.update_with(self.xkb_state); } #[cfg(feature = "wayland")] @@ -567,6 +568,14 @@ impl<'a> KeyEventResults<'a> { None }; + // let key_text = state.keysym_to_utf8_raw(keysym); + // unsafe { + // let layout_id = (XKBH.xkb_state_serialize_layout)(state.xkb_state, xkb_state_component::XKB_STATE_LAYOUT_EFFECTIVE); + // let layout_name_cstr = (XKBH.xkb_keymap_layout_get_name)(state.xkb_keymap, layout_id); + // let layout_name = std::ffi::CStr::from_ptr(layout_name_cstr as *mut _); + // debug!("KeyEventResults::new {:?}, {:?}", key_text, layout_name); + // } + KeyEventResults { state, keycode, diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 539b5a52fb..bcb9b08e87 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -1169,7 +1169,23 @@ impl EventProcessor { ffi::XkbStateNotify => { let xev = unsafe { &*(xev as *const _ as *const ffi::XkbStateNotifyEvent) }; - if matches!(xev.event_type, 2 | 3) { + debug!( + "XkbStateNotify. group: {}, event_type: {}", + xev.group, xev.event_type + ); + if xev.event_type == 0 { + // This probably indicates that the keyboard layout was switched. + // Let's update the groups (i.e. the layout) + self.kb_state.update_modifiers( + xev.base_mods, + xev.latched_mods, + xev.locked_mods, + xev.base_group as u32, + xev.latched_group as u32, + xev.locked_group as u32, + ); + } + if matches!(xev.event_type as i32, ffi::KeyPress | ffi::KeyRelease) { self.kb_state.update_modifiers( xev.base_mods, xev.latched_mods, From 10b424b2c47542c028aa49a302e98f3712735032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Sun, 4 Jul 2021 23:22:59 +0200 Subject: [PATCH 35/53] fixup! Wire up X11 IME support --- .../linux/x11/event_processor.rs | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index bcb9b08e87..c9878c1d56 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -555,16 +555,21 @@ impl EventProcessor { let window = xkev.window; let window_id = mkwid(window); - let written = if let Some(ic) = wt.ime.borrow().get_context(window) { - wt.xconn.lookup_utf8(ic, xkev) - } else { - return; - }; - let event = Event::WindowEvent { - window_id, - event: WindowEvent::ReceivedImeText(written), - }; - callback(event); + let keycode = xkev.keycode; + // When a compose sequence or IME pre-edit is finished, it ends in a KeyPress with + // a keycode of 0. + if keycode == 0 { + let written = if let Some(ic) = wt.ime.borrow().get_context(window) { + wt.xconn.lookup_utf8(ic, xkev) + } else { + return; + }; + let event = Event::WindowEvent { + window_id, + event: WindowEvent::ReceivedImeText(written), + }; + callback(event); + } } ffi::GenericEvent => { From 1d24616c6fc5135c2d8c06205ae53c91d265c444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Tue, 3 Aug 2021 15:58:48 +0200 Subject: [PATCH 36/53] Enable keysym mapping for "Alt Graph" --- src/platform_impl/linux/common/keymap.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/platform_impl/linux/common/keymap.rs b/src/platform_impl/linux/common/keymap.rs index 4f72adc8f9..b54a1776ab 100644 --- a/src/platform_impl/linux/common/keymap.rs +++ b/src/platform_impl/linux/common/keymap.rs @@ -436,10 +436,10 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { // XKB function and modifier keys // keysyms::XKB_KEY_ISO_Lock => Key::IsoLock, // keysyms::XKB_KEY_ISO_Level2_Latch => Key::IsoLevel2Latch, - // NOTE: I'm not quite certain if mapping the next 3 values to AltGraph is correct. - // keysyms::XKB_KEY_ISO_Level3_Shift => Key::AltGraph, - // keysyms::XKB_KEY_ISO_Level3_Latch => Key::AltGraph, - // keysyms::XKB_KEY_ISO_Level3_Lock => Key::AltGraph, + keysyms::XKB_KEY_ISO_Level3_Shift => Key::AltGraph, + // NOTE: I'm not quite certain if mapping the next 2 values to AltGraph is correct. + keysyms::XKB_KEY_ISO_Level3_Latch => Key::AltGraph, + keysyms::XKB_KEY_ISO_Level3_Lock => Key::AltGraph, // keysyms::XKB_KEY_ISO_Level5_Shift => Key::IsoLevel5Shift, // keysyms::XKB_KEY_ISO_Level5_Latch => Key::IsoLevel5Latch, // keysyms::XKB_KEY_ISO_Level5_Lock => Key::IsoLevel5Lock, From ea9a4d685b8a3ccb5b186b92d732a4aff894f4e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 5 Aug 2021 00:13:45 +0200 Subject: [PATCH 37/53] Actually respect keyboard layout changes 9486ac0 did not work for me --- .../linux/x11/event_processor.rs | 67 +++++++++---------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index c9878c1d56..1952a71a74 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -159,24 +159,6 @@ impl EventProcessor { let event_type = xev.get_type(); match event_type { - ffi::MappingNotify => { - let mapping: &ffi::XMappingEvent = xev.as_ref(); - - if mapping.request == ffi::MappingModifier - || mapping.request == ffi::MappingKeyboard - { - unsafe { - (wt.xconn.xlib.XRefreshKeyboardMapping)(xev.as_mut()); - } - wt.xconn - .check_errors() - .expect("Failed to call XRefreshKeyboardMapping"); - - self.mod_keymap.reset_from_x_connection(&wt.xconn); - self.device_mod_state.update_keymap(&self.mod_keymap); - } - } - ffi::ClientMessage => { let client_msg: &ffi::XClientMessageEvent = xev.as_ref(); @@ -1092,6 +1074,39 @@ impl EventProcessor { } ffi::XI_RawKeyPress | ffi::XI_RawKeyRelease => { + // This is horrible, but I couldn't manage to respect keyboard layout changes + // in any other way. In fact, getting this to work at all proved so frustrating + // that I (@maroider) lost motivation to work on the keyboard event rework for + // some months. Thankfully, @ArturKovacs offered to help debug the problem + // over discord, and the following is the result of that debugging session. + // + // Without the XKB extension, the X.Org server sends us the `MappingNotify` + // event when there's been a change in the keyboard layout. This stops + // being the case when we select ourselves some XKB events with `XkbSelectEvents` + // and the "core keyboard device (0x100)" (we haven't tried with any other + // devices). We managed to reproduce this on both our machines. + // + // With the XKB extension active, it would seem like we're supposed to use the + // `XkbStateNotify` event to detect keyboard layout changes, but the `group` + // never changes value (it is always `0`). This worked for @ArturKovacs, but + // not for me. We also tried to use the `group` given to us in keypress events, + // but it remained constant there, too. + // + // We also tried to see if there was some other event that got fired when the + // keyboard layout changed, and we found a mysterious event with the value + // `85` (`0x55`). We couldn't find any reference to it in the X11 headers or + // in the X.Org server source. + // + // `KeymapNotify` did briefly look interesting based purely on the name, but + // it is only useful for checking what keys are pressed when we receive the + // event. + // + // So instead of any vaguely reasonable approach, we get this: reloading the + // keymap on *every* keypress. That's peak efficiency right there! + // + // FIXME: Someone please save our souls! Or at least our wasted CPU cycles. + unsafe { self.kb_state.load_x11_keymap() }; + let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) }; let state = match xev.evtype { @@ -1174,22 +1189,6 @@ impl EventProcessor { ffi::XkbStateNotify => { let xev = unsafe { &*(xev as *const _ as *const ffi::XkbStateNotifyEvent) }; - debug!( - "XkbStateNotify. group: {}, event_type: {}", - xev.group, xev.event_type - ); - if xev.event_type == 0 { - // This probably indicates that the keyboard layout was switched. - // Let's update the groups (i.e. the layout) - self.kb_state.update_modifiers( - xev.base_mods, - xev.latched_mods, - xev.locked_mods, - xev.base_group as u32, - xev.latched_group as u32, - xev.locked_group as u32, - ); - } if matches!(xev.event_type as i32, ffi::KeyPress | ffi::KeyRelease) { self.kb_state.update_modifiers( xev.base_mods, From 91a3b1041bd1d79f9c9229686ca0ee0a33f8157d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 5 Aug 2021 19:03:25 +0200 Subject: [PATCH 38/53] Make `xkb_state` more internally consistent --- src/platform_impl/linux/common/xkb_state.rs | 77 +++++++++++-------- .../linux/wayland/seat/keyboard/handlers.rs | 6 -- .../linux/x11/event_processor.rs | 2 +- 3 files changed, 44 insertions(+), 41 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index 8c82f2df06..437e5ddf0a 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -64,8 +64,8 @@ pub struct ModifiersState { } impl ModifiersState { - fn new() -> ModifiersState { - ModifiersState::default() + fn new() -> Self { + Self::default() } fn update_with(&mut self, state: *mut ffi::xkb_state) { @@ -253,7 +253,7 @@ impl KbState { Some(byte_slice_to_cached_string(&self.scratch_buffer)) } - pub(crate) fn new() -> Result { + pub(crate) fn new() -> Result { if ffi::XKBCOMMON_OPTION.as_ref().is_none() { return Err(Error::XKBNotFound); } @@ -264,7 +264,7 @@ impl KbState { return Err(Error::XKBNotFound); } - let mut me = KbState { + let mut me = Self { #[cfg(feature = "x11")] xcb_connection: ptr::null_mut(), xkb_context: context, @@ -286,7 +286,7 @@ impl KbState { impl KbState { #[cfg(feature = "x11")] - pub(crate) fn from_x11_xkb(connection: *mut xcb_connection_t) -> Result { + pub(crate) fn from_x11_xkb(connection: *mut xcb_connection_t) -> Result { let mut me = Self::new()?; me.xcb_connection = connection; @@ -304,40 +304,19 @@ impl KbState { }; assert_eq!(result, 1, "Failed to initialize libxkbcommon"); - unsafe { me.load_x11_keymap() }; + unsafe { me.init_with_x11_keymap() }; Ok(me) } - #[cfg(feature = "x11")] - pub(crate) unsafe fn load_x11_keymap(&mut self) { - if !self.xkb_keymap.is_null() { - self.de_init(); - } - - // TODO: Support keyboards other than the "virtual core keyboard device". - let core_keyboard_id = (XKBXH.xkb_x11_get_core_keyboard_device_id)(self.xcb_connection); - let keymap = (XKBXH.xkb_x11_keymap_new_from_device)( - self.xkb_context, - self.xcb_connection, - core_keyboard_id, - xkbcommon_dl::xkb_keymap_compile_flags::XKB_KEYMAP_COMPILE_NO_FLAGS, - ); - assert_ne!(keymap, ptr::null_mut()); - self.xkb_keymap = keymap; - self.xkb_state = - (XKBXH.xkb_x11_state_new_from_device)(keymap, self.xcb_connection, core_keyboard_id); - self.mods_state.update_with(self.xkb_state); - } - #[cfg(feature = "wayland")] - pub(crate) fn from_rmlvo(rmlvo: RMLVO) -> Result { + pub(crate) fn from_rmlvo(rmlvo: RMLVO) -> Result { fn to_cstring(s: Option) -> Result, Error> { s.map_or(Ok(None), |s| CString::new(s).map(Option::Some)) .map_err(|_| Error::BadNames) } - let mut state = KbState::new()?; + let mut state = Self::new()?; let rules = to_cstring(rmlvo.rules)?; let model = to_cstring(rmlvo.model)?; @@ -403,22 +382,46 @@ impl KbState { self.xkb_compose_state_2 = compose_state_2; } - pub(crate) unsafe fn post_init(&mut self, keymap: *mut ffi::xkb_keymap) { - let state = (XKBH.xkb_state_new)(keymap); + unsafe fn post_init(&mut self, state: *mut ffi::xkb_state, keymap: *mut ffi::xkb_keymap) { self.xkb_keymap = keymap; self.xkb_state = state; self.mods_state.update_with(state); } - pub(crate) unsafe fn de_init(&mut self) { + unsafe fn de_init(&mut self) { (XKBH.xkb_state_unref)(self.xkb_state); self.xkb_state = ptr::null_mut(); (XKBH.xkb_keymap_unref)(self.xkb_keymap); self.xkb_keymap = ptr::null_mut(); } + #[cfg(feature = "x11")] + pub(crate) unsafe fn init_with_x11_keymap(&mut self) { + if !self.xkb_keymap.is_null() { + self.de_init(); + } + + // TODO: Support keyboards other than the "virtual core keyboard device". + let core_keyboard_id = (XKBXH.xkb_x11_get_core_keyboard_device_id)(self.xcb_connection); + let keymap = (XKBXH.xkb_x11_keymap_new_from_device)( + self.xkb_context, + self.xcb_connection, + core_keyboard_id, + xkbcommon_dl::xkb_keymap_compile_flags::XKB_KEYMAP_COMPILE_NO_FLAGS, + ); + assert_ne!(keymap, ptr::null_mut()); + + let state = + (XKBXH.xkb_x11_state_new_from_device)(keymap, self.xcb_connection, core_keyboard_id); + self.post_init(state, keymap); + } + #[cfg(feature = "wayland")] pub(crate) unsafe fn init_with_fd(&mut self, fd: File, size: usize) { + if !self.xkb_keymap.is_null() { + self.de_init(); + } + let map = MmapOptions::new().len(size).map(&fd).unwrap(); let keymap = (XKBH.xkb_keymap_new_from_string)( @@ -432,7 +435,8 @@ impl KbState { panic!("Received invalid keymap from compositor."); } - self.post_init(keymap); + let state = (XKBH.xkb_state_new)(keymap); + self.post_init(state, keymap); } #[cfg(feature = "wayland")] @@ -440,6 +444,10 @@ impl KbState { &mut self, names: ffi::xkb_rule_names, ) -> Result<(), Error> { + if !self.xkb_keymap.is_null() { + self.de_init(); + } + let keymap = (XKBH.xkb_keymap_new_from_names)( self.xkb_context, &names, @@ -450,7 +458,8 @@ impl KbState { return Err(Error::BadNames); } - self.post_init(keymap); + let state = (XKBH.xkb_state_new)(keymap); + self.post_init(state, keymap); Ok(()) } diff --git a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs index ee4188bde5..26b1faeb46 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs @@ -470,12 +470,6 @@ impl KbdHandler { // state is locked, ignore keymap updates return; } - if state.ready() { - // new keymap, we first deinit to free resources - unsafe { - state.de_init(); - } - } match format { wl_keyboard::KeymapFormat::XkbV1 => unsafe { state.init_with_fd(fd, size as usize); diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 1952a71a74..5cca7f659b 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -1105,7 +1105,7 @@ impl EventProcessor { // keymap on *every* keypress. That's peak efficiency right there! // // FIXME: Someone please save our souls! Or at least our wasted CPU cycles. - unsafe { self.kb_state.load_x11_keymap() }; + unsafe { self.kb_state.init_with_x11_keymap() }; let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) }; From 67cb19ac023b8ce6725a4dd0d773c7372768f689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 5 Aug 2021 19:14:25 +0200 Subject: [PATCH 39/53] Improve the safety of `KbState` --- src/platform_impl/linux/common/xkb_state.rs | 31 +++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index 437e5ddf0a..0b7ca1638a 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -366,14 +366,21 @@ impl KbState { ffi::xkb_compose_state_flags::XKB_COMPOSE_STATE_NO_FLAGS, ); + if compose_table.is_null() { + // init of compose state failed, continue without compose + (XKBCH.xkb_compose_table_unref)(compose_table); + return; + } + let compose_state_2 = (XKBCH.xkb_compose_state_new)( compose_table, ffi::xkb_compose_state_flags::XKB_COMPOSE_STATE_NO_FLAGS, ); - if compose_state.is_null() || compose_state_2.is_null() { + if compose_state_2.is_null() { // init of compose state failed, continue without compose (XKBCH.xkb_compose_table_unref)(compose_table); + (XKBCH.xkb_compose_state_unref)(compose_state); return; } @@ -489,10 +496,24 @@ impl KbState { impl Drop for KbState { fn drop(&mut self) { unsafe { - (XKBCH.xkb_compose_state_unref)(self.xkb_compose_state); - (XKBCH.xkb_compose_table_unref)(self.xkb_compose_table); - (XKBH.xkb_state_unref)(self.xkb_state); - (XKBH.xkb_keymap_unref)(self.xkb_keymap); + // TODO: Simplify this. We can currently only safely assume that the `xkb_context` + // is always valid. If we can somehow guarantee the same for `xkb_state` and + // `xkb_keymap`, then we could omit their null-checks. + if !self.xkb_compose_state.is_null() { + (XKBCH.xkb_compose_state_unref)(self.xkb_compose_state); + } + if !self.xkb_compose_state_2.is_null() { + (XKBCH.xkb_compose_state_unref)(self.xkb_compose_state_2); + } + if !self.xkb_compose_table.is_null() { + (XKBCH.xkb_compose_table_unref)(self.xkb_compose_table); + } + if !self.xkb_state.is_null() { + (XKBH.xkb_state_unref)(self.xkb_state); + } + if !self.xkb_keymap.is_null() { + (XKBH.xkb_keymap_unref)(self.xkb_keymap); + } (XKBH.xkb_context_unref)(self.xkb_context); } } From 494a1e59c0547a56bb8ca694090533e8f5d913d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 5 Aug 2021 19:21:40 +0200 Subject: [PATCH 40/53] Make a decision on control characters and dead keys --- src/platform_impl/linux/common/xkb_state.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index 0b7ca1638a..40403d02ab 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -698,9 +698,9 @@ impl<'a> KeyEventResults<'a> { } pub fn text_with_all_modifiers(&mut self) -> Option<&'static str> { - // TODO: Should Ctrl override any attempts to compose text? - // gnome-terminal agrees, but konsole disagrees. - // Should it be configurable instead? + // The current behaviour makes it so composing a character overrides attempts to input a + // control character with the `Ctrl` key. We can potentially add a configuration option + // if someone specifically wants the oppsite behaviour. self.composed_text() .unwrap_or_else(|_| self.state.get_utf8_raw(self.keycode)) } From df9a96aaeb850a111e5487e04790278e681a879d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 5 Aug 2021 19:56:09 +0200 Subject: [PATCH 41/53] Store keycodes with X11's keycode offset --- src/platform_impl/linux/common/keymap.rs | 3 ++- src/platform_impl/linux/common/xkb_state.rs | 16 ++++++++-------- .../linux/wayland/seat/keyboard/handlers.rs | 4 ++-- src/platform_impl/linux/x11/event_processor.rs | 11 +++++------ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/platform_impl/linux/common/keymap.rs b/src/platform_impl/linux/common/keymap.rs index b54a1776ab..b64932e918 100644 --- a/src/platform_impl/linux/common/keymap.rs +++ b/src/platform_impl/linux/common/keymap.rs @@ -4,7 +4,8 @@ use crate::keyboard::{Key, KeyCode, KeyLocation, NativeKeyCode}; // TODO: Do another pass on all of this -pub fn rawkey_to_keycode(rawkey: u32) -> KeyCode { +pub fn raw_keycode_to_keycode(keycode: u32) -> KeyCode { + let rawkey = keycode - 8; // The keycode values are taken from linux/include/uapi/linux/input-event-codes.h, as // libxkbcommon's documentation indicates that the keycode values we're getting from it are // defined by the Linux kernel. If Winit programs end up being run on other Unix-likes which diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index 40403d02ab..558a30303f 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -148,16 +148,16 @@ impl KbState { if !self.ready() { return 0; } - unsafe { (XKBH.xkb_state_key_get_one_sym)(self.xkb_state, keycode + 8) } + unsafe { (XKBH.xkb_state_key_get_one_sym)(self.xkb_state, keycode) } } pub(crate) fn get_utf8_raw(&mut self, keycode: u32) -> Option<&'static str> { if !self.ready() { return None; } - let size = unsafe { - (XKBH.xkb_state_key_get_utf8)(self.xkb_state, keycode + 8, ptr::null_mut(), 0) - } + 1; + let size = + unsafe { (XKBH.xkb_state_key_get_utf8)(self.xkb_state, keycode, ptr::null_mut(), 0) } + + 1; if size <= 1 { return None; }; @@ -168,7 +168,7 @@ impl KbState { self.scratch_buffer.set_len(size); (XKBH.xkb_state_key_get_utf8)( self.xkb_state, - keycode + 8, + keycode, self.scratch_buffer.as_mut_ptr() as *mut _, size, ); @@ -474,7 +474,7 @@ impl KbState { impl KbState { pub(crate) unsafe fn key_repeats(&mut self, keycode: ffi::xkb_keycode_t) -> bool { - (XKBH.xkb_keymap_key_repeats)(self.xkb_keymap, keycode + 8) == 1 + (XKBH.xkb_keymap_key_repeats)(self.xkb_keymap, keycode) == 1 } #[inline] @@ -615,7 +615,7 @@ impl<'a> KeyEventResults<'a> { } pub fn keycode(&mut self) -> KeyCode { - super::keymap::rawkey_to_keycode(self.keycode) + super::keymap::raw_keycode_to_keycode(self.keycode) } pub fn key(&mut self) -> (Key<'static>, KeyLocation) { @@ -656,7 +656,7 @@ impl<'a> KeyEventResults<'a> { let keysym_count = unsafe { (XKBH.xkb_keymap_key_get_syms_by_level)( self.state.xkb_keymap, - self.keycode + 8, + self.keycode, 0, 0, &mut keysyms, diff --git a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs index 26b1faeb46..fddecc09fc 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs @@ -548,7 +548,7 @@ impl KbdHandler { _ => unreachable!(), }; - let mut ker = state.process_key_event(key, key_state); + let mut ker = state.process_key_event(key + 8, key_state); let physical_key = ker.keycode(); let (logical_key, location) = ker.key(); @@ -683,7 +683,7 @@ impl calloop::EventSource for RepeatSource { if let Some(ref mut data) = *current_repeat.borrow_mut() { // there is something to repeat let mut state = state.borrow_mut(); - let mut ker = state.process_key_repeat_event(data.keycode); + let mut ker = state.process_key_repeat_event(data.keycode + 8); let physical_key = ker.keycode(); let (logical_key, location) = ker.key(); diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 5cca7f659b..053a9821f7 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -1042,7 +1042,6 @@ impl EventProcessor { let device_id = mkdid(xkev.deviceid); let keycode = xkev.detail as u32; - let keycode = keycode - KEYCODE_OFFSET as u32; let mut ker = self.kb_state.process_key_event(keycode, state); let physical_key = ker.keycode(); let (logical_key, location) = ker.key(); @@ -1116,12 +1115,11 @@ impl EventProcessor { }; let device_id = mkdid(xev.sourceid); - let keycode = xev.detail; - let scancode = keycode - KEYCODE_OFFSET as i32; - if scancode < 0 { + let keycode = xev.detail as u32; + if keycode < KEYCODE_OFFSET as u32 { return; } - let physical_key = keymap::rawkey_to_keycode(scancode as u32); + let physical_key = keymap::raw_keycode_to_keycode(keycode); let modifiers = self.device_mod_state.modifiers(); callback(Event::DeviceEvent { @@ -1290,7 +1288,8 @@ impl EventProcessor { .into_iter() .filter(|k| *k >= KEYCODE_OFFSET) { - let keycode = (keycode - KEYCODE_OFFSET) as u32; + let keycode = keycode as u32; + let mut ker = kb_state.process_key_event(keycode, state); let physical_key = ker.keycode(); let (logical_key, location) = ker.key(); From a2c33d6fb7e2316d43a327ad3ef37a896ea41dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 5 Aug 2021 19:59:32 +0200 Subject: [PATCH 42/53] Log an error if we can't select XKB events --- src/platform_impl/linux/x11/util/input.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform_impl/linux/x11/util/input.rs b/src/platform_impl/linux/x11/util/input.rs index db0f22eb03..24aad57937 100644 --- a/src/platform_impl/linux/x11/util/input.rs +++ b/src/platform_impl/linux/x11/util/input.rs @@ -86,7 +86,7 @@ impl XConnection { if status == ffi::True { Some(Flusher::new(self)) } else { - // This should only happen if the XKB extension isn't initialized. + error!("Could not select XKB events: The XKB extension is not initialized!"); None } } From b2c73be4a28137b47d9d641c4bc60a8cb27178c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 5 Aug 2021 20:08:40 +0200 Subject: [PATCH 43/53] Remove superfluous call to `Vec::set_len` --- src/platform_impl/linux/common/xkb_state.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index 558a30303f..6cdc335637 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -540,7 +540,6 @@ impl KbState { self.scratch_buffer.clear(); self.scratch_buffer.reserve(8); loop { - unsafe { self.scratch_buffer.set_len(8) }; let bytes_written = unsafe { (XKBH.xkb_keysym_to_utf8)( keysym, From dd3fff825037ebeb2ef853d9e8f4566a8b65e8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 12 Aug 2021 01:51:50 +0200 Subject: [PATCH 44/53] Send a warning if the server doesn't send a keymap --- src/platform_impl/linux/wayland/seat/keyboard/handlers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs index fddecc09fc..232cac4be2 100644 --- a/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs +++ b/src/platform_impl/linux/wayland/seat/keyboard/handlers.rs @@ -475,7 +475,7 @@ impl KbdHandler { state.init_with_fd(fd, size as usize); }, wl_keyboard::KeymapFormat::NoKeymap => { - // TODO: how to handle this (hopefully never occuring) case? + warn!("The Wayland server did not send a keymap!"); } _ => unreachable!(), } From 8c7001cfb3ee2db83382136fa8e841f6453e78e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Wed, 25 Aug 2021 00:32:07 +0200 Subject: [PATCH 45/53] Implement `KeyCodeExtScancode` on Wayland and X11 --- src/platform/scancode.rs | 1 + src/platform/unix.rs | 15 +- src/platform_impl/linux/common/keymap.rs | 172 +++++++++++++++++++++-- src/platform_impl/linux/mod.rs | 2 +- 4 files changed, 173 insertions(+), 17 deletions(-) diff --git a/src/platform/scancode.rs b/src/platform/scancode.rs index 078fe74dea..00188c6212 100644 --- a/src/platform/scancode.rs +++ b/src/platform/scancode.rs @@ -20,6 +20,7 @@ pub trait KeyCodeExtScancode { /// /// ## Platform-specific /// - **Windows:** A 16bit extended scancode + /// - **Wayland/X11**: A 32-bit X11-style keycode. // TODO: Describe what this value contains for each platform fn to_scancode(self) -> Option; diff --git a/src/platform/unix.rs b/src/platform/unix.rs index ae3b9659b4..abf7c4c108 100644 --- a/src/platform/unix.rs +++ b/src/platform/unix.rs @@ -13,9 +13,10 @@ use std::{ptr, sync::Arc}; use crate::{ event::KeyEvent, event_loop::{EventLoop, EventLoopWindowTarget}, - keyboard::Key, + keyboard::{Key, KeyCode}, monitor::MonitorHandle, - platform::modifier_supplement::KeyEventExtModifierSupplement, + platform::{modifier_supplement::KeyEventExtModifierSupplement, scancode::KeyCodeExtScancode}, + platform_impl::common::keymap, window::{Window, WindowBuilder}, }; @@ -477,3 +478,13 @@ impl KeyEventExtModifierSupplement for KeyEvent { self.platform_specific.key_without_modifiers } } + +impl KeyCodeExtScancode for KeyCode { + fn from_scancode(scancode: u32) -> KeyCode { + keymap::raw_keycode_to_keycode(scancode) + } + + fn to_scancode(self) -> Option { + keymap::keycode_to_raw(self) + } +} diff --git a/src/platform_impl/linux/common/keymap.rs b/src/platform_impl/linux/common/keymap.rs index b64932e918..610fc4f38a 100644 --- a/src/platform_impl/linux/common/keymap.rs +++ b/src/platform_impl/linux/common/keymap.rs @@ -2,8 +2,9 @@ use crate::keyboard::{Key, KeyCode, KeyLocation, NativeKeyCode}; -// TODO: Do another pass on all of this - +/// Map the raw X11-style keycode to the `KeyCode` enum. +/// +/// X11-style keycodes are offset by 8 from the keycodes the Linux kernel uses. pub fn raw_keycode_to_keycode(keycode: u32) -> KeyCode { let rawkey = keycode - 8; // The keycode values are taken from linux/include/uapi/linux/input-event-codes.h, as @@ -14,10 +15,8 @@ pub fn raw_keycode_to_keycode(keycode: u32) -> KeyCode { // Some of the keycodes are likely superfluous for our purposes, and some are ones which are // difficult to test the correctness of, or discover the purpose of. Because of this, they've // either been commented out here, or not included at all. - // - // TODO: There are probably a couple more unproblematic keycodes to map here. match rawkey { - 0 => KeyCode::Unidentified(NativeKeyCode::XKB(0)), // TODO: Is `NativeKeyCode::Unidentified` better? + 0 => KeyCode::Unidentified(NativeKeyCode::XKB(0)), 1 => KeyCode::Escape, 2 => KeyCode::Digit1, 3 => KeyCode::Digit2, @@ -93,7 +92,7 @@ pub fn raw_keycode_to_keycode(keycode: u32) -> KeyCode { 73 => KeyCode::Numpad9, 74 => KeyCode::NumpadSubtract, 75 => KeyCode::Numpad4, - 76 => KeyCode::Numpad4, + 76 => KeyCode::Numpad5, 77 => KeyCode::Numpad6, 78 => KeyCode::NumpadAdd, 79 => KeyCode::Numpad1, @@ -264,6 +263,151 @@ pub fn raw_keycode_to_keycode(keycode: u32) -> KeyCode { } } +pub fn keycode_to_raw(keycode: KeyCode) -> Option { + match keycode { + KeyCode::Unidentified(NativeKeyCode::Unidentified) => Some(240), + KeyCode::Unidentified(NativeKeyCode::XKB(raw)) => Some(raw), + KeyCode::Escape => Some(1), + KeyCode::Digit1 => Some(2), + KeyCode::Digit2 => Some(3), + KeyCode::Digit3 => Some(4), + KeyCode::Digit4 => Some(5), + KeyCode::Digit5 => Some(6), + KeyCode::Digit6 => Some(7), + KeyCode::Digit7 => Some(8), + KeyCode::Digit8 => Some(9), + KeyCode::Digit9 => Some(10), + KeyCode::Digit0 => Some(11), + KeyCode::Minus => Some(12), + KeyCode::Equal => Some(13), + KeyCode::Backspace => Some(14), + KeyCode::Tab => Some(15), + KeyCode::KeyQ => Some(16), + KeyCode::KeyW => Some(17), + KeyCode::KeyE => Some(18), + KeyCode::KeyR => Some(19), + KeyCode::KeyT => Some(20), + KeyCode::KeyY => Some(21), + KeyCode::KeyU => Some(22), + KeyCode::KeyI => Some(23), + KeyCode::KeyO => Some(24), + KeyCode::KeyP => Some(25), + KeyCode::BracketLeft => Some(26), + KeyCode::BracketRight => Some(27), + KeyCode::Enter => Some(28), + KeyCode::ControlLeft => Some(29), + KeyCode::KeyA => Some(30), + KeyCode::KeyS => Some(31), + KeyCode::KeyD => Some(32), + KeyCode::KeyF => Some(33), + KeyCode::KeyG => Some(34), + KeyCode::KeyH => Some(35), + KeyCode::KeyJ => Some(36), + KeyCode::KeyK => Some(37), + KeyCode::KeyL => Some(38), + KeyCode::Semicolon => Some(39), + KeyCode::Quote => Some(40), + KeyCode::Backquote => Some(41), + KeyCode::ShiftLeft => Some(42), + KeyCode::Backslash => Some(43), + KeyCode::KeyZ => Some(44), + KeyCode::KeyX => Some(45), + KeyCode::KeyC => Some(46), + KeyCode::KeyV => Some(47), + KeyCode::KeyB => Some(48), + KeyCode::KeyN => Some(49), + KeyCode::KeyM => Some(50), + KeyCode::Comma => Some(51), + KeyCode::Period => Some(52), + KeyCode::Slash => Some(53), + KeyCode::ShiftRight => Some(54), + KeyCode::NumpadMultiply => Some(55), + KeyCode::AltLeft => Some(56), + KeyCode::Space => Some(57), + KeyCode::CapsLock => Some(58), + KeyCode::F1 => Some(59), + KeyCode::F2 => Some(60), + KeyCode::F3 => Some(61), + KeyCode::F4 => Some(62), + KeyCode::F5 => Some(63), + KeyCode::F6 => Some(64), + KeyCode::F7 => Some(65), + KeyCode::F8 => Some(66), + KeyCode::F9 => Some(67), + KeyCode::F10 => Some(68), + KeyCode::NumLock => Some(69), + KeyCode::ScrollLock => Some(70), + KeyCode::Numpad7 => Some(71), + KeyCode::Numpad8 => Some(72), + KeyCode::Numpad9 => Some(73), + KeyCode::NumpadSubtract => Some(74), + KeyCode::Numpad4 => Some(75), + KeyCode::Numpad5 => Some(76), + KeyCode::Numpad6 => Some(77), + KeyCode::NumpadAdd => Some(78), + KeyCode::Numpad1 => Some(79), + KeyCode::Numpad2 => Some(80), + KeyCode::Numpad3 => Some(81), + KeyCode::Numpad0 => Some(82), + KeyCode::NumpadDecimal => Some(83), + KeyCode::Lang5 => Some(85), + KeyCode::IntlBackslash => Some(86), + KeyCode::F11 => Some(87), + KeyCode::F12 => Some(88), + KeyCode::IntlRo => Some(89), + KeyCode::Lang3 => Some(90), + KeyCode::Lang4 => Some(91), + KeyCode::Convert => Some(92), + KeyCode::KanaMode => Some(93), + KeyCode::NonConvert => Some(94), + KeyCode::NumpadEnter => Some(96), + KeyCode::ControlRight => Some(97), + KeyCode::NumpadDivide => Some(98), + KeyCode::PrintScreen => Some(99), + KeyCode::AltRight => Some(100), + KeyCode::Home => Some(102), + KeyCode::ArrowUp => Some(103), + KeyCode::PageUp => Some(104), + KeyCode::ArrowLeft => Some(105), + KeyCode::ArrowRight => Some(106), + KeyCode::End => Some(107), + KeyCode::ArrowDown => Some(108), + KeyCode::PageDown => Some(109), + KeyCode::Insert => Some(110), + KeyCode::Delete => Some(111), + KeyCode::AudioVolumeMute => Some(113), + KeyCode::AudioVolumeDown => Some(114), + KeyCode::AudioVolumeUp => Some(115), + KeyCode::NumpadEqual => Some(117), + KeyCode::Pause => Some(119), + KeyCode::NumpadComma => Some(121), + KeyCode::Lang1 => Some(122), + KeyCode::Lang2 => Some(123), + KeyCode::IntlYen => Some(124), + KeyCode::SuperLeft => Some(125), + KeyCode::SuperRight => Some(126), + KeyCode::ContextMenu => Some(127), + KeyCode::MediaTrackNext => Some(163), + KeyCode::MediaPlayPause => Some(164), + KeyCode::MediaTrackPrevious => Some(165), + KeyCode::MediaStop => Some(166), + KeyCode::F13 => Some(183), + KeyCode::F14 => Some(184), + KeyCode::F15 => Some(185), + KeyCode::F16 => Some(186), + KeyCode::F17 => Some(187), + KeyCode::F18 => Some(188), + KeyCode::F19 => Some(189), + KeyCode::F20 => Some(190), + KeyCode::F21 => Some(191), + KeyCode::F22 => Some(192), + KeyCode::F23 => Some(193), + KeyCode::F24 => Some(194), + _ => None, + } + .map(|raw| raw + 8) +} + pub fn keysym_to_key(keysym: u32) -> Key<'static> { use xkbcommon_dl::keysyms; match keysym { @@ -273,7 +417,7 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { // keysyms::XKB_KEY_Linefeed => Key::Linefeed, keysyms::XKB_KEY_Clear => Key::Clear, keysyms::XKB_KEY_Return => Key::Enter, - // keysyms::XKB_KEY_Pause => Key::Pause, + keysyms::XKB_KEY_Pause => Key::Pause, keysyms::XKB_KEY_Scroll_Lock => Key::ScrollLock, keysyms::XKB_KEY_Sys_Req => Key::PrintScreen, keysyms::XKB_KEY_Escape => Key::Escape, @@ -357,6 +501,8 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { // keysyms::XKB_KEY_KP_Next => Key::PageDown, keysyms::XKB_KEY_KP_Page_Down => Key::PageDown, keysyms::XKB_KEY_KP_End => Key::End, + // TODO: What is this supposed to map to? + // This is the key labeled "5" on the numpad when NumLock is off. // keysyms::XKB_KEY_KP_Begin => Key::Begin, keysyms::XKB_KEY_KP_Insert => Key::Insert, keysyms::XKB_KEY_KP_Delete => Key::Delete, @@ -423,8 +569,7 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { keysyms::XKB_KEY_Control_R => Key::Control, keysyms::XKB_KEY_Caps_Lock => Key::CapsLock, // keysyms::XKB_KEY_Shift_Lock => Key::ShiftLock, - // - // TODO: Address how renaming `Meta` to `Super` affects this set of keys. + // keysyms::XKB_KEY_Meta_L => Key::Meta, // keysyms::XKB_KEY_Meta_R => Key::Meta, keysyms::XKB_KEY_Alt_L => Key::Alt, @@ -438,7 +583,6 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { // keysyms::XKB_KEY_ISO_Lock => Key::IsoLock, // keysyms::XKB_KEY_ISO_Level2_Latch => Key::IsoLevel2Latch, keysyms::XKB_KEY_ISO_Level3_Shift => Key::AltGraph, - // NOTE: I'm not quite certain if mapping the next 2 values to AltGraph is correct. keysyms::XKB_KEY_ISO_Level3_Latch => Key::AltGraph, keysyms::XKB_KEY_ISO_Level3_Lock => Key::AltGraph, // keysyms::XKB_KEY_ISO_Level5_Shift => Key::IsoLevel5Shift, @@ -562,9 +706,9 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { keysyms::XKB_KEY_XF86Calendar => Key::LaunchCalendar, keysyms::XKB_KEY_XF86PowerDown => Key::Power, // keysyms::XKB_KEY_XF86ContrastAdjust => Key::AdjustContrast, - // keysyms::XKB_KEY_XF86RockerUp => Key::RockerUp, // TODO: Use Key::ArrowUp? - // keysyms::XKB_KEY_XF86RockerDown => Key::RockerDown, // TODO: Use Key::ArrowDown? - // keysyms::XKB_KEY_XF86RockerEnter => Key::RockerEnter, // TODO: Use Key::Enter? + // keysyms::XKB_KEY_XF86RockerUp => Key::RockerUp, + // keysyms::XKB_KEY_XF86RockerDown => Key::RockerDown, + // keysyms::XKB_KEY_XF86RockerEnter => Key::RockerEnter, // XFree86 - More "Internet" keysyms::XKB_KEY_XF86Back => Key::BrowserBack, @@ -596,7 +740,7 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { // XKB_KEY_XF86Launch0..XKB_KEY_XF86LaunchF // XKB_KEY_XF86ApplicationLeft..XKB_KEY_XF86CD - keysyms::XKB_KEY_XF86Calculater => Key::LaunchApplication2, // This must be a typo, right? + keysyms::XKB_KEY_XF86Calculater => Key::LaunchApplication2, // Nice typo, libxkbcommon :) // XKB_KEY_XF86Clear keysyms::XKB_KEY_XF86Close => Key::Close, keysyms::XKB_KEY_XF86Copy => Key::Copy, diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 73892f19a9..9a8b1365a4 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -42,7 +42,7 @@ pub mod wayland; pub mod x11; #[cfg(any(feature = "x11", feature = "wayland"))] -mod common; +pub mod common; #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct KeyEventExtra { From 1c3813ea506a85c503f5394af7e06a971ca6473f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Wed, 25 Aug 2021 00:47:28 +0200 Subject: [PATCH 46/53] Implement `reset_dead_keys` (poorly) --- src/platform_impl/linux/common/xkb_state.rs | 42 +++++++++++++++---- src/platform_impl/linux/mod.rs | 3 +- .../linux/x11/event_processor.rs | 9 ++++ 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/platform_impl/linux/common/xkb_state.rs b/src/platform_impl/linux/common/xkb_state.rs index 6cdc335637..b1ff556db4 100644 --- a/src/platform_impl/linux/common/xkb_state.rs +++ b/src/platform_impl/linux/common/xkb_state.rs @@ -5,6 +5,8 @@ use std::fs::File; use std::os::raw::c_char; use std::os::unix::ffi::OsStringExt; use std::ptr; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Mutex; #[cfg(feature = "wayland")] use memmap2::MmapOptions; @@ -25,6 +27,20 @@ use crate::{ keyboard::{Key, KeyCode, KeyLocation}, }; +// TODO: Wire this up without using a static `Mutex>`. +#[cfg(feature = "x11")] +lazy_static! { + pub(crate) static ref X11_EVPROC_NEXT_COMPOSE: Mutex> = Mutex::new(None); +} + +// TODO: Wire this up without using a static `AtomicBool`. +static RESET_DEAD_KEYS: AtomicBool = AtomicBool::new(false); + +#[inline] +pub(crate) fn reset_dead_keys() { + RESET_DEAD_KEYS.store(true, Ordering::SeqCst); +} + pub(crate) struct KbState { #[cfg(feature = "x11")] xcb_connection: *mut xcb_connection_t, @@ -194,6 +210,9 @@ impl KbState { if !self.ready() || self.xkb_compose_state.is_null() { return None; } + if RESET_DEAD_KEYS.swap(false, Ordering::SeqCst) { + unsafe { self.init_compose() }; + } Some(unsafe { (XKBCH.xkb_compose_state_feed)(xkb_compose_state, keysym) }) } @@ -639,13 +658,22 @@ impl<'a> KeyEventResults<'a> { _ => (key, location), } } - _ => ( - self.composed_text() - .unwrap_or_else(|_| self.state.keysym_to_utf8_raw(self.keysym)) - .map(Key::Character) - .unwrap_or(key), - location, - ), + _ => { + let composed_text = self.composed_text(); + + #[cfg(feature = "x11")] + if let Ok(Some(composed_text)) = composed_text { + *X11_EVPROC_NEXT_COMPOSE.lock().unwrap() = Some(composed_text); + } + + ( + composed_text + .unwrap_or_else(|_| self.state.keysym_to_utf8_raw(self.keysym)) + .map(Key::Character) + .unwrap_or(key), + location, + ) + } }) } diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 9a8b1365a4..d2786488db 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -438,8 +438,9 @@ impl Window { x11_or_wayland!(match self; Window(w) => w.set_ime_position(position)) } + #[inline] pub fn reset_dead_keys(&self) { - todo!() + common::xkb_state::reset_dead_keys() } #[inline] diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 053a9821f7..4c398f1e3e 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -546,6 +546,15 @@ impl EventProcessor { } else { return; }; + if super::super::common::xkb_state::X11_EVPROC_NEXT_COMPOSE + .lock() + .unwrap() + .take() + .map(|composed| composed == written) + .unwrap_or(false) + { + return; + } let event = Event::WindowEvent { window_id, event: WindowEvent::ReceivedImeText(written), From 22c090747d06679c908adaf2f1969b9efdcff63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 9 Sep 2021 19:25:57 +0200 Subject: [PATCH 47/53] Split the native XKB keycode enum variant in two `XkbCode` now contains keycodes while `XkbSym` contains keysyms. This may change sooner rather than later. --- src/keyboard.rs | 13 +++++++++---- src/platform_impl/linux/common/keymap.rs | 8 ++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index 80a5aa7922..dce46a6f90 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -175,11 +175,12 @@ pub enum NativeKeyCode { Unidentified, Windows(u16), MacOS(u32), - XKB(u32), + XkbCode(u32), + XkbSym(u32), } impl std::fmt::Debug for NativeKeyCode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use NativeKeyCode::{MacOS, Unidentified, Windows, XKB}; + use NativeKeyCode::{MacOS, Unidentified, Windows, XkbCode, XkbSym}; let mut debug_tuple; match self { Unidentified => { @@ -193,8 +194,12 @@ impl std::fmt::Debug for NativeKeyCode { debug_tuple = f.debug_tuple(name_of!(MacOS)); debug_tuple.field(v); } - XKB(v) => { - debug_tuple = f.debug_tuple(name_of!(XKB)); + XkbCode(v) => { + debug_tuple = f.debug_tuple(name_of!(XkbCode)); + debug_tuple.field(&format_args!("0x{:04X}", v)); + } + XkbSym(v) => { + debug_tuple = f.debug_tuple(name_of!(XkbSym)); debug_tuple.field(&format_args!("0x{:04X}", v)); } } diff --git a/src/platform_impl/linux/common/keymap.rs b/src/platform_impl/linux/common/keymap.rs index 610fc4f38a..8e2e6c2458 100644 --- a/src/platform_impl/linux/common/keymap.rs +++ b/src/platform_impl/linux/common/keymap.rs @@ -16,7 +16,7 @@ pub fn raw_keycode_to_keycode(keycode: u32) -> KeyCode { // difficult to test the correctness of, or discover the purpose of. Because of this, they've // either been commented out here, or not included at all. match rawkey { - 0 => KeyCode::Unidentified(NativeKeyCode::XKB(0)), + 0 => KeyCode::Unidentified(NativeKeyCode::XkbCode(0)), 1 => KeyCode::Escape, 2 => KeyCode::Digit1, 3 => KeyCode::Digit2, @@ -259,14 +259,14 @@ pub fn raw_keycode_to_keycode(keycode: u32) -> KeyCode { // 246 => KeyCode::WWAN, // 247 => KeyCode::RFKILL, // 248 => KeyCode::KEY_MICMUTE, - _ => KeyCode::Unidentified(NativeKeyCode::XKB(rawkey)), + _ => KeyCode::Unidentified(NativeKeyCode::XkbCode(rawkey)), } } pub fn keycode_to_raw(keycode: KeyCode) -> Option { match keycode { KeyCode::Unidentified(NativeKeyCode::Unidentified) => Some(240), - KeyCode::Unidentified(NativeKeyCode::XKB(raw)) => Some(raw), + KeyCode::Unidentified(NativeKeyCode::XkbCode(raw)) => Some(raw), KeyCode::Escape => Some(1), KeyCode::Digit1 => Some(2), KeyCode::Digit2 => Some(3), @@ -827,7 +827,7 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { // XKB_KEY_SunPowerSwitchShift // 0 => Key::Unidentified(NativeKeyCode::Unidentified), - _ => Key::Unidentified(NativeKeyCode::XKB(keysym)), + _ => Key::Unidentified(NativeKeyCode::XkbSym(keysym)), } } From 069da0839038a51ebd31f5793bdc6da9c0556497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 9 Sep 2021 20:41:46 +0200 Subject: [PATCH 48/53] Add a TODO regarding the `ModifiersChanged` event. --- src/platform_impl/linux/x11/event_processor.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 4c398f1e3e..e340c52d1c 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -1129,6 +1129,13 @@ impl EventProcessor { return; } let physical_key = keymap::raw_keycode_to_keycode(keycode); + // TODO: Figure out how redundant this is. + // This is the set of modifiers end users end up seeing. However, the set of + // modifiers used internally by the `KbState` are sourced directly from the XKB + // extension. Since we currently panic when the extension doesn't load, we should + // be able to use the modifiers supplied to us by the XKB extension. This + // requires us to have consensus on what to do if we can't load and initialize + // libxkbcommon. let modifiers = self.device_mod_state.modifiers(); callback(Event::DeviceEvent { @@ -1139,8 +1146,6 @@ impl EventProcessor { }), }); - // `ModifiersChanged` is dispatched here because we assume that every `XI_KeyPress` - // is preceeded by a `XI_RawKeyPress`. if let Some(modifier) = self.mod_keymap.get_modifier(keycode as ffi::KeyCode) { From 5f592443973bb8633065dcc264eebd33dd7327e2 Mon Sep 17 00:00:00 2001 From: Robert Timm Date: Thu, 9 Sep 2021 21:35:46 +0200 Subject: [PATCH 49/53] fix: meta mod key on focus handling for gnome/x11 This patch addresses an issue in the modifier key handling appearing on gnome/x11 while focussing a winit window using a meta/super/logo key shortcut. As soon as the window gained focus via a shortcut using a meta key, gnome/x11 reports a meta modifier as pressed in the focus event, even though it was just released. No key release events were sent afterwards, so the meta modifier remained "stuck" in the winit state. This patch refactors the modifier key handling following this goals: - Only rely on winit's own modifier state tracking for key and focus events, do not mix it with x11's modifier reporting - Track modifiers only via non-raw key events, so winit does not track modifier changes when not focussed - Integrate modifier handling with the synthetic key events mechanism in order to report release of all currently held modifiers when unfocussed and report set for all currently held modifiers when focussed. --- .../linux/x11/event_processor.rs | 93 +++++++++---------- 1 file changed, 43 insertions(+), 50 deletions(-) diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index e340c52d1c..f51c3110b6 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -834,10 +834,6 @@ impl EventProcessor { .focus(xev.event) .expect("Failed to focus input context"); - let modifiers = ModifiersState::from_x11(&xev.mods); - - self.device_mod_state.update_state(&modifiers, None); - if self.active_window != Some(xev.event) { self.active_window = Some(xev.event); @@ -849,12 +845,16 @@ impl EventProcessor { event: Focused(true), }); - if !modifiers.is_empty() { - callback(Event::WindowEvent { - window_id, - event: WindowEvent::ModifiersChanged(modifiers), - }); - } + // Issue key press events for all pressed keys + Self::handle_pressed_keys( + &wt, + window_id, + ElementState::Pressed, + &mut self.kb_state, + &self.mod_keymap, + &mut self.device_mod_state, + &mut callback, + ); // The deviceid for this event is for a keyboard instead of a pointer, // so we have to do a little extra work. @@ -870,7 +870,7 @@ impl EventProcessor { event: CursorMoved { device_id: mkdid(pointer_id), position, - modifiers, + modifiers: self.device_mod_state.modifiers(), }, }); @@ -886,6 +886,7 @@ impl EventProcessor { ); } } + ffi::XI_FocusOut => { let xev: &ffi::XIFocusOutEvent = unsafe { &*(xev.data as *const _) }; if !self.window_exists(xev.event) { @@ -910,11 +911,6 @@ impl EventProcessor { &mut callback, ); - callback(Event::WindowEvent { - window_id, - event: WindowEvent::ModifiersChanged(ModifiersState::empty()), - }); - callback(Event::WindowEvent { window_id, event: Focused(false), @@ -1059,6 +1055,27 @@ impl EventProcessor { let text_with_all_modifiers = ker.text_with_all_modifiers(); let repeat = xkev.flags & ffi::XIKeyRepeat == ffi::XIKeyRepeat; + if let Some(modifier) = + self.mod_keymap.get_modifier(keycode as ffi::KeyCode) + { + let old_modifiers = self.device_mod_state.modifiers(); + + self.device_mod_state.key_event( + state, + keycode as ffi::KeyCode, + modifier, + ); + + if old_modifiers != self.device_mod_state.modifiers() { + callback(Event::WindowEvent { + window_id, + event: WindowEvent::ModifiersChanged( + self.device_mod_state.modifiers(), + ), + }); + } + } + callback(Event::WindowEvent { window_id, event: WindowEvent::KeyboardInput { @@ -1129,14 +1146,6 @@ impl EventProcessor { return; } let physical_key = keymap::raw_keycode_to_keycode(keycode); - // TODO: Figure out how redundant this is. - // This is the set of modifiers end users end up seeing. However, the set of - // modifiers used internally by the `KbState` are sourced directly from the XKB - // extension. Since we currently panic when the extension doesn't load, we should - // be able to use the modifiers supplied to us by the XKB extension. This - // requires us to have consensus on what to do if we can't load and initialize - // libxkbcommon. - let modifiers = self.device_mod_state.modifiers(); callback(Event::DeviceEvent { device_id, @@ -1145,27 +1154,6 @@ impl EventProcessor { state, }), }); - - if let Some(modifier) = - self.mod_keymap.get_modifier(keycode as ffi::KeyCode) - { - self.device_mod_state.key_event( - state, - keycode as ffi::KeyCode, - modifier, - ); - - let new_modifiers = self.device_mod_state.modifiers(); - - if modifiers != new_modifiers { - if let Some(window_id) = self.active_window { - callback(Event::WindowEvent { - window_id: mkwid(window_id), - event: WindowEvent::ModifiersChanged(new_modifiers), - }); - } - } - } } ffi::XI_HierarchyChanged => { @@ -1312,11 +1300,16 @@ impl EventProcessor { let text_with_all_modifiers = ker.text_with_all_modifiers(); if let Some(modifier) = mod_keymap.get_modifier(keycode as ffi::KeyCode) { - device_mod_state.key_event( - ElementState::Pressed, - keycode as ffi::KeyCode, - modifier, - ); + let old_modifiers = device_mod_state.modifiers(); + + device_mod_state.key_event(state, keycode as ffi::KeyCode, modifier); + + if old_modifiers != device_mod_state.modifiers() { + callback(Event::WindowEvent { + window_id, + event: WindowEvent::ModifiersChanged(device_mod_state.modifiers()), + }); + } } callback(Event::WindowEvent { From fd06cbd9026d710753ea7e6029db60bba79d56e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Wed, 6 Oct 2021 18:21:48 +0200 Subject: [PATCH 50/53] Remove the `XkbStateNotify` handler The only thing we did in response to said event is update the `xkb_state`, but we throw that away on every keypress anyway due to the keyeyboard layout change detection hack. This commit also removes associated code which let us recieve and react to the event in the first place. If a fix is ever introduced, then this commit ought to be reverted. --- .../linux/x11/event_processor.rs | 28 ++++------------- src/platform_impl/linux/x11/mod.rs | 31 ------------------- 2 files changed, 6 insertions(+), 53 deletions(-) diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index f51c3110b6..83c93c9606 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, collections::HashMap, convert::identity, rc::Rc, slice, sync::Arc}; +use std::{cell::RefCell, collections::HashMap, rc::Rc, slice, sync::Arc}; use libc::{c_char, c_int, c_long, c_ulong}; @@ -31,7 +31,6 @@ pub(super) struct EventProcessor { pub(super) randr_event_offset: c_int, pub(super) devices: RefCell>, pub(super) xi2ext: XExtension, - pub(super) xkbext: XExtension, pub(super) target: Rc>, pub(super) kb_state: KbState, pub(super) mod_keymap: ModifierKeymap, @@ -1130,6 +1129,11 @@ impl EventProcessor { // keymap on *every* keypress. That's peak efficiency right there! // // FIXME: Someone please save our souls! Or at least our wasted CPU cycles. + // + // If you do manage to find a solution, remember to re-enable (and handle) the + // `XkbStateNotify` event with `XkbSelectEventDetails` with a mask of + // `XkbAllStateComponentsMask & !XkbPointerButtonMask` like in + // . unsafe { self.kb_state.init_with_x11_keymap() }; let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) }; @@ -1183,26 +1187,6 @@ impl EventProcessor { } } _ => { - if event_type == self.xkbext.first_event_id { - let xev = unsafe { &*(identity(xev) as *const _ as *const ffi::XkbAnyEvent) }; - match xev.xkb_type { - ffi::XkbStateNotify => { - let xev = - unsafe { &*(xev as *const _ as *const ffi::XkbStateNotifyEvent) }; - if matches!(xev.event_type as i32, ffi::KeyPress | ffi::KeyRelease) { - self.kb_state.update_modifiers( - xev.base_mods, - xev.latched_mods, - xev.locked_mods, - xev.base_group as u32, - xev.latched_group as u32, - xev.locked_group as u32, - ) - } - } - _ => {} - } - } if event_type == self.randr_event_offset { // In the future, it would be quite easy to emit monitor hotplug events. let prev_list = monitor::invalidate_cached_monitor_list(); diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index d57ef3ce01..9092433986 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -164,27 +164,6 @@ impl EventLoop { ext }; - let xkbext = { - let mut ext = XExtension::default(); - - let res = unsafe { - (xconn.xlib.XkbQueryExtension)( - xconn.display, - &mut ext.opcode, - &mut ext.first_event_id, - &mut ext.first_error_id, - &mut 1, - &mut 0, - ) - }; - - if res == ffi::False { - panic!("X server missing XKB extension"); - } - - ext - }; - unsafe { let mut xinput_major_ver = ffi::XI_2_Major; let mut xinput_minor_ver = ffi::XI_2_Minor; @@ -245,7 +224,6 @@ impl EventLoop { randr_event_offset, ime_receiver, xi2ext, - xkbext, kb_state, mod_keymap, device_mod_state: Default::default(), @@ -261,15 +239,6 @@ impl EventLoop { .select_xinput_events(root, ffi::XIAllDevices, ffi::XI_HierarchyChangedMask) .queue(); - get_xtarget(&target) - .xconn - .select_xkb_events( - 0x100, // Use the "core keyboard device" - ffi::XkbNewKeyboardNotifyMask | ffi::XkbMapNotifyMask | ffi::XkbStateNotifyMask, - ) - .unwrap() - .queue(); - event_processor.init_device(ffi::XIAllDevices); EventLoop { From e6ad0fb6918ce56097ca2f12cf78f4b22d611fc3 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Thu, 21 Oct 2021 11:12:27 +0200 Subject: [PATCH 51/53] X11: Only fetch virtual keyboard events from master devices We must not report virtual keyboard events for keys that were grabbed by other applications (XGrabKey, etc.). Since grabs only affect master devices, we must consume virtual events from master devices only. --- src/platform_impl/linux/x11/mod.rs | 4 +--- src/platform_impl/linux/x11/window.rs | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 9092433986..fcc78e12f8 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -630,9 +630,7 @@ impl Device { | ffi::XI_RawButtonPressMask | ffi::XI_RawButtonReleaseMask | ffi::XI_RawKeyPressMask - | ffi::XI_RawKeyReleaseMask - | ffi::XI_KeyPressMask - | ffi::XI_KeyReleaseMask; + | ffi::XI_RawKeyReleaseMask; // The request buffer is flushed when we poll for events wt.xconn .select_xinput_events(wt.root, info.deviceid, mask) diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index e3525ef521..18c3d4ad15 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -434,8 +434,8 @@ impl UnownedWindow { let mask = ffi::XI_MotionMask | ffi::XI_ButtonPressMask | ffi::XI_ButtonReleaseMask - //| ffi::XI_KeyPressMask - //| ffi::XI_KeyReleaseMask + | ffi::XI_KeyPressMask + | ffi::XI_KeyReleaseMask | ffi::XI_EnterMask | ffi::XI_LeaveMask | ffi::XI_FocusInMask From f3cbfe329f33b2afa7e8e485e832cb13408381ae Mon Sep 17 00:00:00 2001 From: Artur Kovacs Date: Thu, 13 Jan 2022 20:20:26 +0100 Subject: [PATCH 52/53] Add dead-key mappings for keysyms --- src/platform_impl/linux/common/keymap.rs | 77 +++++++++++++++++++++++- src/platform_impl/linux/x11/window.rs | 22 +++---- 2 files changed, 87 insertions(+), 12 deletions(-) diff --git a/src/platform_impl/linux/common/keymap.rs b/src/platform_impl/linux/common/keymap.rs index 8e2e6c2458..9380a23531 100644 --- a/src/platform_impl/linux/common/keymap.rs +++ b/src/platform_impl/linux/common/keymap.rs @@ -622,13 +622,88 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { // keysyms::XKB_KEY_ISO_Center_Object => Key::IsoCenterObject, keysyms::XKB_KEY_ISO_Enter => Key::Enter, - // XKB_KEY_dead_grave..XKB_KEY_dead_currency + keysyms::XKB_KEY_dead_grave => Key::Dead(Some('ˋ')), // 0xfe50 + keysyms::XKB_KEY_dead_acute => Key::Dead(Some('ˊ')), // 0xfe51 + keysyms::XKB_KEY_dead_circumflex => Key::Dead(Some('ˆ')), // 0xfe52 + keysyms::XKB_KEY_dead_tilde => Key::Dead(Some('˜')), // 0xfe53 + // keysyms::XKB_KEY_dead_perispomeni => Key::Dead(None), // 0xfe53 /* alias for dead_tilde */ + keysyms::XKB_KEY_dead_macron => Key::Dead(Some('ˉ')), // 0xfe54 + keysyms::XKB_KEY_dead_breve => Key::Dead(Some('˘')), // 0xfe55 + keysyms::XKB_KEY_dead_abovedot => Key::Dead(Some('˙')), // 0xfe56 + keysyms::XKB_KEY_dead_diaeresis => Key::Dead(Some('¨')), // 0xfe57 + keysyms::XKB_KEY_dead_abovering => Key::Dead(Some('˚')), // 0xfe58 + keysyms::XKB_KEY_dead_doubleacute => Key::Dead(Some('˝')), // 0xfe59 + keysyms::XKB_KEY_dead_caron => Key::Dead(Some('ˇ')), // 0xfe5a + keysyms::XKB_KEY_dead_cedilla => Key::Dead(Some('¸')), // 0xfe5b + keysyms::XKB_KEY_dead_ogonek => Key::Dead(Some('˛')), // 0xfe5c + + // It's None because there doesn't seem to be a spacing version of the iota character, + // only a combining version. But winit always reports non-combining characters for + // dead-keys, mostly for platform consistency with Windows + keysyms::XKB_KEY_dead_iota => Key::Dead(None), // 0xfe5d + + keysyms::XKB_KEY_dead_voiced_sound => Key::Dead(Some('゛')), // 0xfe5e + keysyms::XKB_KEY_dead_semivoiced_sound => Key::Dead(Some('゜')), // 0xfe5f + keysyms::XKB_KEY_dead_belowdot => Key::Dead(Some('.')), // 0xfe60 + + // Combining version is U+0309. No spacing version. See: XKB_KEY_dead_iota + keysyms::XKB_KEY_dead_hook => Key::Dead(None), // 0xfe61 + + // Combining version is U+031B. No spacing version. See: XKB_KEY_dead_iota + keysyms::XKB_KEY_dead_horn => Key::Dead(None), // 0xfe62 + + // Combining version is U+0338. No spacing version. See: XKB_KEY_dead_iota + keysyms::XKB_KEY_dead_stroke => Key::Dead(None), // 0xfe63 + + keysyms::XKB_KEY_dead_abovecomma => Key::Dead(Some('ʼ')), // 0xfe64 + // keysyms::XKB_KEY_dead_psili => Key::Dead(None), // 0xfe64 /* alias for dead_abovecomma */ + keysyms::XKB_KEY_dead_abovereversedcomma => Key::Dead(Some('ʽ')), // 0xfe65 + // keysyms::XKB_KEY_dead_dasia => Key::Dead(Some('')), // 0xfe65 /* alias for dead_abovereversedcomma */ + + // Combining version is U+030F. No spacing version. See: XKB_KEY_dead_iota + keysyms::XKB_KEY_dead_doublegrave => Key::Dead(None), // 0xfe66 + + keysyms::XKB_KEY_dead_belowring => Key::Dead(Some('˳')), // 0xfe67 + keysyms::XKB_KEY_dead_belowmacron => Key::Dead(Some('ˍ')), // 0xfe68 + keysyms::XKB_KEY_dead_belowcircumflex => Key::Dead(Some('˰')), // 0xfe69 + keysyms::XKB_KEY_dead_belowtilde => Key::Dead(Some('˷')), // 0xfe6a + + // Combining version is U+032E. No spacing version. See: XKB_KEY_dead_iota + keysyms::XKB_KEY_dead_belowbreve => Key::Dead(None), // 0xfe6b + + // Combining version is U+0324. No spacing version. See: XKB_KEY_dead_iota + keysyms::XKB_KEY_dead_belowdiaeresis => Key::Dead(None), // 0xfe6c + + // Combining version is U+0311. No spacing version. See: XKB_KEY_dead_iota + keysyms::XKB_KEY_dead_invertedbreve => Key::Dead(None), // 0xfe6d + + keysyms::XKB_KEY_dead_belowcomma => Key::Dead(Some(',')), // 0xfe6e + keysyms::XKB_KEY_dead_currency => Key::Dead(Some('¤')), // 0xfe6f // XKB_KEY_dead_lowline..XKB_KEY_dead_longsolidusoverlay // XKB_KEY_dead_a..XKB_KEY_dead_capital_schwa // XKB_KEY_dead_greek + keysyms::XKB_KEY_dead_lowline => Key::Dead(Some('_')), // 0xfe90 + keysyms::XKB_KEY_dead_aboveverticalline => Key::Dead(Some('ˈ')), // 0xfe91 + keysyms::XKB_KEY_dead_belowverticalline => Key::Dead(Some('ˌ')), // 0xfe92 + keysyms::XKB_KEY_dead_longsolidusoverlay => Key::Dead(Some('/')), // 0xfe93 + keysyms::XKB_KEY_dead_a => Key::Dead(Some('a')), // 0xfe80 + keysyms::XKB_KEY_dead_A => Key::Dead(Some('A')), // 0xfe81 + keysyms::XKB_KEY_dead_e => Key::Dead(Some('e')), // 0xfe82 + keysyms::XKB_KEY_dead_E => Key::Dead(Some('E')), // 0xfe83 + keysyms::XKB_KEY_dead_i => Key::Dead(Some('i')), // 0xfe84 + keysyms::XKB_KEY_dead_I => Key::Dead(Some('I')), // 0xfe85 + keysyms::XKB_KEY_dead_o => Key::Dead(Some('o')), // 0xfe86 + keysyms::XKB_KEY_dead_O => Key::Dead(Some('O')), // 0xfe87 + keysyms::XKB_KEY_dead_u => Key::Dead(Some('u')), // 0xfe88 + keysyms::XKB_KEY_dead_U => Key::Dead(Some('U')), // 0xfe89 + keysyms::XKB_KEY_dead_small_schwa => Key::Dead(Some('ᵊ')), // 0xfe8a + keysyms::XKB_KEY_dead_capital_schwa => Key::Dead(Some('Ə')), // 0xfe8b + + // GREEK QUESTION MARK - Not semicolon + keysyms::XKB_KEY_dead_greek => Key::Dead(Some(';')), // 0xfe8c // XKB_KEY_First_Virtual_Screen..XKB_KEY_Terminate_Server diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index 18c3d4ad15..e32d1dfadc 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -432,17 +432,17 @@ impl UnownedWindow { // Select XInput2 events let mask = ffi::XI_MotionMask - | ffi::XI_ButtonPressMask - | ffi::XI_ButtonReleaseMask - | ffi::XI_KeyPressMask - | ffi::XI_KeyReleaseMask - | ffi::XI_EnterMask - | ffi::XI_LeaveMask - | ffi::XI_FocusInMask - | ffi::XI_FocusOutMask - | ffi::XI_TouchBeginMask - | ffi::XI_TouchUpdateMask - | ffi::XI_TouchEndMask; + | ffi::XI_ButtonPressMask + | ffi::XI_ButtonReleaseMask + | ffi::XI_KeyPressMask + | ffi::XI_KeyReleaseMask + | ffi::XI_EnterMask + | ffi::XI_LeaveMask + | ffi::XI_FocusInMask + | ffi::XI_FocusOutMask + | ffi::XI_TouchBeginMask + | ffi::XI_TouchUpdateMask + | ffi::XI_TouchEndMask; xconn .select_xinput_events(window.xwindow, ffi::XIAllMasterDevices, mask) .queue(); From 2095e406de813ef5ca0525076f92976a1e29dc6d Mon Sep 17 00:00:00 2001 From: Artur Kovacs Date: Thu, 13 Jan 2022 23:02:48 +0100 Subject: [PATCH 53/53] Remove unnecessary stuff --- src/platform_impl/linux/common/keymap.rs | 113 +++++++++++------------ 1 file changed, 54 insertions(+), 59 deletions(-) diff --git a/src/platform_impl/linux/common/keymap.rs b/src/platform_impl/linux/common/keymap.rs index 9380a23531..b378ad4300 100644 --- a/src/platform_impl/linux/common/keymap.rs +++ b/src/platform_impl/linux/common/keymap.rs @@ -622,88 +622,83 @@ pub fn keysym_to_key(keysym: u32) -> Key<'static> { // keysyms::XKB_KEY_ISO_Center_Object => Key::IsoCenterObject, keysyms::XKB_KEY_ISO_Enter => Key::Enter, - keysyms::XKB_KEY_dead_grave => Key::Dead(Some('ˋ')), // 0xfe50 - keysyms::XKB_KEY_dead_acute => Key::Dead(Some('ˊ')), // 0xfe51 - keysyms::XKB_KEY_dead_circumflex => Key::Dead(Some('ˆ')), // 0xfe52 - keysyms::XKB_KEY_dead_tilde => Key::Dead(Some('˜')), // 0xfe53 - // keysyms::XKB_KEY_dead_perispomeni => Key::Dead(None), // 0xfe53 /* alias for dead_tilde */ - keysyms::XKB_KEY_dead_macron => Key::Dead(Some('ˉ')), // 0xfe54 - keysyms::XKB_KEY_dead_breve => Key::Dead(Some('˘')), // 0xfe55 - keysyms::XKB_KEY_dead_abovedot => Key::Dead(Some('˙')), // 0xfe56 - keysyms::XKB_KEY_dead_diaeresis => Key::Dead(Some('¨')), // 0xfe57 - keysyms::XKB_KEY_dead_abovering => Key::Dead(Some('˚')), // 0xfe58 - keysyms::XKB_KEY_dead_doubleacute => Key::Dead(Some('˝')), // 0xfe59 - keysyms::XKB_KEY_dead_caron => Key::Dead(Some('ˇ')), // 0xfe5a - keysyms::XKB_KEY_dead_cedilla => Key::Dead(Some('¸')), // 0xfe5b - keysyms::XKB_KEY_dead_ogonek => Key::Dead(Some('˛')), // 0xfe5c + keysyms::XKB_KEY_dead_grave => Key::Dead(Some('ˋ')), + keysyms::XKB_KEY_dead_acute => Key::Dead(Some('ˊ')), + keysyms::XKB_KEY_dead_circumflex => Key::Dead(Some('ˆ')), + keysyms::XKB_KEY_dead_tilde => Key::Dead(Some('˜')), + // keysyms::XKB_KEY_dead_perispomeni => Key::Dead(None), /* alias for dead_tilde */ + keysyms::XKB_KEY_dead_macron => Key::Dead(Some('ˉ')), + keysyms::XKB_KEY_dead_breve => Key::Dead(Some('˘')), + keysyms::XKB_KEY_dead_abovedot => Key::Dead(Some('˙')), + keysyms::XKB_KEY_dead_diaeresis => Key::Dead(Some('¨')), + keysyms::XKB_KEY_dead_abovering => Key::Dead(Some('˚')), + keysyms::XKB_KEY_dead_doubleacute => Key::Dead(Some('˝')), + keysyms::XKB_KEY_dead_caron => Key::Dead(Some('ˇ')), + keysyms::XKB_KEY_dead_cedilla => Key::Dead(Some('¸')), + keysyms::XKB_KEY_dead_ogonek => Key::Dead(Some('˛')), // It's None because there doesn't seem to be a spacing version of the iota character, // only a combining version. But winit always reports non-combining characters for // dead-keys, mostly for platform consistency with Windows - keysyms::XKB_KEY_dead_iota => Key::Dead(None), // 0xfe5d + keysyms::XKB_KEY_dead_iota => Key::Dead(None), - keysyms::XKB_KEY_dead_voiced_sound => Key::Dead(Some('゛')), // 0xfe5e - keysyms::XKB_KEY_dead_semivoiced_sound => Key::Dead(Some('゜')), // 0xfe5f - keysyms::XKB_KEY_dead_belowdot => Key::Dead(Some('.')), // 0xfe60 + keysyms::XKB_KEY_dead_voiced_sound => Key::Dead(Some('゛')), + keysyms::XKB_KEY_dead_semivoiced_sound => Key::Dead(Some('゜')), + keysyms::XKB_KEY_dead_belowdot => Key::Dead(Some('.')), // Combining version is U+0309. No spacing version. See: XKB_KEY_dead_iota - keysyms::XKB_KEY_dead_hook => Key::Dead(None), // 0xfe61 + keysyms::XKB_KEY_dead_hook => Key::Dead(None), // Combining version is U+031B. No spacing version. See: XKB_KEY_dead_iota - keysyms::XKB_KEY_dead_horn => Key::Dead(None), // 0xfe62 + keysyms::XKB_KEY_dead_horn => Key::Dead(None), // Combining version is U+0338. No spacing version. See: XKB_KEY_dead_iota - keysyms::XKB_KEY_dead_stroke => Key::Dead(None), // 0xfe63 + keysyms::XKB_KEY_dead_stroke => Key::Dead(None), - keysyms::XKB_KEY_dead_abovecomma => Key::Dead(Some('ʼ')), // 0xfe64 - // keysyms::XKB_KEY_dead_psili => Key::Dead(None), // 0xfe64 /* alias for dead_abovecomma */ - keysyms::XKB_KEY_dead_abovereversedcomma => Key::Dead(Some('ʽ')), // 0xfe65 - // keysyms::XKB_KEY_dead_dasia => Key::Dead(Some('')), // 0xfe65 /* alias for dead_abovereversedcomma */ + keysyms::XKB_KEY_dead_abovecomma => Key::Dead(Some('ʼ')), + // keysyms::XKB_KEY_dead_psili => Key::Dead(None), /* alias for dead_abovecomma */ + keysyms::XKB_KEY_dead_abovereversedcomma => Key::Dead(Some('ʽ')), + // keysyms::XKB_KEY_dead_dasia => Key::Dead(Some('')), /* alias for dead_abovereversedcomma */ // Combining version is U+030F. No spacing version. See: XKB_KEY_dead_iota - keysyms::XKB_KEY_dead_doublegrave => Key::Dead(None), // 0xfe66 + keysyms::XKB_KEY_dead_doublegrave => Key::Dead(None), - keysyms::XKB_KEY_dead_belowring => Key::Dead(Some('˳')), // 0xfe67 - keysyms::XKB_KEY_dead_belowmacron => Key::Dead(Some('ˍ')), // 0xfe68 - keysyms::XKB_KEY_dead_belowcircumflex => Key::Dead(Some('˰')), // 0xfe69 - keysyms::XKB_KEY_dead_belowtilde => Key::Dead(Some('˷')), // 0xfe6a + keysyms::XKB_KEY_dead_belowring => Key::Dead(Some('˳')), + keysyms::XKB_KEY_dead_belowmacron => Key::Dead(Some('ˍ')), + keysyms::XKB_KEY_dead_belowcircumflex => Key::Dead(Some('˰')), + keysyms::XKB_KEY_dead_belowtilde => Key::Dead(Some('˷')), // Combining version is U+032E. No spacing version. See: XKB_KEY_dead_iota - keysyms::XKB_KEY_dead_belowbreve => Key::Dead(None), // 0xfe6b + keysyms::XKB_KEY_dead_belowbreve => Key::Dead(None), // Combining version is U+0324. No spacing version. See: XKB_KEY_dead_iota - keysyms::XKB_KEY_dead_belowdiaeresis => Key::Dead(None), // 0xfe6c + keysyms::XKB_KEY_dead_belowdiaeresis => Key::Dead(None), // Combining version is U+0311. No spacing version. See: XKB_KEY_dead_iota - keysyms::XKB_KEY_dead_invertedbreve => Key::Dead(None), // 0xfe6d - - keysyms::XKB_KEY_dead_belowcomma => Key::Dead(Some(',')), // 0xfe6e - keysyms::XKB_KEY_dead_currency => Key::Dead(Some('¤')), // 0xfe6f - - // XKB_KEY_dead_lowline..XKB_KEY_dead_longsolidusoverlay - - // XKB_KEY_dead_a..XKB_KEY_dead_capital_schwa - - // XKB_KEY_dead_greek - keysyms::XKB_KEY_dead_lowline => Key::Dead(Some('_')), // 0xfe90 - keysyms::XKB_KEY_dead_aboveverticalline => Key::Dead(Some('ˈ')), // 0xfe91 - keysyms::XKB_KEY_dead_belowverticalline => Key::Dead(Some('ˌ')), // 0xfe92 - keysyms::XKB_KEY_dead_longsolidusoverlay => Key::Dead(Some('/')), // 0xfe93 - keysyms::XKB_KEY_dead_a => Key::Dead(Some('a')), // 0xfe80 - keysyms::XKB_KEY_dead_A => Key::Dead(Some('A')), // 0xfe81 - keysyms::XKB_KEY_dead_e => Key::Dead(Some('e')), // 0xfe82 - keysyms::XKB_KEY_dead_E => Key::Dead(Some('E')), // 0xfe83 - keysyms::XKB_KEY_dead_i => Key::Dead(Some('i')), // 0xfe84 - keysyms::XKB_KEY_dead_I => Key::Dead(Some('I')), // 0xfe85 - keysyms::XKB_KEY_dead_o => Key::Dead(Some('o')), // 0xfe86 - keysyms::XKB_KEY_dead_O => Key::Dead(Some('O')), // 0xfe87 - keysyms::XKB_KEY_dead_u => Key::Dead(Some('u')), // 0xfe88 - keysyms::XKB_KEY_dead_U => Key::Dead(Some('U')), // 0xfe89 - keysyms::XKB_KEY_dead_small_schwa => Key::Dead(Some('ᵊ')), // 0xfe8a - keysyms::XKB_KEY_dead_capital_schwa => Key::Dead(Some('Ə')), // 0xfe8b + keysyms::XKB_KEY_dead_invertedbreve => Key::Dead(None), + + keysyms::XKB_KEY_dead_belowcomma => Key::Dead(Some(',')), + keysyms::XKB_KEY_dead_currency => Key::Dead(Some('¤')), + + keysyms::XKB_KEY_dead_lowline => Key::Dead(Some('_')), + keysyms::XKB_KEY_dead_aboveverticalline => Key::Dead(Some('ˈ')), + keysyms::XKB_KEY_dead_belowverticalline => Key::Dead(Some('ˌ')), + keysyms::XKB_KEY_dead_longsolidusoverlay => Key::Dead(Some('/')), + keysyms::XKB_KEY_dead_a => Key::Dead(Some('a')), + keysyms::XKB_KEY_dead_A => Key::Dead(Some('A')), + keysyms::XKB_KEY_dead_e => Key::Dead(Some('e')), + keysyms::XKB_KEY_dead_E => Key::Dead(Some('E')), + keysyms::XKB_KEY_dead_i => Key::Dead(Some('i')), + keysyms::XKB_KEY_dead_I => Key::Dead(Some('I')), + keysyms::XKB_KEY_dead_o => Key::Dead(Some('o')), + keysyms::XKB_KEY_dead_O => Key::Dead(Some('O')), + keysyms::XKB_KEY_dead_u => Key::Dead(Some('u')), + keysyms::XKB_KEY_dead_U => Key::Dead(Some('U')), + keysyms::XKB_KEY_dead_small_schwa => Key::Dead(Some('ᵊ')), + keysyms::XKB_KEY_dead_capital_schwa => Key::Dead(Some('Ə')), // GREEK QUESTION MARK - Not semicolon - keysyms::XKB_KEY_dead_greek => Key::Dead(Some(';')), // 0xfe8c + keysyms::XKB_KEY_dead_greek => Key::Dead(Some(';')), // XKB_KEY_First_Virtual_Screen..XKB_KEY_Terminate_Server