Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
src/server/keyboard.rs (12.7K)
1 // SPDX-FileCopyrightText: © 2026 The River Developers
2 // SPDX-License-Identifier: GPL-3.0-only
3
4 use crate::ffi;
5 use crate::input_device::InputDevice;
6 use crate::server::{WlListener, wl_listener_remove, wl_signal_add};
7 use crate::keyboard_group::KeyboardGroup;
8 use std::collections::HashSet;
9
10 /// Key repeat defaults (keys/s, ms before the first repeat). A hardware
11 /// keyboard takes `input { repeat_rate repeat_delay }` over these
12 /// (`InputConfig::repeat_info`); the synthetic and virtual keyboards keep
13 /// them. A client can still change a device's via river's
14 /// `input_device.set_repeat_info`, until the next config load.
15 pub const DEFAULT_REPEAT_RATE: i32 = 40;
16 pub const DEFAULT_REPEAT_DELAY: i32 = 250;
17
18 #[derive(Clone, Copy)]
19 pub struct KeyboardConfig {
20 pub keymap: *mut ffi::xkb_keymap,
21 pub repeat_rate: i32,
22 pub repeat_delay: i32,
23 }
24
25 pub struct Keyboard {
26 pub device: *mut InputDevice,
27 pub wlr_keyboard: *mut ffi::wlr_keyboard,
28 pub key_listener: ffi::wl_listener,
29 pub modifiers_listener: ffi::wl_listener,
30 /// Registered for virtual keyboards only: their keymap arrives from the
31 /// client *after* creation (the zwp_virtual_keyboard_v1 keymap request),
32 /// so it must be forwarded to the group once it lands.
33 pub keymap_listener: ffi::wl_listener,
34 pub pressed: HashSet<u32>,
35 pub group: *mut KeyboardGroup,
36 pub group_link: ffi::wl_list,
37 pub config: KeyboardConfig,
38 }
39
40 impl Keyboard {
41 pub unsafe fn create(device: *mut InputDevice) -> *mut Self {
42 let wlr_keyboard = ffi::wlr_keyboard_from_input_device((*device).wlr_device);
43
44 let virtual_device = (*device).virtual_device;
45 let (repeat_rate, repeat_delay) = if virtual_device {
46 (DEFAULT_REPEAT_RATE, DEFAULT_REPEAT_DELAY)
47 } else {
48 (*(*(*device).seat).server).wm.input_config.repeat_info()
49 };
50 let mut keymap = std::ptr::null_mut();
51 if virtual_device {
52 let kbd_keymap = ffi::river_wlr_keyboard_get_keymap(wlr_keyboard);
53 if !kbd_keymap.is_null() {
54 keymap = kbd_keymap;
55 ffi::xkb_keymap_ref(keymap);
56 }
57 } else {
58 let server = (*(*device).seat).server;
59 keymap = (*server).xkb_config.default_keymap;
60 if !keymap.is_null() {
61 ffi::xkb_keymap_ref(keymap);
62 }
63 }
64
65 let keyboard = Box::into_raw(Box::new(Self {
66 device,
67 wlr_keyboard,
68 key_listener: std::mem::zeroed(),
69 modifiers_listener: std::mem::zeroed(),
70 keymap_listener: std::mem::zeroed(),
71 pressed: HashSet::new(),
72 group: std::ptr::null_mut(),
73 group_link: std::mem::zeroed(),
74 config: KeyboardConfig {
75 keymap,
76 repeat_rate,
77 repeat_delay,
78 },
79 }));
80
81 ffi::wl_list_init(&mut (*keyboard).group_link);
82 ffi::river_wlr_keyboard_set_data(wlr_keyboard, keyboard as *mut _);
83
84 let key_listener_ptr = &mut (*keyboard).key_listener as *mut ffi::wl_listener as *mut WlListener;
85 (*key_listener_ptr).notify = Some(handle_key);
86
87 let modifiers_listener_ptr = &mut (*keyboard).modifiers_listener as *mut ffi::wl_listener as *mut WlListener;
88 (*modifiers_listener_ptr).notify = Some(handle_modifiers);
89
90 let key_signal = ffi::river_wlr_keyboard_get_key_signal(wlr_keyboard);
91 wl_signal_add(key_signal, &mut (*keyboard).key_listener);
92
93 let modifiers_signal = ffi::river_wlr_keyboard_get_modifiers_signal(wlr_keyboard);
94 wl_signal_add(modifiers_signal, &mut (*keyboard).modifiers_listener);
95
96 if virtual_device {
97 let keymap_listener_ptr = &mut (*keyboard).keymap_listener as *mut ffi::wl_listener as *mut WlListener;
98 (*keymap_listener_ptr).notify = Some(handle_keymap);
99 let keymap_signal = ffi::river_wlr_keyboard_get_keymap_signal(wlr_keyboard);
100 wl_signal_add(keymap_signal, &mut (*keyboard).keymap_listener);
101 }
102
103 if !virtual_device && should_set_keymap((*(*device).seat).server) {
104 if !keymap.is_null() {
105 ffi::wlr_keyboard_set_keymap(wlr_keyboard, keymap);
106 }
107 }
108
109 (*device).destroy_fn = Some(destroy_callback);
110 (*device).destroy_data = keyboard as *mut _;
111
112 keyboard
113 }
114
115 pub unsafe fn destroy(keyboard: *mut Self) {
116 wl_listener_remove(&mut (*keyboard).key_listener);
117 wl_listener_remove(&mut (*keyboard).modifiers_listener);
118 // destroy_fn runs before the InputDevice is freed, so device is valid.
119 if (*(*keyboard).device).virtual_device {
120 wl_listener_remove(&mut (*keyboard).keymap_listener);
121 }
122
123 if !(*keyboard).group.is_null() {
124 let keys: Vec<u32> = (*keyboard).pressed.iter().cloned().collect();
125 (*(*keyboard).group).unref(&keys);
126 (*keyboard).group = std::ptr::null_mut();
127 }
128
129 if !(*keyboard).config.keymap.is_null() {
130 ffi::xkb_keymap_unref((*keyboard).config.keymap);
131 }
132
133 let _boxed = Box::from_raw(keyboard);
134 }
135
136 pub unsafe fn set_group(&mut self) {
137 assert!(self.group.is_null());
138 let seat = (*self.device).seat;
139
140 if !(*self.device).virtual_device {
141 let seat_groups_head = &mut (*seat).keyboard_groups as *mut ffi::wl_list as *mut crate::server::WlList;
142 let mut curr = (*seat_groups_head).next;
143 while curr != seat_groups_head {
144 let next = (*curr).next;
145 let group = crate::container_of!(curr, KeyboardGroup, link);
146 // A virtual keyboard's group is private to it (its keymap can
147 // change under it, and its IME grab is disabled) — hardware
148 // keyboards must never join one.
149 if (*group).virtual_device {
150 curr = next;
151 continue;
152 }
153 let config_ptr = &mut self.config as *mut KeyboardConfig;
154 if (*group).match_config(config_ptr) {
155 self.group = (*group).ref_group();
156 let keyboards_head = &mut (*self.group).keyboards as *mut ffi::wl_list as *mut crate::server::WlList;
157 crate::server::wl_list_insert(keyboards_head, &mut self.group_link as *mut ffi::wl_list as *mut crate::server::WlList);
158 return;
159 }
160 curr = next;
161 }
162 }
163
164 match KeyboardGroup::create(seat, self.config, (*self.device).virtual_device) {
165 Ok(group_ptr) => {
166 self.group = group_ptr;
167 let keyboards_head = &mut (*self.group).keyboards as *mut ffi::wl_list as *mut crate::server::WlList;
168 crate::server::wl_list_insert(keyboards_head, &mut self.group_link as *mut ffi::wl_list as *mut crate::server::WlList);
169 }
170 Err(err) => {
171 log::error!("failed to create KeyboardGroup: {}", err);
172 }
173 }
174 }
175
176 pub unsafe fn set_repeat_info(&mut self, rate: i32, delay: i32) {
177 assert!(!(*self.device).virtual_device);
178 self.config.repeat_rate = rate;
179 self.config.repeat_delay = delay;
180 if !self.group.is_null() {
181 let keys: Vec<u32> = self.pressed.iter().cloned().collect();
182 crate::server::wl_list_remove(&mut self.group_link as *mut ffi::wl_list as *mut crate::server::WlList);
183 (*self.group).unref(&keys);
184 self.group = std::ptr::null_mut();
185 }
186 self.set_group();
187 }
188
189 pub unsafe fn set_keymap(&mut self, keymap: *mut ffi::xkb_keymap) {
190 assert!(!(*self.device).virtual_device);
191 if should_set_keymap((*(*self.device).seat).server) {
192 ffi::wlr_keyboard_set_keymap(self.wlr_keyboard, keymap);
193 }
194 if !self.config.keymap.is_null() {
195 ffi::xkb_keymap_unref(self.config.keymap);
196 }
197 self.config.keymap = keymap;
198 if !keymap.is_null() {
199 ffi::xkb_keymap_ref(keymap);
200 }
201 if !self.group.is_null() {
202 let keys: Vec<u32> = self.pressed.iter().cloned().collect();
203 crate::server::wl_list_remove(&mut self.group_link as *mut ffi::wl_list as *mut crate::server::WlList);
204 (*self.group).unref(&keys);
205 self.group = std::ptr::null_mut();
206 }
207 self.set_group();
208 }
209 }
210
211 unsafe extern "C" fn destroy_callback(data: *mut std::ffi::c_void) {
212 Keyboard::destroy(data as *mut Keyboard);
213 }
214
215 unsafe fn should_set_keymap(server: *mut crate::server::Server) -> bool {
216 let backend = (*server).backend;
217 ffi::wlr_backend_is_wl(backend) || ffi::wlr_backend_is_x11(backend)
218 }
219
220 pub unsafe fn keysym_is_modifier(sym: u32) -> bool {
221 match sym {
222 ffi::XKB_KEY_Shift_L |
223 ffi::XKB_KEY_Shift_R |
224 ffi::XKB_KEY_Control_L |
225 ffi::XKB_KEY_Control_R |
226 ffi::XKB_KEY_Caps_Lock |
227 ffi::XKB_KEY_Shift_Lock |
228
229 ffi::XKB_KEY_Meta_L |
230 ffi::XKB_KEY_Meta_R |
231 ffi::XKB_KEY_Alt_L |
232 ffi::XKB_KEY_Alt_R |
233 ffi::XKB_KEY_Super_L |
234 ffi::XKB_KEY_Super_R |
235 ffi::XKB_KEY_Hyper_L |
236 ffi::XKB_KEY_Hyper_R |
237
238 ffi::XKB_KEY_Num_Lock |
239
240 ffi::XKB_KEY_ISO_Lock |
241 ffi::XKB_KEY_ISO_Level2_Latch |
242 ffi::XKB_KEY_ISO_Level3_Shift |
243 ffi::XKB_KEY_ISO_Level3_Latch |
244 ffi::XKB_KEY_ISO_Level3_Lock |
245 ffi::XKB_KEY_ISO_Level5_Shift |
246 ffi::XKB_KEY_ISO_Level5_Latch |
247 ffi::XKB_KEY_ISO_Level5_Lock |
248 ffi::XKB_KEY_ISO_Group_Shift |
249 ffi::XKB_KEY_ISO_Group_Latch |
250 ffi::XKB_KEY_ISO_Group_Lock |
251 ffi::XKB_KEY_ISO_Next_Group |
252 ffi::XKB_KEY_ISO_Next_Group_Lock |
253 ffi::XKB_KEY_ISO_Prev_Group |
254 ffi::XKB_KEY_ISO_Prev_Group_Lock |
255 ffi::XKB_KEY_ISO_First_Group |
256 ffi::XKB_KEY_ISO_First_Group_Lock |
257 ffi::XKB_KEY_ISO_Last_Group |
258 ffi::XKB_KEY_ISO_Last_Group_Lock => true,
259 _ => false,
260 }
261 }
262
263 unsafe extern "C" fn handle_key(listener: *mut ffi::wl_listener, data: *mut std::ffi::c_void) {
264 let keyboard = &mut *crate::container_of!(listener, Keyboard, key_listener);
265 let event = data as *mut ffi::wlr_keyboard_key_event;
266
267 if (*event).state == ffi::wl_keyboard_key_state_WL_KEYBOARD_KEY_STATE_RELEASED {
268 keyboard.pressed.remove(&(*event).keycode);
269 } else if (*event).state == ffi::wl_keyboard_key_state_WL_KEYBOARD_KEY_STATE_PRESSED {
270 if keyboard.pressed.len() < 32 {
271 keyboard.pressed.insert((*event).keycode);
272 }
273 // First deliberate input ends the session-restore settling phase
274 // (see the focus gate in Window::map).
275 if !keyboard.group.is_null() && !(*keyboard.group).seat.is_null() {
276 (*(*(*keyboard.group).seat).server).wm.startup_input_seen = true;
277 }
278 }
279
280 if !keyboard.group.is_null() {
281 (*keyboard.group).process_key(event);
282 }
283 }
284
285 /// Virtual keyboards only. The client's keymap request lands after the group
286 /// already exists, and the group's own wlr_keyboard is what processes keys —
287 /// with no keymap it has no xkb_state and every key is dropped. The group is
288 /// private to this keyboard (see set_group), so its config can be rewritten
289 /// in place instead of regrouping.
290 unsafe extern "C" fn handle_keymap(listener: *mut ffi::wl_listener, _data: *mut std::ffi::c_void) {
291 let keyboard = &mut *crate::container_of!(listener, Keyboard, keymap_listener);
292 let keymap = ffi::river_wlr_keyboard_get_keymap(keyboard.wlr_keyboard);
293
294 if !keymap.is_null() {
295 ffi::xkb_keymap_ref(keymap);
296 }
297 if !keyboard.config.keymap.is_null() {
298 ffi::xkb_keymap_unref(keyboard.config.keymap);
299 }
300 keyboard.config.keymap = keymap;
301
302 if !keyboard.group.is_null() {
303 let group = &mut *keyboard.group;
304 if !keymap.is_null() {
305 ffi::xkb_keymap_ref(keymap);
306 }
307 if !group.config.keymap.is_null() {
308 ffi::xkb_keymap_unref(group.config.keymap);
309 }
310 group.config.keymap = keymap;
311 if !keymap.is_null() {
312 group.process_keymap(keymap);
313 }
314 }
315 }
316
317 unsafe extern "C" fn handle_modifiers(listener: *mut ffi::wl_listener, _data: *mut std::ffi::c_void) {
318 let keyboard = &mut *crate::container_of!(listener, Keyboard, modifiers_listener);
319
320 if !keyboard.group.is_null() {
321 let modifiers = ffi::river_wlr_keyboard_get_modifiers(keyboard.wlr_keyboard);
322 (*keyboard.group).process_modifiers(*modifiers);
323
324 let seat = (*keyboard.group).seat;
325 if !seat.is_null() && !(*seat).server.is_null() {
326 (*(*seat).server).wm.update_status();
327 (*(*seat).server).wm.refresh_adjust_held();
328 }
329 }
330 }