winit/platform_impl/linux/wayland/seat/keyboard/
mod.rs
1use std::sync::Mutex;
4use std::time::Duration;
5
6use calloop::timer::{TimeoutAction, Timer};
7use calloop::{LoopHandle, RegistrationToken};
8use tracing::warn;
9
10use sctk::reexports::client::protocol::wl_keyboard::{
11 Event as WlKeyboardEvent, KeyState as WlKeyState, KeymapFormat as WlKeymapFormat, WlKeyboard,
12};
13use sctk::reexports::client::protocol::wl_seat::WlSeat;
14use sctk::reexports::client::{Connection, Dispatch, Proxy, QueueHandle, WEnum};
15
16use crate::event::{ElementState, WindowEvent};
17use crate::keyboard::ModifiersState;
18
19use crate::platform_impl::common::xkb::Context;
20use crate::platform_impl::wayland::event_loop::sink::EventSink;
21use crate::platform_impl::wayland::state::WinitState;
22use crate::platform_impl::wayland::{self, DeviceId, WindowId};
23
24impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
25 fn event(
26 state: &mut WinitState,
27 wl_keyboard: &WlKeyboard,
28 event: <WlKeyboard as Proxy>::Event,
29 data: &KeyboardData,
30 _: &Connection,
31 _: &QueueHandle<WinitState>,
32 ) {
33 let seat_state = match state.seats.get_mut(&data.seat.id()) {
34 Some(seat_state) => seat_state,
35 None => {
36 warn!("Received keyboard event {event:?} without seat");
37 return;
38 },
39 };
40 let keyboard_state = match seat_state.keyboard_state.as_mut() {
41 Some(keyboard_state) => keyboard_state,
42 None => {
43 warn!("Received keyboard event {event:?} without keyboard");
44 return;
45 },
46 };
47
48 match event {
49 WlKeyboardEvent::Keymap { format, fd, size } => match format {
50 WEnum::Value(format) => match format {
51 WlKeymapFormat::NoKeymap => {
52 warn!("non-xkb compatible keymap")
53 },
54 WlKeymapFormat::XkbV1 => {
55 let context = &mut keyboard_state.xkb_context;
56 context.set_keymap_from_fd(fd, size as usize);
57 },
58 _ => unreachable!(),
59 },
60 WEnum::Unknown(value) => {
61 warn!("unknown keymap format 0x{:x}", value)
62 },
63 },
64 WlKeyboardEvent::Enter { surface, .. } => {
65 let window_id = wayland::make_wid(&surface);
66
67 let was_unfocused = match state.windows.get_mut().get(&window_id) {
69 Some(window) => {
70 let mut window = window.lock().unwrap();
71 let was_unfocused = !window.has_focus();
72 window.add_seat_focus(data.seat.id());
73 was_unfocused
74 },
75 None => return,
76 };
77
78 keyboard_state.current_repeat = None;
80 if let Some(token) = keyboard_state.repeat_token.take() {
81 keyboard_state.loop_handle.remove(token);
82 }
83
84 *data.window_id.lock().unwrap() = Some(window_id);
85
86 if was_unfocused {
88 state.events_sink.push_window_event(WindowEvent::Focused(true), window_id);
89 }
90
91 if std::mem::take(&mut seat_state.modifiers_pending) {
93 state.events_sink.push_window_event(
94 WindowEvent::ModifiersChanged(seat_state.modifiers.into()),
95 window_id,
96 );
97 }
98 },
99 WlKeyboardEvent::Leave { surface, .. } => {
100 let window_id = wayland::make_wid(&surface);
101
102 keyboard_state.current_repeat = None;
105 if let Some(token) = keyboard_state.repeat_token.take() {
106 keyboard_state.loop_handle.remove(token);
107 }
108
109 let focused = match state.windows.get_mut().get(&window_id) {
112 Some(window) => {
113 let mut window = window.lock().unwrap();
114 window.remove_seat_focus(&data.seat.id());
115 window.has_focus()
116 },
117 None => return,
118 };
119
120 *data.window_id.lock().unwrap() = None;
123
124 if !focused {
125 state.events_sink.push_window_event(
127 WindowEvent::ModifiersChanged(ModifiersState::empty().into()),
128 window_id,
129 );
130
131 state.events_sink.push_window_event(WindowEvent::Focused(false), window_id);
132 }
133 },
134 WlKeyboardEvent::Key { key, state: WEnum::Value(WlKeyState::Pressed), .. } => {
135 let key = key + 8;
136
137 key_input(
138 keyboard_state,
139 &mut state.events_sink,
140 data,
141 key,
142 ElementState::Pressed,
143 false,
144 );
145
146 let delay = match keyboard_state.repeat_info {
147 RepeatInfo::Repeat { delay, .. } => delay,
148 RepeatInfo::Disable => return,
149 };
150
151 if !keyboard_state.xkb_context.keymap_mut().unwrap().key_repeats(key) {
152 return;
153 }
154
155 keyboard_state.current_repeat = Some(key);
156
157 if let Some(token) = keyboard_state.repeat_token.take() {
160 keyboard_state.loop_handle.remove(token);
161 }
162
163 let timer = Timer::from_duration(delay);
164 let wl_keyboard = wl_keyboard.clone();
165 keyboard_state.repeat_token = keyboard_state
166 .loop_handle
167 .insert_source(timer, move |_, _, state| {
168 state.dispatched_events = true;
170
171 let data = wl_keyboard.data::<KeyboardData>().unwrap();
172 let seat_state = match state.seats.get_mut(&data.seat.id()) {
173 Some(seat_state) => seat_state,
174 None => return TimeoutAction::Drop,
175 };
176
177 let keyboard_state = match seat_state.keyboard_state.as_mut() {
178 Some(keyboard_state) => keyboard_state,
179 None => return TimeoutAction::Drop,
180 };
181
182 let repeat_keycode = match keyboard_state.current_repeat {
185 Some(repeat_keycode) => repeat_keycode,
186 None => return TimeoutAction::Drop,
187 };
188
189 key_input(
190 keyboard_state,
191 &mut state.events_sink,
192 data,
193 repeat_keycode,
194 ElementState::Pressed,
195 true,
196 );
197
198 match keyboard_state.repeat_info {
200 RepeatInfo::Repeat { gap, .. } => TimeoutAction::ToDuration(gap),
201 RepeatInfo::Disable => TimeoutAction::Drop,
202 }
203 })
204 .ok();
205 },
206 WlKeyboardEvent::Key { key, state: WEnum::Value(WlKeyState::Released), .. } => {
207 let key = key + 8;
208
209 key_input(
210 keyboard_state,
211 &mut state.events_sink,
212 data,
213 key,
214 ElementState::Released,
215 false,
216 );
217
218 if keyboard_state.repeat_info != RepeatInfo::Disable
219 && keyboard_state.xkb_context.keymap_mut().unwrap().key_repeats(key)
220 && Some(key) == keyboard_state.current_repeat
221 {
222 keyboard_state.current_repeat = None;
223 if let Some(token) = keyboard_state.repeat_token.take() {
224 keyboard_state.loop_handle.remove(token);
225 }
226 }
227 },
228 WlKeyboardEvent::Modifiers {
229 mods_depressed, mods_latched, mods_locked, group, ..
230 } => {
231 let xkb_context = &mut keyboard_state.xkb_context;
232 let xkb_state = match xkb_context.state_mut() {
233 Some(state) => state,
234 None => return,
235 };
236
237 xkb_state.update_modifiers(mods_depressed, mods_latched, mods_locked, 0, 0, group);
238 seat_state.modifiers = xkb_state.modifiers().into();
239
240 let window_id = match *data.window_id.lock().unwrap() {
242 Some(window_id) => window_id,
243 None => {
244 seat_state.modifiers_pending = true;
245 return;
246 },
247 };
248
249 state.events_sink.push_window_event(
250 WindowEvent::ModifiersChanged(seat_state.modifiers.into()),
251 window_id,
252 );
253 },
254 WlKeyboardEvent::RepeatInfo { rate, delay } => {
255 keyboard_state.repeat_info = if rate == 0 {
256 keyboard_state.current_repeat = None;
258 if let Some(repeat_token) = keyboard_state.repeat_token.take() {
259 keyboard_state.loop_handle.remove(repeat_token);
260 }
261 RepeatInfo::Disable
262 } else {
263 let gap = Duration::from_micros(1_000_000 / rate as u64);
264 let delay = Duration::from_millis(delay as u64);
265 RepeatInfo::Repeat { gap, delay }
266 };
267 },
268 _ => unreachable!(),
269 }
270 }
271}
272
273#[derive(Debug)]
275pub struct KeyboardState {
276 pub keyboard: WlKeyboard,
278
279 pub loop_handle: LoopHandle<'static, WinitState>,
281
282 pub xkb_context: Context,
284
285 pub repeat_info: RepeatInfo,
287
288 pub repeat_token: Option<RegistrationToken>,
290
291 pub current_repeat: Option<u32>,
293}
294
295impl KeyboardState {
296 pub fn new(keyboard: WlKeyboard, loop_handle: LoopHandle<'static, WinitState>) -> Self {
297 Self {
298 keyboard,
299 loop_handle,
300 xkb_context: Context::new().unwrap(),
301 repeat_info: RepeatInfo::default(),
302 repeat_token: None,
303 current_repeat: None,
304 }
305 }
306}
307
308impl Drop for KeyboardState {
309 fn drop(&mut self) {
310 if self.keyboard.version() >= 3 {
311 self.keyboard.release();
312 }
313
314 if let Some(token) = self.repeat_token.take() {
315 self.loop_handle.remove(token);
316 }
317 }
318}
319
320#[derive(Debug, Clone, Copy, PartialEq, Eq)]
322pub enum RepeatInfo {
323 Repeat {
325 gap: Duration,
327
328 delay: Duration,
330 },
331
332 Disable,
334}
335
336impl Default for RepeatInfo {
337 fn default() -> Self {
341 Self::Repeat { gap: Duration::from_millis(40), delay: Duration::from_millis(200) }
342 }
343}
344
345#[derive(Debug)]
347pub struct KeyboardData {
348 window_id: Mutex<Option<WindowId>>,
350
351 seat: WlSeat,
353}
354
355impl KeyboardData {
356 pub fn new(seat: WlSeat) -> Self {
357 Self { window_id: Default::default(), seat }
358 }
359}
360
361fn key_input(
362 keyboard_state: &mut KeyboardState,
363 event_sink: &mut EventSink,
364 data: &KeyboardData,
365 keycode: u32,
366 state: ElementState,
367 repeat: bool,
368) {
369 let window_id = match *data.window_id.lock().unwrap() {
370 Some(window_id) => window_id,
371 None => return,
372 };
373
374 let device_id = crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId));
375 if let Some(mut key_context) = keyboard_state.xkb_context.key_context() {
376 let event = key_context.process_key_event(keycode, state, repeat);
377 let event = WindowEvent::KeyboardInput { device_id, event, is_synthetic: false };
378 event_sink.push_window_event(event, window_id);
379 }
380}