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 `<C-Tab>` so applications receive the event.
- On macOS, fix `<Cmd-{key}>` 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) # 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] [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"] } 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" x11-dl = "2.18.3"
parking_lot = "0.6" parking_lot = "0.6"
percent-encoding = "1.0" percent-encoding = "1.0"

View file

@ -1,20 +1,21 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt; use std::fmt;
use std::sync::{Arc, Mutex, Weak};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, Weak};
use {ControlFlow, EventsLoopClosed, PhysicalPosition, PhysicalSize}; use {ControlFlow, EventsLoopClosed, PhysicalPosition, PhysicalSize};
use super::WindowId;
use super::window::WindowStore; use super::window::WindowStore;
use super::WindowId;
use sctk::Environment;
use sctk::output::OutputMgr; use sctk::output::OutputMgr;
use sctk::reexports::client::{Display, EventQueue, GlobalEvent, Proxy, ConnectError};
use sctk::reexports::client::commons::Implementation; use sctk::reexports::client::commons::Implementation;
use sctk::reexports::client::protocol::{wl_keyboard, wl_output, wl_pointer, wl_registry, wl_seat, use sctk::reexports::client::protocol::{
wl_touch}; 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; use sctk::reexports::client::protocol::wl_display::RequestsTrait as DisplayRequests;
@ -104,6 +105,8 @@ impl EventsLoop {
pub fn new() -> Result<EventsLoop, ConnectError> { pub fn new() -> Result<EventsLoop, ConnectError> {
let (display, mut event_queue) = Display::connect_to_env()?; 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 sink = Arc::new(Mutex::new(EventsLoopSink::new()));
let store = Arc::new(Mutex::new(WindowStore::new())); let store = Arc::new(Mutex::new(WindowStore::new()));
let seats = Arc::new(Mutex::new(Vec::new())); let seats = Arc::new(Mutex::new(Vec::new()));
@ -115,18 +118,22 @@ impl EventsLoop {
sink: sink.clone(), sink: sink.clone(),
store: store.clone(), store: store.clone(),
seats: seats.clone(), seats: seats.clone(),
events_loop_proxy: EventsLoopProxy {
display: Arc::downgrade(&display),
pending_wakeup: Arc::downgrade(&pending_wakeup),
},
}, },
).unwrap(); ).unwrap();
Ok(EventsLoop { Ok(EventsLoop {
display: Arc::new(display), display,
evq: RefCell::new(event_queue), evq: RefCell::new(event_queue),
sink: sink, sink,
pending_wakeup: Arc::new(AtomicBool::new(false)), pending_wakeup,
store: store, store,
env: env, env,
cleanup_needed: Arc::new(Mutex::new(false)), cleanup_needed: Arc::new(Mutex::new(false)),
seats: seats, seats,
}) })
} }
@ -266,6 +273,7 @@ struct SeatManager {
sink: Arc<Mutex<EventsLoopSink>>, sink: Arc<Mutex<EventsLoopSink>>,
store: Arc<Mutex<WindowStore>>, store: Arc<Mutex<WindowStore>>,
seats: Arc<Mutex<Vec<(u32, Proxy<wl_seat::WlSeat>)>>>, seats: Arc<Mutex<Vec<(u32, Proxy<wl_seat::WlSeat>)>>>,
events_loop_proxy: EventsLoopProxy,
} }
impl Implementation<Proxy<wl_registry::WlRegistry>, GlobalEvent> for SeatManager { impl Implementation<Proxy<wl_registry::WlRegistry>, GlobalEvent> for SeatManager {
@ -289,6 +297,7 @@ impl Implementation<Proxy<wl_registry::WlRegistry>, GlobalEvent> for SeatManager
pointer: None, pointer: None,
keyboard: None, keyboard: None,
touch: None, touch: None,
events_loop_proxy: self.events_loop_proxy.clone(),
}); });
self.store.lock().unwrap().new_seat(&seat); self.store.lock().unwrap().new_seat(&seat);
self.seats.lock().unwrap().push((id, seat)); self.seats.lock().unwrap().push((id, seat));
@ -313,6 +322,7 @@ struct SeatData {
pointer: Option<Proxy<wl_pointer::WlPointer>>, pointer: Option<Proxy<wl_pointer::WlPointer>>,
keyboard: Option<Proxy<wl_keyboard::WlKeyboard>>, keyboard: Option<Proxy<wl_keyboard::WlKeyboard>>,
touch: Option<Proxy<wl_touch::WlTouch>>, touch: Option<Proxy<wl_touch::WlTouch>>,
events_loop_proxy: EventsLoopProxy,
} }
impl Implementation<Proxy<wl_seat::WlSeat>, wl_seat::Event> for SeatData { 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( self.keyboard = Some(super::keyboard::init_keyboard(
seat.get_keyboard().unwrap(), seat.get_keyboard().unwrap(),
self.sink.clone(), self.sink.clone(),
self.events_loop_proxy.clone(),
)) ))
} }
// destroy keyboard if applicable // destroy keyboard if applicable

View file

@ -1,77 +1,110 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use {ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent}; use super::{make_wid, DeviceId, EventsLoopProxy, EventsLoopSink};
use sctk::keyboard::{
use super::{make_wid, DeviceId, EventsLoopSink}; self, map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatEvent, KeyRepeatKind,
use sctk::keyboard::{self, map_keyboard_auto, Event as KbEvent}; };
use sctk::reexports::client::{NewProxy, Proxy};
use sctk::reexports::client::protocol::wl_keyboard; use sctk::reexports::client::protocol::wl_keyboard;
use sctk::reexports::client::{NewProxy, Proxy};
use {ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent};
pub fn init_keyboard( pub fn init_keyboard(
keyboard: NewProxy<wl_keyboard::WlKeyboard>, keyboard: NewProxy<wl_keyboard::WlKeyboard>,
sink: Arc<Mutex<EventsLoopSink>>, sink: Arc<Mutex<EventsLoopSink>>,
events_loop_proxy: EventsLoopProxy,
) -> Proxy<wl_keyboard::WlKeyboard> { ) -> Proxy<wl_keyboard::WlKeyboard> {
// { variables to be captured by the closure // { variables to be captured by the closures
let mut target = None; let target = Arc::new(Mutex::new(None));
let my_sink = sink.clone(); 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(
KbEvent::Enter { surface, .. } => { keyboard,
let wid = make_wid(&surface); KeyRepeatKind::System,
my_sink move |evt: KbEvent, _| match evt {
.lock() KbEvent::Enter { surface, .. } => {
.unwrap() let wid = make_wid(&surface);
.send_event(WindowEvent::Focused(true), wid); my_sink
target = Some(wid); .lock()
} .unwrap()
KbEvent::Leave { surface, .. } => { .send_event(WindowEvent::Focused(true), wid);
let wid = make_wid(&surface); *target.lock().unwrap() = Some(wid);
my_sink }
.lock() KbEvent::Leave { surface, .. } => {
.unwrap() let wid = make_wid(&surface);
.send_event(WindowEvent::Focused(false), wid); my_sink
target = None; .lock()
} .unwrap()
KbEvent::Key { .send_event(WindowEvent::Focused(false), wid);
modifiers, *target.lock().unwrap() = None;
rawkey, }
keysym, KbEvent::Key {
state, modifiers,
utf8, rawkey,
.. keysym,
} => { state,
if let Some(wid) = target { utf8,
let state = match state { ..
wl_keyboard::KeyState::Pressed => ElementState::Pressed, } => {
wl_keyboard::KeyState::Released => ElementState::Released, if let Some(wid) = *target.lock().unwrap() {
}; let state = match state {
let vkcode = key_to_vkey(rawkey, keysym); wl_keyboard::KeyState::Pressed => ElementState::Pressed,
let mut guard = my_sink.lock().unwrap(); 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( guard.send_event(
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)), device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
input: KeyboardInput { input: KeyboardInput {
state: state, state: state,
scancode: rawkey, scancode: repeat_event.rawkey,
virtual_keycode: vkcode, virtual_keycode: vkcode,
modifiers: modifiers.into(), modifiers: repeat_event.modifiers.into(),
}, },
}, },
wid, wid,
); );
// send char event only on key press, not release if let Some(txt) = repeat_event.utf8 {
if let ElementState::Released = state {
return;
}
if let Some(txt) = utf8 {
for chr in txt.chars() { for chr in txt.chars() {
guard.send_event(WindowEvent::ReceivedCharacter(chr), wid); guard.send_event(WindowEvent::ReceivedCharacter(chr), wid);
} }
} }
events_loop_proxy.wakeup().unwrap();
} }
} },
KbEvent::RepeatInfo { .. } => { /* TODO: handle repeat info */ } );
});
match ret { match ret {
Ok(keyboard) => keyboard, Ok(keyboard) => keyboard,