git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

src/server/keyboard.rs (12.1K)

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