Add key repetition for the wayland backend (#628)

* Add key repetition for the wayland backend

* Upgrade smithay-client-toolkit to 0.3.0
This commit is contained in:
trimental 2018-08-20 05:17:40 +08:00 committed by Francesca Frangipane
parent 1c795c3f1c
commit e4e53fe315
4 changed files with 107 additions and 62 deletions

View file

@ -2,6 +2,7 @@
- On macOS, fix `<C-Tab>` so applications receive the event.
- On macOS, fix `<Cmd-{key}>` so applications receive the event.
- On Wayland, key press events will now be repeated.
# Version 0.17.1 (2018-08-05)

View file

@ -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"

View file

@ -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<EventsLoop, ConnectError> {
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<Mutex<EventsLoopSink>>,
store: Arc<Mutex<WindowStore>>,
seats: Arc<Mutex<Vec<(u32, Proxy<wl_seat::WlSeat>)>>>,
events_loop_proxy: EventsLoopProxy,
}
impl Implementation<Proxy<wl_registry::WlRegistry>, GlobalEvent> for SeatManager {
@ -289,6 +297,7 @@ impl Implementation<Proxy<wl_registry::WlRegistry>, 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<Proxy<wl_pointer::WlPointer>>,
keyboard: Option<Proxy<wl_keyboard::WlKeyboard>>,
touch: Option<Proxy<wl_touch::WlTouch>>,
events_loop_proxy: EventsLoopProxy,
}
impl Implementation<Proxy<wl_seat::WlSeat>, wl_seat::Event> for SeatData {
@ -343,6 +353,7 @@ impl Implementation<Proxy<wl_seat::WlSeat>, 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

View file

@ -1,28 +1,35 @@
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<wl_keyboard::WlKeyboard>,
sink: Arc<Mutex<EventsLoopSink>>,
events_loop_proxy: EventsLoopProxy,
) -> Proxy<wl_keyboard::WlKeyboard> {
// { 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 {
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 = Some(wid);
*target.lock().unwrap() = Some(wid);
}
KbEvent::Leave { surface, .. } => {
let wid = make_wid(&surface);
@ -30,7 +37,7 @@ pub fn init_keyboard(
.lock()
.unwrap()
.send_event(WindowEvent::Focused(false), wid);
target = None;
*target.lock().unwrap() = None;
}
KbEvent::Key {
modifiers,
@ -40,7 +47,7 @@ pub fn init_keyboard(
utf8,
..
} => {
if let Some(wid) = target {
if let Some(wid) = *target.lock().unwrap() {
let state = match state {
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
wl_keyboard::KeyState::Released => ElementState::Released,
@ -70,8 +77,34 @@ pub fn init_keyboard(
}
}
}
KbEvent::RepeatInfo { .. } => { /* TODO: handle repeat info */ }
});
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: repeat_event.rawkey,
virtual_keycode: vkcode,
modifiers: repeat_event.modifiers.into(),
},
},
wid,
);
if let Some(txt) = repeat_event.utf8 {
for chr in txt.chars() {
guard.send_event(WindowEvent::ReceivedCharacter(chr), wid);
}
}
events_loop_proxy.wakeup().unwrap();
}
},
);
match ret {
Ok(keyboard) => keyboard,