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