diff --git a/Cargo.toml b/Cargo.toml index 89ed55e3..1d707719 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,15 +50,18 @@ kernel32-sys = "0.1" [target.i686-unknown-linux-gnu.dependencies] osmesa-sys = "0.0.5" -wayland-client = "0.1.5" +wayland-client = "0.1.6" +wayland-kbd = "0.1.1" x11-dl = "=1.0.1" [target.x86_64-unknown-linux-gnu.dependencies] osmesa-sys = "0.0.5" -wayland-client = "0.1.5" +wayland-client = "0.1.6" +wayland-kbd = "0.1.1" x11-dl = "=1.0.1" [target.arm-unknown-linux-gnueabihf.dependencies] osmesa-sys = "0.0.5" -wayland-client = "0.1.5" +wayland-client = "0.1.6" +wayland-kbd = "0.1.1" x11-dl = "=1.0.1" diff --git a/src/api/wayland/context.rs b/src/api/wayland/context.rs index 44a1f518..3b6c0b86 100644 --- a/src/api/wayland/context.rs +++ b/src/api/wayland/context.rs @@ -1,10 +1,21 @@ -use super::wayland::core::{Display, Registry, Compositor, Shell, Output, - Seat, Pointer, default_display, WSurface, SurfaceId}; +use super::wayland::core::{Display, Registry, Compositor, Shell, Output, ButtonState, + Seat, Pointer, default_display, WSurface, SurfaceId, Keyboard, + KeyState}; +use super::wayland_kbd::MappedKeyboard; +use super::keyboard::keycode_to_vkey; + use std::collections::{VecDeque, HashMap}; use std::sync::{Arc, Mutex}; use Event; +use MouseButton; +use ElementState; + +enum AnyKeyboard { + RawKeyBoard(Keyboard), + XKB(MappedKeyboard) +} pub struct WaylandContext { pub display: Display, @@ -13,8 +24,10 @@ pub struct WaylandContext { pub shell: Shell, pub seat: Seat, pub pointer: Option>, + keyboard: Option, windows_event_queues: Arc>>>>>, current_pointer_surface: Arc>>, + current_keyboard_surface: Arc>>, pub outputs: Vec> } @@ -50,7 +63,7 @@ impl WaylandContext { HashMap::>>>::new() )); - // handle inputs + // handle pointer inputs let mut pointer = seat.get_pointer(); if let Some(ref mut p) = pointer { // set the enter/leave callbacks @@ -78,9 +91,6 @@ impl WaylandContext { let current_surface = current_pointer_surface.clone(); let event_queues = windows_event_queues.clone(); p.set_button_action(move |_, sid, b, s| { - use super::wayland::core::ButtonState; - use MouseButton; - use ElementState; let button = match b { 0x110 => MouseButton::Left, 0x111 => MouseButton::Right, @@ -101,6 +111,83 @@ impl WaylandContext { } }); } + + // handle keyboard inputs + let mut keyboard = None; + let current_keyboard_surface = Arc::new(Mutex::new(None)); + if let Some(mut wkbd) = seat.get_keyboard() { + display.sync_roundtrip(); + + let current_surface = current_keyboard_surface.clone(); + wkbd.set_enter_action(move |_, sid, _| { + *current_surface.lock().unwrap() = Some(sid); + }); + let current_surface = current_keyboard_surface.clone(); + wkbd.set_leave_action(move |_, sid| { + *current_surface.lock().unwrap() = None; + }); + + let kbd = match MappedKeyboard::new(wkbd) { + Ok(mkbd) => { + // We managed to load a keymap + let current_surface = current_keyboard_surface.clone(); + let event_queues = windows_event_queues.clone(); + mkbd.set_key_action(move |state, _, _, keycode, keystate| { + let kstate = match keystate { + KeyState::WL_KEYBOARD_KEY_STATE_RELEASED => ElementState::Released, + KeyState::WL_KEYBOARD_KEY_STATE_PRESSED => ElementState::Pressed + }; + let mut events = Vec::new(); + // key event + events.push(Event::KeyboardInput( + kstate, + (keycode & 0xff) as u8, + keycode_to_vkey(state, keycode) + )); + // utf8 events + if kstate == ElementState::Pressed { + if let Some(txt) = state.get_utf8(keycode) { + events.extend( + txt.chars().map(Event::ReceivedCharacter) + ); + } + } + // dispatch to the appropriate queue + let sid = *current_surface.lock().unwrap(); + if let Some(sid) = sid { + let map = event_queues.lock().unwrap(); + if let Some(queue) = map.get(&sid) { + queue.lock().unwrap().extend(events.into_iter()); + } + } + }); + AnyKeyboard::XKB(mkbd) + }, + Err(mut rkbd) => { + // fallback to raw inputs, no virtual keycodes + let current_surface = current_keyboard_surface.clone(); + let event_queues = windows_event_queues.clone(); + rkbd.set_key_action(move |_, _, keycode, keystate| { + let kstate = match keystate { + KeyState::WL_KEYBOARD_KEY_STATE_RELEASED => ElementState::Released, + KeyState::WL_KEYBOARD_KEY_STATE_PRESSED => ElementState::Pressed + }; + let event = Event::KeyboardInput(kstate, (keycode & 0xff) as u8, None); + // dispatch to the appropriate queue + let sid = *current_surface.lock().unwrap(); + if let Some(sid) = sid { + let map = event_queues.lock().unwrap(); + if let Some(queue) = map.get(&sid) { + queue.lock().unwrap().push_back(event); + } + } + }); + AnyKeyboard::RawKeyBoard(rkbd) + } + }; + keyboard = Some(kbd); + } + Some(WaylandContext { display: display, registry: registry, @@ -108,8 +195,10 @@ impl WaylandContext { shell: shell, seat: seat, pointer: pointer, + keyboard: keyboard, windows_event_queues: windows_event_queues, current_pointer_surface: current_pointer_surface, + current_keyboard_surface: current_keyboard_surface, outputs: outputs }) } diff --git a/src/api/wayland/keyboard.rs b/src/api/wayland/keyboard.rs new file mode 100644 index 00000000..911e897e --- /dev/null +++ b/src/api/wayland/keyboard.rs @@ -0,0 +1,170 @@ +use super::wayland_kbd::{KbState, keysyms}; + +use VirtualKeyCode; + +pub fn keycode_to_vkey(state: &KbState, keycode: u32) -> Option { + // first line is hard-coded because it must be case insensitive + // and is a linux constant anyway + match keycode { + 1 => return Some(VirtualKeyCode::Escape), + 2 => return Some(VirtualKeyCode::Key1), + 3 => return Some(VirtualKeyCode::Key2), + 4 => return Some(VirtualKeyCode::Key3), + 5 => return Some(VirtualKeyCode::Key4), + 6 => return Some(VirtualKeyCode::Key5), + 7 => return Some(VirtualKeyCode::Key6), + 8 => return Some(VirtualKeyCode::Key7), + 9 => return Some(VirtualKeyCode::Key8), + 10 => return Some(VirtualKeyCode::Key9), + 11 => return Some(VirtualKeyCode::Key0), + _ => {} + } + // for other keys, we use the keysym + return match state.get_one_sym(keycode) { + // 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), + // F-- + 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), + // 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), + // + keysyms::XKB_KEY_BackSpace => Some(VirtualKeyCode::Back), + keysyms::XKB_KEY_Return => Some(VirtualKeyCode::Return), + keysyms::XKB_KEY_space => Some(VirtualKeyCode::Space), + // 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::Add), + keysyms::XKB_KEY_apostrophe => Some(VirtualKeyCode::Apostrophe), + // => Some(VirtualKeyCode::Apps), + // => Some(VirtualKeyCode::At), + // => Some(VirtualKeyCode::Ax), + keysyms::XKB_KEY_backslash => Some(VirtualKeyCode::Backslash), + // => Some(VirtualKeyCode::Calculator), + // => Some(VirtualKeyCode::Capital), + keysyms::XKB_KEY_colon => Some(VirtualKeyCode::Colon), + keysyms::XKB_KEY_comma => Some(VirtualKeyCode::Comma), + // => Some(VirtualKeyCode::Convert), + // => Some(VirtualKeyCode::Decimal), + // => Some(VirtualKeyCode::Divide), + keysyms::XKB_KEY_equal => Some(VirtualKeyCode::Equals), + // => Some(VirtualKeyCode::Grave), + // => Some(VirtualKeyCode::Kana), + // => Some(VirtualKeyCode::Kanji), + keysyms::XKB_KEY_Alt_L => Some(VirtualKeyCode::LAlt), + // => Some(VirtualKeyCode::LBracket), + keysyms::XKB_KEY_Control_L => Some(VirtualKeyCode::LControl), + // => Some(VirtualKeyCode::LMenu), + keysyms::XKB_KEY_Shift_L => Some(VirtualKeyCode::LShift), + // => Some(VirtualKeyCode::LWin), + // => Some(VirtualKeyCode::Mail), + // => Some(VirtualKeyCode::MediaSelect), + // => Some(VirtualKeyCode::MediaStop), + keysyms::XKB_KEY_minus => Some(VirtualKeyCode::Minus), + keysyms::XKB_KEY_asterisk => Some(VirtualKeyCode::Multiply), + // => Some(VirtualKeyCode::Mute), + // => Some(VirtualKeyCode::MyComputer), + // => 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), + // => Some(VirtualKeyCode::OEM102), + // => Some(VirtualKeyCode::Period), + // => Some(VirtualKeyCode::Playpause), + // => Some(VirtualKeyCode::Power), + // => Some(VirtualKeyCode::Prevtrack), + keysyms::XKB_KEY_Alt_R => Some(VirtualKeyCode::RAlt), + // => Some(VirtualKeyCode::RBracket), + keysyms::XKB_KEY_Control_R => Some(VirtualKeyCode::RControl), + // => Some(VirtualKeyCode::RMenu), + keysyms::XKB_KEY_Shift_R => Some(VirtualKeyCode::RShift), + // => Some(VirtualKeyCode::RWin), + keysyms::XKB_KEY_semicolon => Some(VirtualKeyCode::Semicolon), + keysyms::XKB_KEY_slash => Some(VirtualKeyCode::Slash), + // => Some(VirtualKeyCode::Sleep), + // => Some(VirtualKeyCode::Stop), + // => Some(VirtualKeyCode::Subtract), + // => Some(VirtualKeyCode::Sysrq), + keysyms::XKB_KEY_Tab => Some(VirtualKeyCode::Tab), + // => 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), + // => Some(VirtualKeyCode::Yen), + // fallback + _ => None + } +} \ No newline at end of file diff --git a/src/api/wayland/mod.rs b/src/api/wayland/mod.rs index 569f93f9..8a4b5cc2 100644 --- a/src/api/wayland/mod.rs +++ b/src/api/wayland/mod.rs @@ -25,8 +25,10 @@ use platform::MonitorID as PlatformMonitorID; use self::context::WaylandContext; extern crate wayland_client as wayland; +extern crate wayland_kbd; mod context; +mod keyboard; lazy_static! { static ref WAYLAND_CONTEXT: Option = {