keyboard: Add keyrepeat handling

This commit is contained in:
Kenny Levinsen
2023-02-13 17:39:54 +01:00
parent 9e48eb053d
commit 8826cab89d
4 changed files with 206 additions and 13 deletions
+3 -9
View File
@@ -22,14 +22,14 @@ use xkbcommon::xkb;
pub mod keysyms;
mod state;
mod repeat;
use self::state::KbState;
pub use self::state::ModifiersState;
pub use self::repeat::{KeyRepeatSource, RepeatMessage};
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct KeyEvent {
pub serial: u32,
pub time: u32,
pub rawkey: u32,
pub keysym: u32,
pub state: WEnum<wl_keyboard::KeyState>,
@@ -78,8 +78,6 @@ impl Keyboard {
pub fn key(
&mut self,
serial: u32,
time: u32,
key: u32,
key_state: WEnum<wl_keyboard::KeyState>,
) -> KeyEvent {
@@ -120,8 +118,6 @@ impl Keyboard {
keysym: sym,
state: key_state,
modifiers: state.mods_state(),
serial,
time,
utf8,
repeats,
}
@@ -133,8 +129,6 @@ impl Keyboard {
modifiers: Default::default(),
utf8: None,
repeats: false,
serial,
time,
}
}
}
+169
View File
@@ -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
View File
@@ -25,6 +25,7 @@ use event::{Event, Events};
use fonts::{FontMap, MaybeFontMap};
use state::State;
use widgets::{Geometry, Widget};
use keyboard::{KeyRepeatSource, RepeatMessage};
use std::{env, rc::Rc, thread};
@@ -64,6 +65,7 @@ fn main() {
display.get_registry(&qhandle, ());
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> =
EventLoop::try_new().expect("Failed to initialize the event loop!");
@@ -109,6 +111,17 @@ fn main() {
})
.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 mut fm = FontMap::new();
@@ -143,6 +156,7 @@ fn main() {
layout,
MaybeFontMap::Waiting(font_thread),
events,
keyrepeat_sender,
);
let mut damage = Vec::new();
+20 -4
View File
@@ -33,10 +33,12 @@ use crate::{
buffer::BufferManager,
event::{Event, Events, PointerButton, PointerEvent},
fonts::{FontMap, MaybeFontMap},
keyboard::Keyboard,
keyboard::{Keyboard, RepeatMessage},
widgets::{Geometry, Layout, Widget, WidgetUpdater},
};
use calloop::channel::Sender;
#[derive(Default)]
pub struct MainSurface {
pub wl_surface: Option<wl_surface::WlSurface>,
@@ -71,6 +73,7 @@ pub struct State {
pub bufmgr: BufferManager,
pub widgets: Vec<Box<dyn Widget>>,
pub keyboard: Keyboard,
pub keyrepeat_sender: Sender<RepeatMessage>,
pointer: Option<(f64, f64)>,
pub fonts: MaybeFontMap,
pub events: Arc<Mutex<Events>>,
@@ -84,6 +87,7 @@ impl State {
layout: Rc<Box<dyn Layout>>,
fonts: MaybeFontMap,
events: Arc<Mutex<Events>>,
keyrepeat_sender: Sender<RepeatMessage>,
) -> State {
State {
protocols: Default::default(),
@@ -97,6 +101,7 @@ impl State {
bufmgr: BufferManager::new(),
keyboard: Keyboard::new(),
pointer: None,
keyrepeat_sender,
mode,
widgets,
fonts,
@@ -555,21 +560,29 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for State {
_: &QueueHandle<Self>,
) {
match event {
wl_keyboard::Event::Leave { .. }=> {
state.keyrepeat_sender.send(RepeatMessage::StopRepeat).unwrap();
}
wl_keyboard::Event::Key {
serial,
time,
key,
state: kbstate,
..
} => {
if key == 1 {
state.running = false;
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);
for widget in state.widgets.iter_mut() {
widget.event(&ev);
}
if repeats {
if let Event::KeyEvent(k) = ev {
state.keyrepeat_sender.send(RepeatMessage::KeyEvent(k)).unwrap();
}
}
state.dirty = true;
}
wl_keyboard::Event::Modifiers {
@@ -587,6 +600,9 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for State {
// TODO: Keymap loading blocks xdg configure, consider delaying
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();
}
_ => (),
}
}