1
0
Fork 0
forked from wry/wry

wl_keyboard: don't send key-up events for keys that are not logically down

This commit is contained in:
Julian Orth 2025-01-23 13:48:23 +01:00
parent abaeed4c01
commit 53c38bdd68
9 changed files with 68 additions and 27 deletions

View file

@ -52,11 +52,14 @@ impl EiKeyboard {
}); });
} }
pub fn send_key(&self, key: u32, state: u32) { pub fn send_key(&self, key: u32, state: KeyState) {
self.client.event(ServerKey { self.client.event(ServerKey {
self_id: self.id, self_id: self.id,
key, key,
state, state: match state {
KeyState::Released => 0,
KeyState::Pressed => 1,
},
}); });
} }
} }

View file

@ -111,7 +111,7 @@ impl EiSeat {
self: &Rc<Self>, self: &Rc<Self>,
time_usec: u64, time_usec: u64,
key: u32, key: u32,
state: u32, state: KeyState,
kb_state: &KeyboardState, kb_state: &KeyboardState,
) { ) {
if self.is_sender() { if self.is_sender() {

View file

@ -19,7 +19,7 @@ use {
wl_seat::{ wl_seat::{
tablet::{TabletPad, TabletPadId, TabletTool, TabletToolId}, tablet::{TabletPad, TabletPadId, TabletTool, TabletToolId},
text_input::TextDisconnectReason, text_input::TextDisconnectReason,
wl_keyboard::{self, WlKeyboard}, wl_keyboard::WlKeyboard,
wl_pointer::{ wl_pointer::{
self, PendingScroll, WlPointer, AXIS_DISCRETE_SINCE_VERSION, self, PendingScroll, WlPointer, AXIS_DISCRETE_SINCE_VERSION,
AXIS_RELATIVE_DIRECTION_SINCE_VERSION, AXIS_SOURCE_SINCE_VERSION, AXIS_RELATIVE_DIRECTION_SINCE_VERSION, AXIS_SOURCE_SINCE_VERSION,
@ -873,22 +873,18 @@ impl WlSeatGlobal {
} }
} }
self.send_components(&mut components_changed, &kbvm_state); self.send_components(&mut components_changed, &kbvm_state);
let state = match key_state {
KeyState::Released => wl_keyboard::RELEASED,
KeyState::Pressed => wl_keyboard::PRESSED,
};
match self.input_method_grab.get() { match self.input_method_grab.get() {
Some(g) => g.on_key(time_usec, kc.to_evdev(), state, &kbvm_state.kb_state), Some(g) => g.on_key(time_usec, kc.to_evdev(), key_state, &kbvm_state.kb_state),
_ => self.keyboard_node.get().node_on_key( _ => self.keyboard_node.get().node_on_key(
self, self,
time_usec, time_usec,
kc.to_evdev(), kc.to_evdev(),
state, key_state,
&kbvm_state.kb_state, &kbvm_state.kb_state,
), ),
} }
self.for_each_ei_seat(|ei_seat| { self.for_each_ei_seat(|ei_seat| {
ei_seat.handle_key(time_usec, kc.to_evdev(), state, &kbvm_state.kb_state); ei_seat.handle_key(time_usec, kc.to_evdev(), key_state, &kbvm_state.kb_state);
}); });
update_pressed_keys(&mut kbvm_state); update_pressed_keys(&mut kbvm_state);
} }
@ -1339,7 +1335,7 @@ impl WlSeatGlobal {
surface: &WlSurface, surface: &WlSurface,
time_usec: u64, time_usec: u64,
key: u32, key: u32,
state: u32, state: KeyState,
kb_state: &KeyboardState, kb_state: &KeyboardState,
) { ) {
let serial = surface.client.next_serial(); let serial = surface.client.next_serial();

View file

@ -1,5 +1,6 @@
use { use {
crate::{ crate::{
backend::KeyState,
client::{Client, ClientError}, client::{Client, ClientError},
ifs::wl_seat::{text_input::zwp_input_method_v2::ZwpInputMethodV2, wl_keyboard}, ifs::wl_seat::{text_input::zwp_input_method_v2::ZwpInputMethodV2, wl_keyboard},
keyboard::{KeyboardState, KeyboardStateId}, keyboard::{KeyboardState, KeyboardStateId},
@ -48,7 +49,7 @@ impl ZwpInputMethodKeyboardGrabV2 {
self.kb_state_id.set(kb_state.id); self.kb_state_id.set(kb_state.id);
} }
pub fn on_key(&self, time_usec: u64, key: u32, state: u32, kb_state: &KeyboardState) { pub fn on_key(&self, time_usec: u64, key: u32, state: KeyState, kb_state: &KeyboardState) {
let serial = self.client.next_serial(); let serial = self.client.next_serial();
if self.kb_state_id.get() != kb_state.id { if self.kb_state_id.get() != kb_state.id {
self.update_state(serial, kb_state); self.update_state(serial, kb_state);
@ -56,13 +57,16 @@ impl ZwpInputMethodKeyboardGrabV2 {
self.send_key(serial, time_usec, key, state); self.send_key(serial, time_usec, key, state);
} }
fn send_key(&self, serial: u64, time_usec: u64, key: u32, state: u32) { fn send_key(&self, serial: u64, time_usec: u64, key: u32, state: KeyState) {
self.client.event(Key { self.client.event(Key {
self_id: self.id, self_id: self.id,
serial: serial as _, serial: serial as _,
time: (time_usec / 1000) as _, time: (time_usec / 1000) as _,
key, key,
state, state: match state {
KeyState::Released => wl_keyboard::RELEASED,
KeyState::Pressed => wl_keyboard::PRESSED,
},
}) })
} }

View file

@ -1,15 +1,19 @@
use { use {
crate::{ crate::{
backend::KeyState,
client::ClientError, client::ClientError,
ifs::wl_seat::WlSeat, ifs::wl_seat::WlSeat,
keyboard::{KeyboardError, KeyboardState, KeyboardStateId}, keyboard::{KeyboardError, KeyboardState, KeyboardStateId},
leaks::Tracker, leaks::Tracker,
object::{Object, Version}, object::{Object, Version},
utils::errorfmt::ErrorFmt, utils::{errorfmt::ErrorFmt, vecset::VecSet},
wire::{wl_keyboard::*, WlKeyboardId, WlSurfaceId}, wire::{wl_keyboard::*, WlKeyboardId, WlSurfaceId},
}, },
kbvm::Components, kbvm::Components,
std::{cell::Cell, rc::Rc}, std::{
cell::{Cell, RefCell},
rc::Rc,
},
thiserror::Error, thiserror::Error,
}; };
@ -26,6 +30,7 @@ pub struct WlKeyboard {
id: WlKeyboardId, id: WlKeyboardId,
seat: Rc<WlSeat>, seat: Rc<WlSeat>,
kb_state_id: Cell<KeyboardStateId>, kb_state_id: Cell<KeyboardStateId>,
pressed_keys: RefCell<VecSet<u32>>,
pub tracker: Tracker<Self>, pub tracker: Tracker<Self>,
} }
@ -35,6 +40,7 @@ impl WlKeyboard {
id, id,
seat: seat.clone(), seat: seat.clone(),
kb_state_id: Cell::new(KeyboardStateId::from_raw(0)), kb_state_id: Cell::new(KeyboardStateId::from_raw(0)),
pressed_keys: Default::default(),
tracker: Default::default(), tracker: Default::default(),
} }
} }
@ -89,6 +95,11 @@ impl WlKeyboard {
} }
fn send_enter(&self, serial: u64, surface: WlSurfaceId, keys: &[u32]) { fn send_enter(&self, serial: u64, surface: WlSurfaceId, keys: &[u32]) {
{
let pk = &mut self.pressed_keys.borrow_mut();
pk.clear();
pk.extend(keys);
}
self.seat.client.event(Enter { self.seat.client.event(Enter {
self_id: self.id, self_id: self.id,
serial: serial as _, serial: serial as _,
@ -110,7 +121,7 @@ impl WlKeyboard {
serial: u64, serial: u64,
time: u32, time: u32,
key: u32, key: u32,
state: u32, state: KeyState,
surface: WlSurfaceId, surface: WlSurfaceId,
kb_state: &KeyboardState, kb_state: &KeyboardState,
) { ) {
@ -120,13 +131,31 @@ impl WlKeyboard {
self.send_key(serial, time, key, state); self.send_key(serial, time, key, state);
} }
fn send_key(&self, serial: u64, time: u32, key: u32, state: u32) { fn send_key(&self, serial: u64, time: u32, key: u32, state: KeyState) {
{
let pk = &mut self.pressed_keys.borrow_mut();
match state {
KeyState::Released => {
if !pk.remove(&key) {
return;
}
}
KeyState::Pressed => {
if !pk.insert(key) {
return;
}
}
}
}
self.seat.client.event(Key { self.seat.client.event(Key {
self_id: self.id, self_id: self.id,
serial: serial as _, serial: serial as _,
time, time,
key, key,
state, state: match state {
KeyState::Released => RELEASED,
KeyState::Pressed => PRESSED,
},
}) })
} }

View file

@ -1,5 +1,6 @@
use { use {
crate::{ crate::{
backend::KeyState,
client::{Client, ClientError}, client::{Client, ClientError},
clientmem::{ClientMem, ClientMemError}, clientmem::{ClientMem, ClientMemError},
ifs::{ ifs::{
@ -90,14 +91,14 @@ impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 {
fn key(&self, req: Key, _slf: &Rc<Self>) -> Result<(), Self::Error> { fn key(&self, req: Key, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let kb_state = &mut *self.kb_state.borrow_mut(); let kb_state = &mut *self.kb_state.borrow_mut();
let contains = kb_state.pressed_keys.contains(&req.key); let contains = kb_state.pressed_keys.contains(&req.key);
let valid = match req.state { let (state, valid) = match req.state {
wl_keyboard::RELEASED => contains, wl_keyboard::RELEASED => (KeyState::Released, contains),
wl_keyboard::PRESSED => !contains, wl_keyboard::PRESSED => (KeyState::Pressed, !contains),
_ => return Err(ZwpVirtualKeyboardV1Error::UnknownState(req.state)), _ => return Err(ZwpVirtualKeyboardV1Error::UnknownState(req.state)),
}; };
if valid { if valid {
self.for_each_kb(|serial, surface, kb| { self.for_each_kb(|serial, surface, kb| {
kb.on_key(serial, req.time, req.key, req.state, surface.id, kb_state); kb.on_key(serial, req.time, req.key, state, surface.id, kb_state);
}); });
match req.state { match req.state {
wl_keyboard::RELEASED => kb_state.pressed_keys.remove(&req.key), wl_keyboard::RELEASED => kb_state.pressed_keys.remove(&req.key),

View file

@ -1741,7 +1741,7 @@ impl Node for WlSurface {
seat: &WlSeatGlobal, seat: &WlSeatGlobal,
time_usec: u64, time_usec: u64,
key: u32, key: u32,
state: u32, state: KeyState,
kb_state: &KeyboardState, kb_state: &KeyboardState,
) { ) {
seat.key_surface(self, time_usec, key, state, kb_state); seat.key_surface(self, time_usec, key, state, kb_state);

View file

@ -189,7 +189,7 @@ pub trait Node: 'static {
seat: &WlSeatGlobal, seat: &WlSeatGlobal,
time_usec: u64, time_usec: u64,
key: u32, key: u32,
state: u32, state: KeyState,
kb_state: &KeyboardState, kb_state: &KeyboardState,
) { ) {
let _ = seat; let _ = seat;

View file

@ -19,7 +19,6 @@ impl<T> Deref for VecSet<T> {
} }
impl<T> VecSet<T> { impl<T> VecSet<T> {
#[expect(dead_code)]
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.vec.clear(); self.vec.clear();
} }
@ -47,4 +46,13 @@ impl<T: PartialEq> VecSet<T> {
pub fn pop(&mut self) -> Option<T> { pub fn pop(&mut self) -> Option<T> {
self.vec.pop() self.vec.pop()
} }
pub fn extend(&mut self, vals: &[T])
where
T: Copy,
{
for v in vals.iter().copied() {
self.insert(v);
}
}
} }