seat: add KeyboardState and dynamically switch between states
This commit is contained in:
parent
134e3cc316
commit
5e2cdef388
15 changed files with 406 additions and 222 deletions
|
|
@ -32,15 +32,16 @@ use {
|
|||
tree::{Direction, FloatNode, Node, ToplevelNode},
|
||||
utils::{bitflags::BitflagsExt, smallmap::SmallMap},
|
||||
wire::WlDataOfferId,
|
||||
xkbcommon::{ModifierState, XKB_KEY_DOWN, XKB_KEY_UP},
|
||||
xkbcommon::{KeyboardState, XkbState, XKB_KEY_DOWN, XKB_KEY_UP},
|
||||
},
|
||||
isnt::std_1::primitive::IsntSlice2Ext,
|
||||
jay_config::keyboard::{
|
||||
mods::{Modifiers, CAPS, NUM},
|
||||
syms::KeySym,
|
||||
ModifiedKeySym,
|
||||
},
|
||||
smallvec::SmallVec,
|
||||
std::rc::Rc,
|
||||
std::{cell::RefCell, rc::Rc},
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -196,20 +197,7 @@ impl WlSeatGlobal {
|
|||
time_usec,
|
||||
key,
|
||||
state,
|
||||
} => {
|
||||
let desired_kb_map_id = match dev.keymap_id.get() {
|
||||
Some(id) => id,
|
||||
None => self.seat_kb_map_id.get(),
|
||||
};
|
||||
if desired_kb_map_id != self.effective_kb_map_id.get() {
|
||||
let map = match dev.keymap.get() {
|
||||
Some(map) => map,
|
||||
None => self.seat_kb_map.get(),
|
||||
};
|
||||
self.set_effective_keymap(&map);
|
||||
}
|
||||
self.key_event(time_usec, key, state)
|
||||
}
|
||||
} => self.key_event(time_usec, key, state, || dev.get_effective_xkb_state(self)),
|
||||
InputEvent::ConnectorPosition {
|
||||
time_usec,
|
||||
connector,
|
||||
|
|
@ -356,18 +344,27 @@ impl WlSeatGlobal {
|
|||
self.pointer_owner.button(self, time_usec, button, state);
|
||||
}
|
||||
|
||||
pub(super) fn key_event(&self, time_usec: u64, key: u32, key_state: KeyState) {
|
||||
pub(super) fn key_event<F>(
|
||||
&self,
|
||||
time_usec: u64,
|
||||
key: u32,
|
||||
key_state: KeyState,
|
||||
mut get_state: F,
|
||||
) where
|
||||
F: FnMut() -> Rc<RefCell<XkbState>>,
|
||||
{
|
||||
let mut xkb_state_rc = get_state();
|
||||
let mut xkb_state = xkb_state_rc.borrow_mut();
|
||||
let (state, xkb_dir) = {
|
||||
let mut pk = self.pressed_keys.borrow_mut();
|
||||
match key_state {
|
||||
KeyState::Released => {
|
||||
if !pk.remove(&key) {
|
||||
if xkb_state.kb_state.pressed_keys.not_contains(&key) {
|
||||
return;
|
||||
}
|
||||
(wl_keyboard::RELEASED, XKB_KEY_UP)
|
||||
}
|
||||
KeyState::Pressed => {
|
||||
if !pk.insert(key) {
|
||||
if xkb_state.kb_state.pressed_keys.contains(&key) {
|
||||
return;
|
||||
}
|
||||
(wl_keyboard::PRESSED, XKB_KEY_DOWN)
|
||||
|
|
@ -377,10 +374,9 @@ impl WlSeatGlobal {
|
|||
let mut shortcuts = SmallVec::<[_; 1]>::new();
|
||||
let new_mods;
|
||||
{
|
||||
let mut kb_state = self.kb_state.borrow_mut();
|
||||
if !self.state.lock.locked.get() && state == wl_keyboard::PRESSED {
|
||||
let old_mods = kb_state.mods();
|
||||
let keysyms = kb_state.unmodified_keysyms(key);
|
||||
let old_mods = xkb_state.mods();
|
||||
let keysyms = xkb_state.unmodified_keysyms(key);
|
||||
for &sym in keysyms {
|
||||
let mods = old_mods.mods_effective & !(CAPS.0 | NUM.0);
|
||||
if let Some(mods) = self.shortcuts.get(&(mods, sym)) {
|
||||
|
|
@ -391,44 +387,42 @@ impl WlSeatGlobal {
|
|||
}
|
||||
}
|
||||
}
|
||||
new_mods = kb_state.update(key, xkb_dir);
|
||||
new_mods = xkb_state.update(key, xkb_dir);
|
||||
}
|
||||
self.state.for_each_seat_tester(|t| {
|
||||
t.send_key(self.id, time_usec, key, key_state);
|
||||
});
|
||||
let node = self.keyboard_node.get();
|
||||
if shortcuts.is_empty() {
|
||||
node.node_on_key(self, time_usec, key, state);
|
||||
node.node_on_key(self, time_usec, key, state, &xkb_state.kb_state);
|
||||
} else if let Some(config) = self.state.config.get() {
|
||||
let id = xkb_state.kb_state.id;
|
||||
drop(xkb_state);
|
||||
for shortcut in shortcuts {
|
||||
config.invoke_shortcut(self.id(), &shortcut);
|
||||
}
|
||||
xkb_state_rc = get_state();
|
||||
xkb_state = xkb_state_rc.borrow_mut();
|
||||
if id != xkb_state.kb_state.id {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if let Some(mods) = new_mods {
|
||||
if new_mods {
|
||||
self.state.for_each_seat_tester(|t| {
|
||||
t.send_modifiers(self.id, &mods);
|
||||
t.send_modifiers(self.id, &xkb_state.kb_state.mods);
|
||||
});
|
||||
node.node_on_mods(self, mods);
|
||||
node.node_on_mods(self, &xkb_state.kb_state);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn set_modifiers(
|
||||
&self,
|
||||
mods_depressed: u32,
|
||||
mods_latched: u32,
|
||||
mods_locked: u32,
|
||||
group: u32,
|
||||
) {
|
||||
let new_mods =
|
||||
self.kb_state
|
||||
.borrow_mut()
|
||||
.set(mods_depressed, mods_latched, mods_locked, group);
|
||||
if let Some(mods) = new_mods {
|
||||
self.state.for_each_seat_tester(|t| {
|
||||
t.send_modifiers(self.id, &mods);
|
||||
});
|
||||
self.keyboard_node.get().node_on_mods(self, mods);
|
||||
match key_state {
|
||||
KeyState::Released => {
|
||||
xkb_state.kb_state.pressed_keys.remove(&key);
|
||||
}
|
||||
KeyState::Pressed => {
|
||||
xkb_state.kb_state.pressed_keys.insert(key);
|
||||
}
|
||||
}
|
||||
drop(xkb_state);
|
||||
self.latest_kb_state.set(xkb_state_rc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -578,7 +572,7 @@ impl WlSeatGlobal {
|
|||
});
|
||||
}
|
||||
|
||||
fn surface_kb_event<F>(&self, ver: Version, surface: &WlSurface, mut f: F)
|
||||
pub fn surface_kb_event<F>(&self, ver: Version, surface: &WlSurface, mut f: F)
|
||||
where
|
||||
F: FnMut(&Rc<WlKeyboard>),
|
||||
{
|
||||
|
|
@ -774,21 +768,11 @@ impl WlSeatGlobal {
|
|||
// Focus callbacks
|
||||
impl WlSeatGlobal {
|
||||
pub fn focus_surface(&self, surface: &WlSurface) {
|
||||
let pressed_keys = &*self.pressed_keys.borrow();
|
||||
let kb_state = self.latest_kb_state.get();
|
||||
let kb_state = &*kb_state.borrow();
|
||||
let serial = surface.client.next_serial();
|
||||
self.surface_kb_event(Version::ALL, surface, |k| {
|
||||
k.send_enter(serial, surface.id, pressed_keys)
|
||||
});
|
||||
let ModifierState {
|
||||
mods_depressed,
|
||||
mods_latched,
|
||||
mods_locked,
|
||||
group,
|
||||
..
|
||||
} = self.kb_state.borrow().mods();
|
||||
let serial = surface.client.next_serial();
|
||||
self.surface_kb_event(Version::ALL, surface, |k| {
|
||||
k.send_modifiers(serial, mods_depressed, mods_latched, mods_locked, group)
|
||||
k.enter(serial, surface.id, kb_state);
|
||||
});
|
||||
|
||||
if self.keyboard_node.get().node_client_id() != Some(surface.client.id) {
|
||||
|
|
@ -806,27 +790,28 @@ impl WlSeatGlobal {
|
|||
|
||||
// Key callbacks
|
||||
impl WlSeatGlobal {
|
||||
pub fn key_surface(&self, surface: &WlSurface, time_usec: u64, key: u32, state: u32) {
|
||||
pub fn key_surface(
|
||||
&self,
|
||||
surface: &WlSurface,
|
||||
time_usec: u64,
|
||||
key: u32,
|
||||
state: u32,
|
||||
kb_state: &KeyboardState,
|
||||
) {
|
||||
let serial = surface.client.next_serial();
|
||||
let time = (time_usec / 1000) as _;
|
||||
self.surface_kb_event(Version::ALL, surface, |k| {
|
||||
k.send_key(serial, time, key, state)
|
||||
k.on_key(serial, time, key, state, surface.id, kb_state);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Modifiers callbacks
|
||||
impl WlSeatGlobal {
|
||||
pub fn mods_surface(&self, surface: &WlSurface, mods: ModifierState) {
|
||||
pub fn mods_surface(&self, surface: &WlSurface, kb_state: &KeyboardState) {
|
||||
let serial = surface.client.next_serial();
|
||||
self.surface_kb_event(Version::ALL, surface, |k| {
|
||||
k.send_modifiers(
|
||||
serial,
|
||||
mods.mods_depressed,
|
||||
mods.mods_latched,
|
||||
mods.mods_locked,
|
||||
mods.group,
|
||||
)
|
||||
k.on_mods_changed(serial, surface.id, kb_state)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ use {
|
|||
ifs::wl_seat::WlSeat,
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
utils::{errorfmt::ErrorFmt, numcell::NumCell, oserror::OsError},
|
||||
utils::{errorfmt::ErrorFmt, oserror::OsError},
|
||||
wire::{wl_keyboard::*, WlKeyboardId, WlSurfaceId},
|
||||
xkbcommon::{KeyboardState, KeyboardStateId, ModifierState},
|
||||
},
|
||||
std::rc::Rc,
|
||||
std::{cell::Cell, rc::Rc},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
|
|
@ -23,7 +24,7 @@ pub const PRESSED: u32 = 1;
|
|||
pub struct WlKeyboard {
|
||||
id: WlKeyboardId,
|
||||
seat: Rc<WlSeat>,
|
||||
pub(super) keymap_version: NumCell<u32>,
|
||||
kb_state_id: Cell<KeyboardStateId>,
|
||||
pub tracker: Tracker<Self>,
|
||||
}
|
||||
|
||||
|
|
@ -32,14 +33,33 @@ impl WlKeyboard {
|
|||
Self {
|
||||
id,
|
||||
seat: seat.clone(),
|
||||
keymap_version: NumCell::new(0),
|
||||
kb_state_id: Cell::new(KeyboardStateId::from_raw(0)),
|
||||
tracker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_keymap(&self) {
|
||||
let map = self.seat.global.effective_kb_map.get();
|
||||
let fd = match self.seat.keymap_fd(&map) {
|
||||
pub fn kb_state_id(&self) -> KeyboardStateId {
|
||||
self.kb_state_id.get()
|
||||
}
|
||||
|
||||
fn send_kb_state(
|
||||
&self,
|
||||
serial: u32,
|
||||
kb_state: &KeyboardState,
|
||||
surface_id: WlSurfaceId,
|
||||
send_leave: bool,
|
||||
) {
|
||||
self.kb_state_id.set(kb_state.id);
|
||||
if send_leave {
|
||||
self.send_leave(serial, surface_id);
|
||||
}
|
||||
self.send_keymap(kb_state);
|
||||
self.send_enter(serial, surface_id, &kb_state.pressed_keys);
|
||||
self.send_modifiers(serial, &kb_state.mods);
|
||||
}
|
||||
|
||||
fn send_keymap(&self, state: &KeyboardState) {
|
||||
let fd = match self.seat.keymap_fd(state) {
|
||||
Ok(fd) => fd,
|
||||
Err(e) => {
|
||||
log::error!(
|
||||
|
|
@ -54,16 +74,20 @@ impl WlKeyboard {
|
|||
self_id: self.id,
|
||||
format: XKB_V1,
|
||||
fd,
|
||||
size: map.map_len as _,
|
||||
size: state.map_len as _,
|
||||
});
|
||||
self.keymap_version
|
||||
.set(self.seat.global.keymap_version.get());
|
||||
}
|
||||
|
||||
pub fn send_enter(self: &Rc<Self>, serial: u32, surface: WlSurfaceId, keys: &[u32]) {
|
||||
if self.keymap_version.get() != self.seat.global.keymap_version.get() {
|
||||
self.send_keymap();
|
||||
pub fn enter(&self, serial: u32, surface: WlSurfaceId, kb_state: &KeyboardState) {
|
||||
if kb_state.id != self.kb_state_id.get() {
|
||||
self.send_kb_state(serial, kb_state, surface, false);
|
||||
} else {
|
||||
self.send_enter(serial, surface, &kb_state.pressed_keys);
|
||||
self.send_modifiers(serial, &kb_state.mods);
|
||||
}
|
||||
}
|
||||
|
||||
fn send_enter(&self, serial: u32, surface: WlSurfaceId, keys: &[u32]) {
|
||||
self.seat.client.event(Enter {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
|
|
@ -72,7 +96,7 @@ impl WlKeyboard {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn send_leave(self: &Rc<Self>, serial: u32, surface: WlSurfaceId) {
|
||||
pub fn send_leave(&self, serial: u32, surface: WlSurfaceId) {
|
||||
self.seat.client.event(Leave {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
|
|
@ -80,7 +104,22 @@ impl WlKeyboard {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn send_key(self: &Rc<Self>, serial: u32, time: u32, key: u32, state: u32) {
|
||||
pub fn on_key(
|
||||
&self,
|
||||
serial: u32,
|
||||
time: u32,
|
||||
key: u32,
|
||||
state: u32,
|
||||
surface: WlSurfaceId,
|
||||
kb_state: &KeyboardState,
|
||||
) {
|
||||
if self.kb_state_id.get() != kb_state.id {
|
||||
self.send_kb_state(serial, kb_state, surface, true);
|
||||
}
|
||||
self.send_key(serial, time, key, state);
|
||||
}
|
||||
|
||||
fn send_key(&self, serial: u32, time: u32, key: u32, state: u32) {
|
||||
self.seat.client.event(Key {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
|
|
@ -90,21 +129,22 @@ impl WlKeyboard {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn send_modifiers(
|
||||
self: &Rc<Self>,
|
||||
serial: u32,
|
||||
mods_depressed: u32,
|
||||
mods_latched: u32,
|
||||
mods_locked: u32,
|
||||
group: u32,
|
||||
) {
|
||||
pub fn on_mods_changed(&self, serial: u32, surface: WlSurfaceId, kb_state: &KeyboardState) {
|
||||
if self.kb_state_id.get() != kb_state.id {
|
||||
self.send_kb_state(serial, kb_state, surface, true);
|
||||
} else {
|
||||
self.send_modifiers(serial, &kb_state.mods);
|
||||
}
|
||||
}
|
||||
|
||||
fn send_modifiers(&self, serial: u32, mods: &ModifierState) {
|
||||
self.seat.client.event(Modifiers {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
mods_depressed,
|
||||
mods_latched,
|
||||
mods_locked,
|
||||
group,
|
||||
mods_depressed: mods.mods_depressed,
|
||||
mods_latched: mods.mods_latched,
|
||||
mods_locked: mods.mods_locked,
|
||||
group: mods.group,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ use {
|
|||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{zwp_virtual_keyboard_manager_v1::*, ZwpVirtualKeyboardManagerV1Id},
|
||||
xkbcommon::KeyboardState,
|
||||
},
|
||||
std::rc::Rc,
|
||||
std::{cell::RefCell, rc::Rc},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
|
|
@ -76,14 +77,20 @@ impl ZwpVirtualKeyboardManagerV1RequestHandler for ZwpVirtualKeyboardManagerV1 {
|
|||
_slf: &Rc<Self>,
|
||||
) -> Result<(), Self::Error> {
|
||||
let seat = self.client.lookup(req.seat)?;
|
||||
let seat_keymap = seat.global.seat_kb_map.get();
|
||||
let kb = Rc::new(ZwpVirtualKeyboardV1 {
|
||||
id: req.id,
|
||||
client: self.client.clone(),
|
||||
seat: seat.global.clone(),
|
||||
tracker: Default::default(),
|
||||
version: self.version,
|
||||
keymap_id: Default::default(),
|
||||
keymap: Default::default(),
|
||||
kb_state: Rc::new(RefCell::new(KeyboardState {
|
||||
id: self.client.state.keyboard_state_ids.next(),
|
||||
map: seat_keymap.map.clone(),
|
||||
map_len: seat_keymap.map_len,
|
||||
pressed_keys: Default::default(),
|
||||
mods: Default::default(),
|
||||
})),
|
||||
});
|
||||
track!(self.client, kb);
|
||||
self.client.add_client_obj(&kb)?;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
use {
|
||||
crate::{
|
||||
backend::KeyState,
|
||||
client::{Client, ClientError},
|
||||
clientmem::{ClientMem, ClientMemError},
|
||||
ifs::wl_seat::{wl_keyboard, WlSeatGlobal},
|
||||
ifs::{
|
||||
wl_seat::{
|
||||
wl_keyboard::{self, WlKeyboard},
|
||||
WlSeatGlobal,
|
||||
},
|
||||
wl_surface::WlSurface,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
utils::clonecell::CloneCell,
|
||||
wire::{zwp_virtual_keyboard_v1::*, ZwpVirtualKeyboardV1Id},
|
||||
xkbcommon::{KeymapId, XkbCommonError, XkbKeymap},
|
||||
xkbcommon::{KeyboardState, XkbCommonError},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
std::{cell::RefCell, rc::Rc},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
|
|
@ -20,21 +24,21 @@ pub struct ZwpVirtualKeyboardV1 {
|
|||
pub seat: Rc<WlSeatGlobal>,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub version: Version,
|
||||
pub keymap_id: Cell<Option<KeymapId>>,
|
||||
pub keymap: CloneCell<Option<Rc<XkbKeymap>>>,
|
||||
pub kb_state: Rc<RefCell<KeyboardState>>,
|
||||
}
|
||||
|
||||
impl ZwpVirtualKeyboardV1 {
|
||||
fn ensure_keymap(&self) {
|
||||
if let Some(id) = self.keymap_id.get() {
|
||||
if id == self.seat.effective_kb_map_id.get() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let Some(keymap) = self.keymap.get() else {
|
||||
fn for_each_kb<F>(&self, mut f: F)
|
||||
where
|
||||
F: FnMut(u32, &WlSurface, &WlKeyboard),
|
||||
{
|
||||
let Some(surface) = self.seat.keyboard_node.get().node_into_surface() else {
|
||||
return;
|
||||
};
|
||||
self.seat.set_effective_keymap(&keymap);
|
||||
let serial = surface.client.next_serial();
|
||||
self.seat.surface_kb_event(Version::ALL, &surface, |kb| {
|
||||
f(serial, &surface, kb);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,31 +70,48 @@ impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 {
|
|||
.xkb_ctx
|
||||
.keymap_from_str(&map)
|
||||
.map_err(ZwpVirtualKeyboardV1Error::ParseKeymap)?;
|
||||
self.keymap_id.set(Some(map.id));
|
||||
self.keymap.set(Some(map));
|
||||
*self.kb_state.borrow_mut() = KeyboardState {
|
||||
id: self.client.state.keyboard_state_ids.next(),
|
||||
map: map.map.clone(),
|
||||
map_len: map.map_len,
|
||||
pressed_keys: Default::default(),
|
||||
mods: Default::default(),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn key(&self, req: Key, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.ensure_keymap();
|
||||
let time_usec = (req.time as u64) * 1000;
|
||||
let state = match req.state {
|
||||
wl_keyboard::RELEASED => KeyState::Released,
|
||||
wl_keyboard::PRESSED => KeyState::Pressed,
|
||||
let kb_state = &mut *self.kb_state.borrow_mut();
|
||||
let contains = kb_state.pressed_keys.contains(&req.key);
|
||||
let valid = match req.state {
|
||||
wl_keyboard::RELEASED => contains,
|
||||
wl_keyboard::PRESSED => !contains,
|
||||
_ => return Err(ZwpVirtualKeyboardV1Error::UnknownState(req.state)),
|
||||
};
|
||||
self.seat.key_event(time_usec, req.key, state);
|
||||
if valid {
|
||||
self.for_each_kb(|serial, surface, kb| {
|
||||
kb.on_key(serial, req.time, req.key, req.state, surface.id, kb_state);
|
||||
});
|
||||
match req.state {
|
||||
wl_keyboard::RELEASED => kb_state.pressed_keys.remove(&req.key),
|
||||
_ => kb_state.pressed_keys.insert(req.key),
|
||||
};
|
||||
self.seat.latest_kb_state.set(self.kb_state.clone());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn modifiers(&self, req: Modifiers, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.ensure_keymap();
|
||||
self.seat.set_modifiers(
|
||||
req.mods_depressed,
|
||||
req.mods_latched,
|
||||
req.mods_locked,
|
||||
req.group,
|
||||
);
|
||||
let kb_state = &mut *self.kb_state.borrow_mut();
|
||||
kb_state.mods.mods_depressed = req.mods_depressed;
|
||||
kb_state.mods.mods_latched = req.mods_latched;
|
||||
kb_state.mods.mods_locked = req.mods_locked;
|
||||
kb_state.mods.mods_effective = req.mods_depressed | req.mods_latched | req.mods_locked;
|
||||
kb_state.mods.group = req.group;
|
||||
self.for_each_kb(|serial, surface, kb| {
|
||||
kb.on_mods_changed(serial, surface.id, &kb_state);
|
||||
});
|
||||
self.seat.latest_kb_state.set(self.kb_state.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue