From e4e53fe3152d003b0fac9c10d463e7e74cca9455 Mon Sep 17 00:00:00 2001 From: trimental <40879396+trimental@users.noreply.github.com> Date: Mon, 20 Aug 2018 05:17:40 +0800 Subject: [PATCH] Add key repetition for the wayland backend (#628) * Add key repetition for the wayland backend * Upgrade smithay-client-toolkit to 0.3.0 --- CHANGELOG.md | 1 + Cargo.toml | 2 +- src/platform/linux/wayland/event_loop.rs | 35 +++--- src/platform/linux/wayland/keyboard.rs | 131 ++++++++++++++--------- 4 files changed, 107 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c18e3865..68aa8113 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - On macOS, fix `` so applications receive the event. - On macOS, fix `` so applications receive the event. +- On Wayland, key press events will now be repeated. # Version 0.17.1 (2018-08-05) diff --git a/Cargo.toml b/Cargo.toml index 28303ca6..66d4a57b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,7 @@ features = [ [target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies] wayland-client = { version = "0.20.10", features = [ "dlopen", "egl", "cursor"] } -smithay-client-toolkit = "0.2.6" +smithay-client-toolkit = "0.3.0" x11-dl = "2.18.3" parking_lot = "0.6" percent-encoding = "1.0" diff --git a/src/platform/linux/wayland/event_loop.rs b/src/platform/linux/wayland/event_loop.rs index 9efa307e..cf6b7b2a 100644 --- a/src/platform/linux/wayland/event_loop.rs +++ b/src/platform/linux/wayland/event_loop.rs @@ -1,20 +1,21 @@ use std::cell::RefCell; use std::collections::VecDeque; use std::fmt; -use std::sync::{Arc, Mutex, Weak}; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex, Weak}; use {ControlFlow, EventsLoopClosed, PhysicalPosition, PhysicalSize}; -use super::WindowId; use super::window::WindowStore; +use super::WindowId; -use sctk::Environment; use sctk::output::OutputMgr; -use sctk::reexports::client::{Display, EventQueue, GlobalEvent, Proxy, ConnectError}; use sctk::reexports::client::commons::Implementation; -use sctk::reexports::client::protocol::{wl_keyboard, wl_output, wl_pointer, wl_registry, wl_seat, - wl_touch}; +use sctk::reexports::client::protocol::{ + wl_keyboard, wl_output, wl_pointer, wl_registry, wl_seat, wl_touch, +}; +use sctk::reexports::client::{ConnectError, Display, EventQueue, GlobalEvent, Proxy}; +use sctk::Environment; use sctk::reexports::client::protocol::wl_display::RequestsTrait as DisplayRequests; @@ -104,6 +105,8 @@ impl EventsLoop { pub fn new() -> Result { let (display, mut event_queue) = Display::connect_to_env()?; + let display = Arc::new(display); + let pending_wakeup = Arc::new(AtomicBool::new(false)); let sink = Arc::new(Mutex::new(EventsLoopSink::new())); let store = Arc::new(Mutex::new(WindowStore::new())); let seats = Arc::new(Mutex::new(Vec::new())); @@ -115,18 +118,22 @@ impl EventsLoop { sink: sink.clone(), store: store.clone(), seats: seats.clone(), + events_loop_proxy: EventsLoopProxy { + display: Arc::downgrade(&display), + pending_wakeup: Arc::downgrade(&pending_wakeup), + }, }, ).unwrap(); Ok(EventsLoop { - display: Arc::new(display), + display, evq: RefCell::new(event_queue), - sink: sink, - pending_wakeup: Arc::new(AtomicBool::new(false)), - store: store, - env: env, + sink, + pending_wakeup, + store, + env, cleanup_needed: Arc::new(Mutex::new(false)), - seats: seats, + seats, }) } @@ -266,6 +273,7 @@ struct SeatManager { sink: Arc>, store: Arc>, seats: Arc)>>>, + events_loop_proxy: EventsLoopProxy, } impl Implementation, GlobalEvent> for SeatManager { @@ -289,6 +297,7 @@ impl Implementation, GlobalEvent> for SeatManager pointer: None, keyboard: None, touch: None, + events_loop_proxy: self.events_loop_proxy.clone(), }); self.store.lock().unwrap().new_seat(&seat); self.seats.lock().unwrap().push((id, seat)); @@ -313,6 +322,7 @@ struct SeatData { pointer: Option>, keyboard: Option>, touch: Option>, + events_loop_proxy: EventsLoopProxy, } impl Implementation, wl_seat::Event> for SeatData { @@ -343,6 +353,7 @@ impl Implementation, wl_seat::Event> for SeatData { self.keyboard = Some(super::keyboard::init_keyboard( seat.get_keyboard().unwrap(), self.sink.clone(), + self.events_loop_proxy.clone(), )) } // destroy keyboard if applicable diff --git a/src/platform/linux/wayland/keyboard.rs b/src/platform/linux/wayland/keyboard.rs index d0d28e81..471aa4f1 100644 --- a/src/platform/linux/wayland/keyboard.rs +++ b/src/platform/linux/wayland/keyboard.rs @@ -1,77 +1,110 @@ use std::sync::{Arc, Mutex}; -use {ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent}; - -use super::{make_wid, DeviceId, EventsLoopSink}; -use sctk::keyboard::{self, map_keyboard_auto, Event as KbEvent}; -use sctk::reexports::client::{NewProxy, Proxy}; +use super::{make_wid, DeviceId, EventsLoopProxy, EventsLoopSink}; +use sctk::keyboard::{ + self, map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatEvent, KeyRepeatKind, +}; use sctk::reexports::client::protocol::wl_keyboard; +use sctk::reexports::client::{NewProxy, Proxy}; +use {ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent}; pub fn init_keyboard( keyboard: NewProxy, sink: Arc>, + events_loop_proxy: EventsLoopProxy, ) -> Proxy { - // { variables to be captured by the closure - let mut target = None; + // { variables to be captured by the closures + let target = Arc::new(Mutex::new(None)); let my_sink = sink.clone(); + let repeat_sink = sink.clone(); + let repeat_target = target.clone(); // } - let ret = map_keyboard_auto(keyboard, move |evt: KbEvent, _| match evt { - KbEvent::Enter { surface, .. } => { - let wid = make_wid(&surface); - my_sink - .lock() - .unwrap() - .send_event(WindowEvent::Focused(true), wid); - target = Some(wid); - } - KbEvent::Leave { surface, .. } => { - let wid = make_wid(&surface); - my_sink - .lock() - .unwrap() - .send_event(WindowEvent::Focused(false), wid); - target = None; - } - KbEvent::Key { - modifiers, - rawkey, - keysym, - state, - utf8, - .. - } => { - if let Some(wid) = target { - let state = match state { - wl_keyboard::KeyState::Pressed => ElementState::Pressed, - wl_keyboard::KeyState::Released => ElementState::Released, - }; - let vkcode = key_to_vkey(rawkey, keysym); - let mut guard = my_sink.lock().unwrap(); + let ret = map_keyboard_auto_with_repeat( + keyboard, + KeyRepeatKind::System, + move |evt: KbEvent, _| match evt { + KbEvent::Enter { surface, .. } => { + let wid = make_wid(&surface); + my_sink + .lock() + .unwrap() + .send_event(WindowEvent::Focused(true), wid); + *target.lock().unwrap() = Some(wid); + } + KbEvent::Leave { surface, .. } => { + let wid = make_wid(&surface); + my_sink + .lock() + .unwrap() + .send_event(WindowEvent::Focused(false), wid); + *target.lock().unwrap() = None; + } + KbEvent::Key { + modifiers, + rawkey, + keysym, + state, + utf8, + .. + } => { + if let Some(wid) = *target.lock().unwrap() { + let state = match state { + wl_keyboard::KeyState::Pressed => ElementState::Pressed, + wl_keyboard::KeyState::Released => ElementState::Released, + }; + let vkcode = key_to_vkey(rawkey, keysym); + let mut guard = my_sink.lock().unwrap(); + guard.send_event( + WindowEvent::KeyboardInput { + device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)), + input: KeyboardInput { + state: state, + scancode: rawkey, + virtual_keycode: vkcode, + modifiers: modifiers.into(), + }, + }, + wid, + ); + // send char event only on key press, not release + if let ElementState::Released = state { + return; + } + if let Some(txt) = utf8 { + for chr in txt.chars() { + guard.send_event(WindowEvent::ReceivedCharacter(chr), wid); + } + } + } + } + KbEvent::RepeatInfo { .. } => { /* Handled by smithay client toolkit */ } + }, + move |repeat_event: KeyRepeatEvent, _| { + if let Some(wid) = *repeat_target.lock().unwrap() { + let state = ElementState::Pressed; + let vkcode = key_to_vkey(repeat_event.rawkey, repeat_event.keysym); + let mut guard = repeat_sink.lock().unwrap(); guard.send_event( WindowEvent::KeyboardInput { device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)), input: KeyboardInput { state: state, - scancode: rawkey, + scancode: repeat_event.rawkey, virtual_keycode: vkcode, - modifiers: modifiers.into(), + modifiers: repeat_event.modifiers.into(), }, }, wid, ); - // send char event only on key press, not release - if let ElementState::Released = state { - return; - } - if let Some(txt) = utf8 { + if let Some(txt) = repeat_event.utf8 { for chr in txt.chars() { guard.send_event(WindowEvent::ReceivedCharacter(chr), wid); } } + events_loop_proxy.wakeup().unwrap(); } - } - KbEvent::RepeatInfo { .. } => { /* TODO: handle repeat info */ } - }); + }, + ); match ret { Ok(keyboard) => keyboard,