1use std::fmt::{self, Debug};
4use std::time::Duration;
5
6use wayrs_client::object::ObjectId;
7use wayrs_client::object::Proxy;
8use wayrs_client::protocol::wl_keyboard::{EnterArgs, LeaveArgs};
9use wayrs_client::protocol::*;
10use wayrs_client::{Connection, EventCtx};
11
12pub use xkbcommon::xkb;
13
14use crate::timer::Timer;
15
16pub trait KeyboardHandler: Sized + 'static {
17 fn get_keyboard(&mut self, wl_keyboard: WlKeyboard) -> &mut Keyboard;
22
23 fn key_presed(&mut self, conn: &mut Connection<Self>, event: KeyboardEvent);
24
25 fn key_released(&mut self, conn: &mut Connection<Self>, event: KeyboardEvent);
26
27 fn enter_surface(&mut self, _: &mut Connection<Self>, _: WlKeyboard, _: EnterArgs) {}
28
29 fn leave_surface(&mut self, _: &mut Connection<Self>, _: WlKeyboard, _: LeaveArgs) {}
30}
31
32pub struct Keyboard {
36 seat: WlSeat,
37 wl: WlKeyboard,
38 focused_surface: Option<ObjectId>,
39 xkb_context: xkb::Context,
40 xkb_state: Option<xkb::State>,
41 repeat_info: Option<RepeatInfo>,
42}
43
44#[derive(Debug, Clone, Copy)]
45pub struct RepeatInfo {
46 pub delay: Duration,
47 pub interval: Duration,
48}
49
50#[derive(Clone)]
51#[non_exhaustive]
52pub struct KeyboardEvent {
53 pub seat: WlSeat,
54 pub keyboard: WlKeyboard,
55 pub surface: ObjectId,
56 pub serial: u32,
57 pub time: u32,
58 pub keycode: xkb::Keycode,
59 pub keysym: xkb::Keysym,
60 pub repeat_info: Option<RepeatInfo>,
65 pub xkb_state: xkb::State,
66}
67
68impl Keyboard {
69 #[inline]
73 pub fn new<D: KeyboardHandler>(conn: &mut Connection<D>, seat: WlSeat) -> Self {
74 Self {
75 seat,
76 wl: seat.get_keyboard_with_cb(conn, wl_keyboard_cb),
77 focused_surface: None,
78 xkb_context: xkb::Context::new(xkb::CONTEXT_NO_FLAGS),
79 xkb_state: None,
80 repeat_info: None,
81 }
82 }
83
84 #[inline]
85 pub fn seat(&self) -> WlSeat {
86 self.seat
87 }
88
89 #[inline]
90 pub fn wl_keyboard(&self) -> WlKeyboard {
91 self.wl
92 }
93
94 #[inline]
95 pub fn destroy<D>(self, conn: &mut Connection<D>) {
96 if self.wl.version() >= 3 {
97 self.wl.release(conn);
98 }
99 }
100}
101
102impl RepeatInfo {
103 pub fn timer(self) -> Timer {
105 Timer::new(self.delay, self.interval)
106 }
107}
108
109fn wl_keyboard_cb<D: KeyboardHandler>(ctx: EventCtx<D, WlKeyboard>) {
110 let kbd = ctx.state.get_keyboard(ctx.proxy);
111 assert_eq!(
112 kbd.wl, ctx.proxy,
113 "invalid KeyboardHandler::get_keyboard() implementation"
114 );
115
116 match ctx.event {
117 wl_keyboard::Event::Keymap(args) if args.format == wl_keyboard::KeymapFormat::XkbV1 => {
118 let keymap = unsafe {
119 xkb::Keymap::new_from_fd(
120 &kbd.xkb_context,
121 args.fd,
122 args.size as usize,
123 xkb::FORMAT_TEXT_V1,
124 xkb::KEYMAP_COMPILE_NO_FLAGS,
125 )
126 };
127 if let Ok(Some(keymap)) = keymap {
128 kbd.xkb_state = Some(xkb::State::new(&keymap));
129 }
130 }
131 wl_keyboard::Event::Enter(args) => {
132 kbd.focused_surface = Some(args.surface);
133 ctx.state.enter_surface(ctx.conn, ctx.proxy, args);
134 }
135 wl_keyboard::Event::Leave(args) => {
136 kbd.focused_surface = None;
137 ctx.state.leave_surface(ctx.conn, ctx.proxy, args);
138 }
140 wl_keyboard::Event::Key(args) => {
141 let Some(xkb_state) = kbd.xkb_state.clone() else {
142 return;
143 };
144 let Some(surface) = kbd.focused_surface else {
145 return;
146 };
147
148 let keycode = xkb::Keycode::new(args.key + 8);
149 let keysym = xkb_state.key_get_one_sym(keycode);
150
151 let repeat_info = if xkb_state.get_keymap().key_repeats(keycode) {
152 kbd.repeat_info
153 } else {
154 None
155 };
156
157 let event = KeyboardEvent {
158 seat: kbd.seat,
159 keyboard: kbd.wl,
160 surface,
161 serial: args.serial,
162 time: args.time,
163 keycode,
164 keysym,
165 repeat_info,
166 xkb_state,
167 };
168
169 match args.state {
170 wl_keyboard::KeyState::Released => ctx.state.key_released(ctx.conn, event),
171 wl_keyboard::KeyState::Pressed => ctx.state.key_presed(ctx.conn, event),
172 _ => (),
173 }
174 }
175 wl_keyboard::Event::Modifiers(args) => {
176 if let Some(xkb_state) = &mut kbd.xkb_state {
177 xkb_state.update_mask(
178 args.mods_depressed,
179 args.mods_latched,
180 args.mods_locked,
181 0,
182 0,
183 args.group,
184 );
185 }
186 }
187 wl_keyboard::Event::RepeatInfo(args) => {
188 if args.rate == 0 {
189 kbd.repeat_info = None;
190 } else if args.rate > 0 && args.delay > 0 {
191 kbd.repeat_info = Some(RepeatInfo {
192 delay: Duration::from_millis(args.delay as u64),
193 interval: Duration::from_micros(1_000_000 / args.rate as u64),
194 });
195 }
196 }
197 _ => (),
198 }
199}
200
201impl Debug for KeyboardEvent {
202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203 f.debug_struct("KeyboardEvent")
204 .field("seat", &self.seat)
205 .field("keyboard", &self.keyboard)
206 .field("serial", &self.serial)
207 .field("time", &self.time)
208 .field("keycode", &self.keycode)
209 .field("repeat_info", &self.repeat_info)
210 .field("xkb_state", &"???")
211 .finish()
212 }
213}