keyboard: Add keyrepeat handling
This commit is contained in:
+3
-9
@@ -22,14 +22,14 @@ use xkbcommon::xkb;
|
|||||||
|
|
||||||
pub mod keysyms;
|
pub mod keysyms;
|
||||||
mod state;
|
mod state;
|
||||||
|
mod repeat;
|
||||||
|
|
||||||
use self::state::KbState;
|
use self::state::KbState;
|
||||||
pub use self::state::ModifiersState;
|
pub use self::state::ModifiersState;
|
||||||
|
pub use self::repeat::{KeyRepeatSource, RepeatMessage};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct KeyEvent {
|
pub struct KeyEvent {
|
||||||
pub serial: u32,
|
|
||||||
pub time: u32,
|
|
||||||
pub rawkey: u32,
|
pub rawkey: u32,
|
||||||
pub keysym: u32,
|
pub keysym: u32,
|
||||||
pub state: WEnum<wl_keyboard::KeyState>,
|
pub state: WEnum<wl_keyboard::KeyState>,
|
||||||
@@ -78,8 +78,6 @@ impl Keyboard {
|
|||||||
|
|
||||||
pub fn key(
|
pub fn key(
|
||||||
&mut self,
|
&mut self,
|
||||||
serial: u32,
|
|
||||||
time: u32,
|
|
||||||
key: u32,
|
key: u32,
|
||||||
key_state: WEnum<wl_keyboard::KeyState>,
|
key_state: WEnum<wl_keyboard::KeyState>,
|
||||||
) -> KeyEvent {
|
) -> KeyEvent {
|
||||||
@@ -120,8 +118,6 @@ impl Keyboard {
|
|||||||
keysym: sym,
|
keysym: sym,
|
||||||
state: key_state,
|
state: key_state,
|
||||||
modifiers: state.mods_state(),
|
modifiers: state.mods_state(),
|
||||||
serial,
|
|
||||||
time,
|
|
||||||
utf8,
|
utf8,
|
||||||
repeats,
|
repeats,
|
||||||
}
|
}
|
||||||
@@ -133,8 +129,6 @@ impl Keyboard {
|
|||||||
modifiers: Default::default(),
|
modifiers: Default::default(),
|
||||||
utf8: None,
|
utf8: None,
|
||||||
repeats: false,
|
repeats: false,
|
||||||
serial,
|
|
||||||
time,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,169 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use calloop::{
|
||||||
|
channel::{self, Channel},
|
||||||
|
timer::{TimeoutAction, Timer},
|
||||||
|
EventSource, Poll, PostAction, Readiness, Token, TokenFactory,
|
||||||
|
};
|
||||||
|
use wayland_client::{
|
||||||
|
protocol::wl_keyboard, WEnum,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::KeyEvent;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum RepeatMessage {
|
||||||
|
StopRepeat,
|
||||||
|
KeyEvent(KeyEvent),
|
||||||
|
RepeatInfo((u32, u32))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct KeyRepeatSource {
|
||||||
|
channel: Channel<RepeatMessage>,
|
||||||
|
timer: Timer,
|
||||||
|
rate: Duration,
|
||||||
|
delay: Duration,
|
||||||
|
disabled: bool,
|
||||||
|
key: Option<KeyEvent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyRepeatSource {
|
||||||
|
pub fn new(ch: channel::Channel<RepeatMessage>) -> KeyRepeatSource {
|
||||||
|
KeyRepeatSource{
|
||||||
|
channel: ch,
|
||||||
|
timer: Timer::immediate(),
|
||||||
|
delay: Duration::ZERO,
|
||||||
|
rate: Duration::ZERO,
|
||||||
|
disabled: true,
|
||||||
|
key: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventSource for KeyRepeatSource {
|
||||||
|
type Event = KeyEvent;
|
||||||
|
type Metadata = ();
|
||||||
|
type Ret = ();
|
||||||
|
type Error = calloop::Error;
|
||||||
|
|
||||||
|
fn process_events<F>(
|
||||||
|
&mut self,
|
||||||
|
readiness: Readiness,
|
||||||
|
token: Token,
|
||||||
|
mut callback: F,
|
||||||
|
) -> calloop::Result<PostAction>
|
||||||
|
where
|
||||||
|
F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
|
||||||
|
{
|
||||||
|
let mut removed = false;
|
||||||
|
|
||||||
|
let timer = &mut self.timer;
|
||||||
|
let rate = &mut self.rate;
|
||||||
|
let delay = &mut self.delay;
|
||||||
|
let key = &mut self.key;
|
||||||
|
let disabled = &mut self.disabled;
|
||||||
|
|
||||||
|
let mut reregister = false;
|
||||||
|
|
||||||
|
let mut next_deadline = std::time::Instant::now();
|
||||||
|
|
||||||
|
// Check if the key repeat should stop
|
||||||
|
let channel_pa = self
|
||||||
|
.channel
|
||||||
|
.process_events(readiness, token, |event, _| {
|
||||||
|
match event {
|
||||||
|
channel::Event::Msg(message) => {
|
||||||
|
match message {
|
||||||
|
RepeatMessage::StopRepeat => {
|
||||||
|
key.take();
|
||||||
|
}
|
||||||
|
RepeatMessage::KeyEvent(event) => match event.state {
|
||||||
|
WEnum::Value(wl_keyboard::KeyState::Pressed) => {
|
||||||
|
key.replace(event);
|
||||||
|
reregister = true;
|
||||||
|
|
||||||
|
next_deadline = std::time::Instant::now() + *delay;
|
||||||
|
timer.set_deadline(next_deadline);
|
||||||
|
}
|
||||||
|
WEnum::Value(wl_keyboard::KeyState::Released) => match key {
|
||||||
|
Some(k) if k.keysym == event.keysym => {
|
||||||
|
key.take();
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
RepeatMessage::RepeatInfo((new_rate, new_delay)) => {
|
||||||
|
*rate = Duration::from_micros(1_000_000 / new_rate as u64);
|
||||||
|
*delay = Duration::from_millis(new_delay as u64);
|
||||||
|
*disabled = false;
|
||||||
|
if key.is_some() {
|
||||||
|
next_deadline = std::time::Instant::now() + *delay;
|
||||||
|
timer.set_deadline(next_deadline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
channel::Event::Closed => {
|
||||||
|
removed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map_err(|err| calloop::Error::OtherError(Box::new(err)))?;
|
||||||
|
|
||||||
|
// Keyboard was destroyed
|
||||||
|
if removed {
|
||||||
|
return Ok(PostAction::Remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-register the timer to start it again
|
||||||
|
if reregister {
|
||||||
|
return Ok(PostAction::Reregister);
|
||||||
|
}
|
||||||
|
|
||||||
|
let timer_pa = timer.process_events(readiness, token, |_event, _| {
|
||||||
|
if self.disabled || key.is_none() {
|
||||||
|
return TimeoutAction::Drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke the event
|
||||||
|
callback(key.as_ref().unwrap().clone(), &mut ());
|
||||||
|
next_deadline += *rate;
|
||||||
|
TimeoutAction::ToInstant(next_deadline)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Only disable or remove if both want to, otherwise continue or re-register
|
||||||
|
Ok(match (timer_pa, channel_pa) {
|
||||||
|
(PostAction::Disable, PostAction::Disable) => PostAction::Disable,
|
||||||
|
(PostAction::Remove, PostAction::Remove) => PostAction::Remove,
|
||||||
|
(PostAction::Reregister, _) | (_, PostAction::Reregister) => PostAction::Reregister,
|
||||||
|
_ => PostAction::Continue,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register(
|
||||||
|
&mut self,
|
||||||
|
poll: &mut Poll,
|
||||||
|
token_factory: &mut TokenFactory,
|
||||||
|
) -> calloop::Result<()> {
|
||||||
|
self.channel.register(poll, token_factory)?;
|
||||||
|
self.timer.register(poll, token_factory)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reregister(
|
||||||
|
&mut self,
|
||||||
|
poll: &mut Poll,
|
||||||
|
token_factory: &mut TokenFactory,
|
||||||
|
) -> calloop::Result<()> {
|
||||||
|
self.channel.reregister(poll, token_factory)?;
|
||||||
|
self.timer.reregister(poll, token_factory)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unregister(&mut self, poll: &mut Poll) -> calloop::Result<()> {
|
||||||
|
self.channel.unregister(poll)?;
|
||||||
|
self.timer.unregister(poll)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+14
@@ -25,6 +25,7 @@ use event::{Event, Events};
|
|||||||
use fonts::{FontMap, MaybeFontMap};
|
use fonts::{FontMap, MaybeFontMap};
|
||||||
use state::State;
|
use state::State;
|
||||||
use widgets::{Geometry, Widget};
|
use widgets::{Geometry, Widget};
|
||||||
|
use keyboard::{KeyRepeatSource, RepeatMessage};
|
||||||
|
|
||||||
use std::{env, rc::Rc, thread};
|
use std::{env, rc::Rc, thread};
|
||||||
|
|
||||||
@@ -64,6 +65,7 @@ fn main() {
|
|||||||
display.get_registry(&qhandle, ());
|
display.get_registry(&qhandle, ());
|
||||||
|
|
||||||
let (ping_sender, ping_source) = calloop::ping::make_ping().unwrap();
|
let (ping_sender, ping_source) = calloop::ping::make_ping().unwrap();
|
||||||
|
let (keyrepeat_sender, keyrepeat_channel) = calloop::channel::channel::<RepeatMessage>();
|
||||||
|
|
||||||
let mut event_loop: EventLoop<State> =
|
let mut event_loop: EventLoop<State> =
|
||||||
EventLoop::try_new().expect("Failed to initialize the event loop!");
|
EventLoop::try_new().expect("Failed to initialize the event loop!");
|
||||||
@@ -109,6 +111,17 @@ fn main() {
|
|||||||
})
|
})
|
||||||
.expect("Failed to insert event source!");
|
.expect("Failed to insert event source!");
|
||||||
|
|
||||||
|
let keyrepeat_source = KeyRepeatSource::new(keyrepeat_channel);
|
||||||
|
handle
|
||||||
|
.insert_source(keyrepeat_source, |event, _metadata, state| {
|
||||||
|
let ev = Event::KeyEvent(event);
|
||||||
|
for widget in state.widgets.iter_mut() {
|
||||||
|
widget.event(&ev);
|
||||||
|
}
|
||||||
|
state.dirty = true;
|
||||||
|
})
|
||||||
|
.expect("Failed to insert keyrepeat source!");
|
||||||
|
|
||||||
let events = Events::new(ping_sender);
|
let events = Events::new(ping_sender);
|
||||||
|
|
||||||
let mut fm = FontMap::new();
|
let mut fm = FontMap::new();
|
||||||
@@ -143,6 +156,7 @@ fn main() {
|
|||||||
layout,
|
layout,
|
||||||
MaybeFontMap::Waiting(font_thread),
|
MaybeFontMap::Waiting(font_thread),
|
||||||
events,
|
events,
|
||||||
|
keyrepeat_sender,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut damage = Vec::new();
|
let mut damage = Vec::new();
|
||||||
|
|||||||
+20
-4
@@ -33,10 +33,12 @@ use crate::{
|
|||||||
buffer::BufferManager,
|
buffer::BufferManager,
|
||||||
event::{Event, Events, PointerButton, PointerEvent},
|
event::{Event, Events, PointerButton, PointerEvent},
|
||||||
fonts::{FontMap, MaybeFontMap},
|
fonts::{FontMap, MaybeFontMap},
|
||||||
keyboard::Keyboard,
|
keyboard::{Keyboard, RepeatMessage},
|
||||||
widgets::{Geometry, Layout, Widget, WidgetUpdater},
|
widgets::{Geometry, Layout, Widget, WidgetUpdater},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use calloop::channel::Sender;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct MainSurface {
|
pub struct MainSurface {
|
||||||
pub wl_surface: Option<wl_surface::WlSurface>,
|
pub wl_surface: Option<wl_surface::WlSurface>,
|
||||||
@@ -71,6 +73,7 @@ pub struct State {
|
|||||||
pub bufmgr: BufferManager,
|
pub bufmgr: BufferManager,
|
||||||
pub widgets: Vec<Box<dyn Widget>>,
|
pub widgets: Vec<Box<dyn Widget>>,
|
||||||
pub keyboard: Keyboard,
|
pub keyboard: Keyboard,
|
||||||
|
pub keyrepeat_sender: Sender<RepeatMessage>,
|
||||||
pointer: Option<(f64, f64)>,
|
pointer: Option<(f64, f64)>,
|
||||||
pub fonts: MaybeFontMap,
|
pub fonts: MaybeFontMap,
|
||||||
pub events: Arc<Mutex<Events>>,
|
pub events: Arc<Mutex<Events>>,
|
||||||
@@ -84,6 +87,7 @@ impl State {
|
|||||||
layout: Rc<Box<dyn Layout>>,
|
layout: Rc<Box<dyn Layout>>,
|
||||||
fonts: MaybeFontMap,
|
fonts: MaybeFontMap,
|
||||||
events: Arc<Mutex<Events>>,
|
events: Arc<Mutex<Events>>,
|
||||||
|
keyrepeat_sender: Sender<RepeatMessage>,
|
||||||
) -> State {
|
) -> State {
|
||||||
State {
|
State {
|
||||||
protocols: Default::default(),
|
protocols: Default::default(),
|
||||||
@@ -97,6 +101,7 @@ impl State {
|
|||||||
bufmgr: BufferManager::new(),
|
bufmgr: BufferManager::new(),
|
||||||
keyboard: Keyboard::new(),
|
keyboard: Keyboard::new(),
|
||||||
pointer: None,
|
pointer: None,
|
||||||
|
keyrepeat_sender,
|
||||||
mode,
|
mode,
|
||||||
widgets,
|
widgets,
|
||||||
fonts,
|
fonts,
|
||||||
@@ -555,21 +560,29 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for State {
|
|||||||
_: &QueueHandle<Self>,
|
_: &QueueHandle<Self>,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
|
wl_keyboard::Event::Leave { .. }=> {
|
||||||
|
state.keyrepeat_sender.send(RepeatMessage::StopRepeat).unwrap();
|
||||||
|
}
|
||||||
wl_keyboard::Event::Key {
|
wl_keyboard::Event::Key {
|
||||||
serial,
|
|
||||||
time,
|
|
||||||
key,
|
key,
|
||||||
state: kbstate,
|
state: kbstate,
|
||||||
|
..
|
||||||
} => {
|
} => {
|
||||||
if key == 1 {
|
if key == 1 {
|
||||||
state.running = false;
|
state.running = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let k = state.keyboard.key(serial, time, key, kbstate);
|
let k = state.keyboard.key(key, kbstate);
|
||||||
|
let repeats = k.repeats;
|
||||||
let ev = Event::KeyEvent(k);
|
let ev = Event::KeyEvent(k);
|
||||||
for widget in state.widgets.iter_mut() {
|
for widget in state.widgets.iter_mut() {
|
||||||
widget.event(&ev);
|
widget.event(&ev);
|
||||||
}
|
}
|
||||||
|
if repeats {
|
||||||
|
if let Event::KeyEvent(k) = ev {
|
||||||
|
state.keyrepeat_sender.send(RepeatMessage::KeyEvent(k)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
state.dirty = true;
|
state.dirty = true;
|
||||||
}
|
}
|
||||||
wl_keyboard::Event::Modifiers {
|
wl_keyboard::Event::Modifiers {
|
||||||
@@ -587,6 +600,9 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for State {
|
|||||||
// TODO: Keymap loading blocks xdg configure, consider delaying
|
// TODO: Keymap loading blocks xdg configure, consider delaying
|
||||||
state.keyboard.keymap(format, fd, size);
|
state.keyboard.keymap(format, fd, size);
|
||||||
}
|
}
|
||||||
|
wl_keyboard::Event::RepeatInfo { rate, delay } => {
|
||||||
|
state.keyrepeat_sender.send(RepeatMessage::RepeatInfo((rate as u32, delay as u32))).unwrap();
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user