winit/platform_impl/linux/common/xkb/
keymap.rs

1//! XKB keymap.
2
3use std::ffi::c_char;
4use std::ops::Deref;
5use std::ptr::{self, NonNull};
6
7#[cfg(x11_platform)]
8use x11_dl::xlib_xcb::xcb_connection_t;
9#[cfg(wayland_platform)]
10use {memmap2::MmapOptions, std::os::unix::io::OwnedFd};
11
12use xkb::XKB_MOD_INVALID;
13use xkbcommon_dl::{
14    self as xkb, xkb_keycode_t, xkb_keymap, xkb_keymap_compile_flags, xkb_keysym_t,
15    xkb_layout_index_t, xkb_mod_index_t,
16};
17
18use crate::keyboard::{Key, KeyCode, KeyLocation, NamedKey, NativeKey, NativeKeyCode, PhysicalKey};
19#[cfg(x11_platform)]
20use crate::platform_impl::common::xkb::XKBXH;
21use crate::platform_impl::common::xkb::{XkbContext, XKBH};
22
23/// Map the raw X11-style keycode to the `KeyCode` enum.
24///
25/// X11-style keycodes are offset by 8 from the keycodes the Linux kernel uses.
26pub fn raw_keycode_to_physicalkey(keycode: u32) -> PhysicalKey {
27    scancode_to_physicalkey(keycode.saturating_sub(8))
28}
29
30/// Map the linux scancode to Keycode.
31///
32/// Both X11 and Wayland use keys with `+ 8` offset to linux scancode.
33pub fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
34    // The keycode values are taken from linux/include/uapi/linux/input-event-codes.h, as
35    // libxkbcommon's documentation seems to suggest that the keycode values we're interested in
36    // are defined by the Linux kernel. If Winit programs end up being run on other Unix-likes,
37    // I can only hope they agree on what the keycodes mean.
38    //
39    // Some of the keycodes are likely superfluous for our purposes, and some are ones which are
40    // difficult to test the correctness of, or discover the purpose of. Because of this, they've
41    // either been commented out here, or not included at all.
42    PhysicalKey::Code(match scancode {
43        0 => return PhysicalKey::Unidentified(NativeKeyCode::Xkb(0)),
44        1 => KeyCode::Escape,
45        2 => KeyCode::Digit1,
46        3 => KeyCode::Digit2,
47        4 => KeyCode::Digit3,
48        5 => KeyCode::Digit4,
49        6 => KeyCode::Digit5,
50        7 => KeyCode::Digit6,
51        8 => KeyCode::Digit7,
52        9 => KeyCode::Digit8,
53        10 => KeyCode::Digit9,
54        11 => KeyCode::Digit0,
55        12 => KeyCode::Minus,
56        13 => KeyCode::Equal,
57        14 => KeyCode::Backspace,
58        15 => KeyCode::Tab,
59        16 => KeyCode::KeyQ,
60        17 => KeyCode::KeyW,
61        18 => KeyCode::KeyE,
62        19 => KeyCode::KeyR,
63        20 => KeyCode::KeyT,
64        21 => KeyCode::KeyY,
65        22 => KeyCode::KeyU,
66        23 => KeyCode::KeyI,
67        24 => KeyCode::KeyO,
68        25 => KeyCode::KeyP,
69        26 => KeyCode::BracketLeft,
70        27 => KeyCode::BracketRight,
71        28 => KeyCode::Enter,
72        29 => KeyCode::ControlLeft,
73        30 => KeyCode::KeyA,
74        31 => KeyCode::KeyS,
75        32 => KeyCode::KeyD,
76        33 => KeyCode::KeyF,
77        34 => KeyCode::KeyG,
78        35 => KeyCode::KeyH,
79        36 => KeyCode::KeyJ,
80        37 => KeyCode::KeyK,
81        38 => KeyCode::KeyL,
82        39 => KeyCode::Semicolon,
83        40 => KeyCode::Quote,
84        41 => KeyCode::Backquote,
85        42 => KeyCode::ShiftLeft,
86        43 => KeyCode::Backslash,
87        44 => KeyCode::KeyZ,
88        45 => KeyCode::KeyX,
89        46 => KeyCode::KeyC,
90        47 => KeyCode::KeyV,
91        48 => KeyCode::KeyB,
92        49 => KeyCode::KeyN,
93        50 => KeyCode::KeyM,
94        51 => KeyCode::Comma,
95        52 => KeyCode::Period,
96        53 => KeyCode::Slash,
97        54 => KeyCode::ShiftRight,
98        55 => KeyCode::NumpadMultiply,
99        56 => KeyCode::AltLeft,
100        57 => KeyCode::Space,
101        58 => KeyCode::CapsLock,
102        59 => KeyCode::F1,
103        60 => KeyCode::F2,
104        61 => KeyCode::F3,
105        62 => KeyCode::F4,
106        63 => KeyCode::F5,
107        64 => KeyCode::F6,
108        65 => KeyCode::F7,
109        66 => KeyCode::F8,
110        67 => KeyCode::F9,
111        68 => KeyCode::F10,
112        69 => KeyCode::NumLock,
113        70 => KeyCode::ScrollLock,
114        71 => KeyCode::Numpad7,
115        72 => KeyCode::Numpad8,
116        73 => KeyCode::Numpad9,
117        74 => KeyCode::NumpadSubtract,
118        75 => KeyCode::Numpad4,
119        76 => KeyCode::Numpad5,
120        77 => KeyCode::Numpad6,
121        78 => KeyCode::NumpadAdd,
122        79 => KeyCode::Numpad1,
123        80 => KeyCode::Numpad2,
124        81 => KeyCode::Numpad3,
125        82 => KeyCode::Numpad0,
126        83 => KeyCode::NumpadDecimal,
127        85 => KeyCode::Lang5,
128        86 => KeyCode::IntlBackslash,
129        87 => KeyCode::F11,
130        88 => KeyCode::F12,
131        89 => KeyCode::IntlRo,
132        90 => KeyCode::Lang3,
133        91 => KeyCode::Lang4,
134        92 => KeyCode::Convert,
135        93 => KeyCode::KanaMode,
136        94 => KeyCode::NonConvert,
137        // 95 => KeyCode::KPJPCOMMA,
138        96 => KeyCode::NumpadEnter,
139        97 => KeyCode::ControlRight,
140        98 => KeyCode::NumpadDivide,
141        99 => KeyCode::PrintScreen,
142        100 => KeyCode::AltRight,
143        // 101 => KeyCode::LINEFEED,
144        102 => KeyCode::Home,
145        103 => KeyCode::ArrowUp,
146        104 => KeyCode::PageUp,
147        105 => KeyCode::ArrowLeft,
148        106 => KeyCode::ArrowRight,
149        107 => KeyCode::End,
150        108 => KeyCode::ArrowDown,
151        109 => KeyCode::PageDown,
152        110 => KeyCode::Insert,
153        111 => KeyCode::Delete,
154        // 112 => KeyCode::MACRO,
155        113 => KeyCode::AudioVolumeMute,
156        114 => KeyCode::AudioVolumeDown,
157        115 => KeyCode::AudioVolumeUp,
158        // 116 => KeyCode::POWER,
159        117 => KeyCode::NumpadEqual,
160        // 118 => KeyCode::KPPLUSMINUS,
161        119 => KeyCode::Pause,
162        // 120 => KeyCode::SCALE,
163        121 => KeyCode::NumpadComma,
164        122 => KeyCode::Lang1,
165        123 => KeyCode::Lang2,
166        124 => KeyCode::IntlYen,
167        125 => KeyCode::SuperLeft,
168        126 => KeyCode::SuperRight,
169        127 => KeyCode::ContextMenu,
170        // 128 => KeyCode::STOP,
171        // 129 => KeyCode::AGAIN,
172        // 130 => KeyCode::PROPS,
173        // 131 => KeyCode::UNDO,
174        // 132 => KeyCode::FRONT,
175        // 133 => KeyCode::COPY,
176        // 134 => KeyCode::OPEN,
177        // 135 => KeyCode::PASTE,
178        // 136 => KeyCode::FIND,
179        // 137 => KeyCode::CUT,
180        // 138 => KeyCode::HELP,
181        // 139 => KeyCode::MENU,
182        // 140 => KeyCode::CALC,
183        // 141 => KeyCode::SETUP,
184        // 142 => KeyCode::SLEEP,
185        // 143 => KeyCode::WAKEUP,
186        // 144 => KeyCode::FILE,
187        // 145 => KeyCode::SENDFILE,
188        // 146 => KeyCode::DELETEFILE,
189        // 147 => KeyCode::XFER,
190        // 148 => KeyCode::PROG1,
191        // 149 => KeyCode::PROG2,
192        // 150 => KeyCode::WWW,
193        // 151 => KeyCode::MSDOS,
194        // 152 => KeyCode::COFFEE,
195        // 153 => KeyCode::ROTATE_DISPLAY,
196        // 154 => KeyCode::CYCLEWINDOWS,
197        // 155 => KeyCode::MAIL,
198        // 156 => KeyCode::BOOKMARKS,
199        // 157 => KeyCode::COMPUTER,
200        // 158 => KeyCode::BACK,
201        // 159 => KeyCode::FORWARD,
202        // 160 => KeyCode::CLOSECD,
203        // 161 => KeyCode::EJECTCD,
204        // 162 => KeyCode::EJECTCLOSECD,
205        163 => KeyCode::MediaTrackNext,
206        164 => KeyCode::MediaPlayPause,
207        165 => KeyCode::MediaTrackPrevious,
208        166 => KeyCode::MediaStop,
209        // 167 => KeyCode::RECORD,
210        // 168 => KeyCode::REWIND,
211        // 169 => KeyCode::PHONE,
212        // 170 => KeyCode::ISO,
213        // 171 => KeyCode::CONFIG,
214        // 172 => KeyCode::HOMEPAGE,
215        // 173 => KeyCode::REFRESH,
216        // 174 => KeyCode::EXIT,
217        // 175 => KeyCode::MOVE,
218        // 176 => KeyCode::EDIT,
219        // 177 => KeyCode::SCROLLUP,
220        // 178 => KeyCode::SCROLLDOWN,
221        // 179 => KeyCode::KPLEFTPAREN,
222        // 180 => KeyCode::KPRIGHTPAREN,
223        // 181 => KeyCode::NEW,
224        // 182 => KeyCode::REDO,
225        183 => KeyCode::F13,
226        184 => KeyCode::F14,
227        185 => KeyCode::F15,
228        186 => KeyCode::F16,
229        187 => KeyCode::F17,
230        188 => KeyCode::F18,
231        189 => KeyCode::F19,
232        190 => KeyCode::F20,
233        191 => KeyCode::F21,
234        192 => KeyCode::F22,
235        193 => KeyCode::F23,
236        194 => KeyCode::F24,
237        // 200 => KeyCode::PLAYCD,
238        // 201 => KeyCode::PAUSECD,
239        // 202 => KeyCode::PROG3,
240        // 203 => KeyCode::PROG4,
241        // 204 => KeyCode::DASHBOARD,
242        // 205 => KeyCode::SUSPEND,
243        // 206 => KeyCode::CLOSE,
244        // 207 => KeyCode::PLAY,
245        // 208 => KeyCode::FASTFORWARD,
246        // 209 => KeyCode::BASSBOOST,
247        // 210 => KeyCode::PRINT,
248        // 211 => KeyCode::HP,
249        // 212 => KeyCode::CAMERA,
250        // 213 => KeyCode::SOUND,
251        // 214 => KeyCode::QUESTION,
252        // 215 => KeyCode::EMAIL,
253        // 216 => KeyCode::CHAT,
254        // 217 => KeyCode::SEARCH,
255        // 218 => KeyCode::CONNECT,
256        // 219 => KeyCode::FINANCE,
257        // 220 => KeyCode::SPORT,
258        // 221 => KeyCode::SHOP,
259        // 222 => KeyCode::ALTERASE,
260        // 223 => KeyCode::CANCEL,
261        // 224 => KeyCode::BRIGHTNESSDOW,
262        // 225 => KeyCode::BRIGHTNESSU,
263        // 226 => KeyCode::MEDIA,
264        // 227 => KeyCode::SWITCHVIDEOMODE,
265        // 228 => KeyCode::KBDILLUMTOGGLE,
266        // 229 => KeyCode::KBDILLUMDOWN,
267        // 230 => KeyCode::KBDILLUMUP,
268        // 231 => KeyCode::SEND,
269        // 232 => KeyCode::REPLY,
270        // 233 => KeyCode::FORWARDMAIL,
271        // 234 => KeyCode::SAVE,
272        // 235 => KeyCode::DOCUMENTS,
273        // 236 => KeyCode::BATTERY,
274        // 237 => KeyCode::BLUETOOTH,
275        // 238 => KeyCode::WLAN,
276        // 239 => KeyCode::UWB,
277        240 => return PhysicalKey::Unidentified(NativeKeyCode::Unidentified),
278        // 241 => KeyCode::VIDEO_NEXT,
279        // 242 => KeyCode::VIDEO_PREV,
280        // 243 => KeyCode::BRIGHTNESS_CYCLE,
281        // 244 => KeyCode::BRIGHTNESS_AUTO,
282        // 245 => KeyCode::DISPLAY_OFF,
283        // 246 => KeyCode::WWAN,
284        // 247 => KeyCode::RFKILL,
285        // 248 => KeyCode::KEY_MICMUTE,
286        _ => return PhysicalKey::Unidentified(NativeKeyCode::Xkb(scancode)),
287    })
288}
289
290pub fn physicalkey_to_scancode(key: PhysicalKey) -> Option<u32> {
291    let code = match key {
292        PhysicalKey::Code(code) => code,
293        PhysicalKey::Unidentified(code) => {
294            return match code {
295                NativeKeyCode::Unidentified => Some(240),
296                NativeKeyCode::Xkb(raw) => Some(raw),
297                _ => None,
298            };
299        },
300    };
301
302    match code {
303        KeyCode::Escape => Some(1),
304        KeyCode::Digit1 => Some(2),
305        KeyCode::Digit2 => Some(3),
306        KeyCode::Digit3 => Some(4),
307        KeyCode::Digit4 => Some(5),
308        KeyCode::Digit5 => Some(6),
309        KeyCode::Digit6 => Some(7),
310        KeyCode::Digit7 => Some(8),
311        KeyCode::Digit8 => Some(9),
312        KeyCode::Digit9 => Some(10),
313        KeyCode::Digit0 => Some(11),
314        KeyCode::Minus => Some(12),
315        KeyCode::Equal => Some(13),
316        KeyCode::Backspace => Some(14),
317        KeyCode::Tab => Some(15),
318        KeyCode::KeyQ => Some(16),
319        KeyCode::KeyW => Some(17),
320        KeyCode::KeyE => Some(18),
321        KeyCode::KeyR => Some(19),
322        KeyCode::KeyT => Some(20),
323        KeyCode::KeyY => Some(21),
324        KeyCode::KeyU => Some(22),
325        KeyCode::KeyI => Some(23),
326        KeyCode::KeyO => Some(24),
327        KeyCode::KeyP => Some(25),
328        KeyCode::BracketLeft => Some(26),
329        KeyCode::BracketRight => Some(27),
330        KeyCode::Enter => Some(28),
331        KeyCode::ControlLeft => Some(29),
332        KeyCode::KeyA => Some(30),
333        KeyCode::KeyS => Some(31),
334        KeyCode::KeyD => Some(32),
335        KeyCode::KeyF => Some(33),
336        KeyCode::KeyG => Some(34),
337        KeyCode::KeyH => Some(35),
338        KeyCode::KeyJ => Some(36),
339        KeyCode::KeyK => Some(37),
340        KeyCode::KeyL => Some(38),
341        KeyCode::Semicolon => Some(39),
342        KeyCode::Quote => Some(40),
343        KeyCode::Backquote => Some(41),
344        KeyCode::ShiftLeft => Some(42),
345        KeyCode::Backslash => Some(43),
346        KeyCode::KeyZ => Some(44),
347        KeyCode::KeyX => Some(45),
348        KeyCode::KeyC => Some(46),
349        KeyCode::KeyV => Some(47),
350        KeyCode::KeyB => Some(48),
351        KeyCode::KeyN => Some(49),
352        KeyCode::KeyM => Some(50),
353        KeyCode::Comma => Some(51),
354        KeyCode::Period => Some(52),
355        KeyCode::Slash => Some(53),
356        KeyCode::ShiftRight => Some(54),
357        KeyCode::NumpadMultiply => Some(55),
358        KeyCode::AltLeft => Some(56),
359        KeyCode::Space => Some(57),
360        KeyCode::CapsLock => Some(58),
361        KeyCode::F1 => Some(59),
362        KeyCode::F2 => Some(60),
363        KeyCode::F3 => Some(61),
364        KeyCode::F4 => Some(62),
365        KeyCode::F5 => Some(63),
366        KeyCode::F6 => Some(64),
367        KeyCode::F7 => Some(65),
368        KeyCode::F8 => Some(66),
369        KeyCode::F9 => Some(67),
370        KeyCode::F10 => Some(68),
371        KeyCode::NumLock => Some(69),
372        KeyCode::ScrollLock => Some(70),
373        KeyCode::Numpad7 => Some(71),
374        KeyCode::Numpad8 => Some(72),
375        KeyCode::Numpad9 => Some(73),
376        KeyCode::NumpadSubtract => Some(74),
377        KeyCode::Numpad4 => Some(75),
378        KeyCode::Numpad5 => Some(76),
379        KeyCode::Numpad6 => Some(77),
380        KeyCode::NumpadAdd => Some(78),
381        KeyCode::Numpad1 => Some(79),
382        KeyCode::Numpad2 => Some(80),
383        KeyCode::Numpad3 => Some(81),
384        KeyCode::Numpad0 => Some(82),
385        KeyCode::NumpadDecimal => Some(83),
386        KeyCode::Lang5 => Some(85),
387        KeyCode::IntlBackslash => Some(86),
388        KeyCode::F11 => Some(87),
389        KeyCode::F12 => Some(88),
390        KeyCode::IntlRo => Some(89),
391        KeyCode::Lang3 => Some(90),
392        KeyCode::Lang4 => Some(91),
393        KeyCode::Convert => Some(92),
394        KeyCode::KanaMode => Some(93),
395        KeyCode::NonConvert => Some(94),
396        KeyCode::NumpadEnter => Some(96),
397        KeyCode::ControlRight => Some(97),
398        KeyCode::NumpadDivide => Some(98),
399        KeyCode::PrintScreen => Some(99),
400        KeyCode::AltRight => Some(100),
401        KeyCode::Home => Some(102),
402        KeyCode::ArrowUp => Some(103),
403        KeyCode::PageUp => Some(104),
404        KeyCode::ArrowLeft => Some(105),
405        KeyCode::ArrowRight => Some(106),
406        KeyCode::End => Some(107),
407        KeyCode::ArrowDown => Some(108),
408        KeyCode::PageDown => Some(109),
409        KeyCode::Insert => Some(110),
410        KeyCode::Delete => Some(111),
411        KeyCode::AudioVolumeMute => Some(113),
412        KeyCode::AudioVolumeDown => Some(114),
413        KeyCode::AudioVolumeUp => Some(115),
414        KeyCode::NumpadEqual => Some(117),
415        KeyCode::Pause => Some(119),
416        KeyCode::NumpadComma => Some(121),
417        KeyCode::Lang1 => Some(122),
418        KeyCode::Lang2 => Some(123),
419        KeyCode::IntlYen => Some(124),
420        KeyCode::SuperLeft => Some(125),
421        KeyCode::SuperRight => Some(126),
422        KeyCode::ContextMenu => Some(127),
423        KeyCode::MediaTrackNext => Some(163),
424        KeyCode::MediaPlayPause => Some(164),
425        KeyCode::MediaTrackPrevious => Some(165),
426        KeyCode::MediaStop => Some(166),
427        KeyCode::F13 => Some(183),
428        KeyCode::F14 => Some(184),
429        KeyCode::F15 => Some(185),
430        KeyCode::F16 => Some(186),
431        KeyCode::F17 => Some(187),
432        KeyCode::F18 => Some(188),
433        KeyCode::F19 => Some(189),
434        KeyCode::F20 => Some(190),
435        KeyCode::F21 => Some(191),
436        KeyCode::F22 => Some(192),
437        KeyCode::F23 => Some(193),
438        KeyCode::F24 => Some(194),
439        _ => None,
440    }
441}
442
443pub fn keysym_to_key(keysym: u32) -> Key {
444    use xkbcommon_dl::keysyms;
445    Key::Named(match keysym {
446        // TTY function keys
447        keysyms::BackSpace => NamedKey::Backspace,
448        keysyms::Tab => NamedKey::Tab,
449        // keysyms::Linefeed => NamedKey::Linefeed,
450        keysyms::Clear => NamedKey::Clear,
451        keysyms::Return => NamedKey::Enter,
452        keysyms::Pause => NamedKey::Pause,
453        keysyms::Scroll_Lock => NamedKey::ScrollLock,
454        keysyms::Sys_Req => NamedKey::PrintScreen,
455        keysyms::Escape => NamedKey::Escape,
456        keysyms::Delete => NamedKey::Delete,
457
458        // IME keys
459        keysyms::Multi_key => NamedKey::Compose,
460        keysyms::Codeinput => NamedKey::CodeInput,
461        keysyms::SingleCandidate => NamedKey::SingleCandidate,
462        keysyms::MultipleCandidate => NamedKey::AllCandidates,
463        keysyms::PreviousCandidate => NamedKey::PreviousCandidate,
464
465        // Japanese keys
466        keysyms::Kanji => NamedKey::KanjiMode,
467        keysyms::Muhenkan => NamedKey::NonConvert,
468        keysyms::Henkan_Mode => NamedKey::Convert,
469        keysyms::Romaji => NamedKey::Romaji,
470        keysyms::Hiragana => NamedKey::Hiragana,
471        keysyms::Hiragana_Katakana => NamedKey::HiraganaKatakana,
472        keysyms::Zenkaku => NamedKey::Zenkaku,
473        keysyms::Hankaku => NamedKey::Hankaku,
474        keysyms::Zenkaku_Hankaku => NamedKey::ZenkakuHankaku,
475        // keysyms::Touroku => NamedKey::Touroku,
476        // keysyms::Massyo => NamedKey::Massyo,
477        keysyms::Kana_Lock => NamedKey::KanaMode,
478        keysyms::Kana_Shift => NamedKey::KanaMode,
479        keysyms::Eisu_Shift => NamedKey::Alphanumeric,
480        keysyms::Eisu_toggle => NamedKey::Alphanumeric,
481        // NOTE: The next three items are aliases for values we've already mapped.
482        // keysyms::Kanji_Bangou => NamedKey::CodeInput,
483        // keysyms::Zen_Koho => NamedKey::AllCandidates,
484        // keysyms::Mae_Koho => NamedKey::PreviousCandidate,
485
486        // Cursor control & motion
487        keysyms::Home => NamedKey::Home,
488        keysyms::Left => NamedKey::ArrowLeft,
489        keysyms::Up => NamedKey::ArrowUp,
490        keysyms::Right => NamedKey::ArrowRight,
491        keysyms::Down => NamedKey::ArrowDown,
492        // keysyms::Prior => NamedKey::PageUp,
493        keysyms::Page_Up => NamedKey::PageUp,
494        // keysyms::Next => NamedKey::PageDown,
495        keysyms::Page_Down => NamedKey::PageDown,
496        keysyms::End => NamedKey::End,
497        // keysyms::Begin => NamedKey::Begin,
498
499        // Misc. functions
500        keysyms::Select => NamedKey::Select,
501        keysyms::Print => NamedKey::PrintScreen,
502        keysyms::Execute => NamedKey::Execute,
503        keysyms::Insert => NamedKey::Insert,
504        keysyms::Undo => NamedKey::Undo,
505        keysyms::Redo => NamedKey::Redo,
506        keysyms::Menu => NamedKey::ContextMenu,
507        keysyms::Find => NamedKey::Find,
508        keysyms::Cancel => NamedKey::Cancel,
509        keysyms::Help => NamedKey::Help,
510        keysyms::Break => NamedKey::Pause,
511        keysyms::Mode_switch => NamedKey::ModeChange,
512        // keysyms::script_switch => NamedKey::ModeChange,
513        keysyms::Num_Lock => NamedKey::NumLock,
514
515        // Keypad keys
516        // keysyms::KP_Space => return Key::Character(" "),
517        keysyms::KP_Tab => NamedKey::Tab,
518        keysyms::KP_Enter => NamedKey::Enter,
519        keysyms::KP_F1 => NamedKey::F1,
520        keysyms::KP_F2 => NamedKey::F2,
521        keysyms::KP_F3 => NamedKey::F3,
522        keysyms::KP_F4 => NamedKey::F4,
523        keysyms::KP_Home => NamedKey::Home,
524        keysyms::KP_Left => NamedKey::ArrowLeft,
525        keysyms::KP_Up => NamedKey::ArrowUp,
526        keysyms::KP_Right => NamedKey::ArrowRight,
527        keysyms::KP_Down => NamedKey::ArrowDown,
528        // keysyms::KP_Prior => NamedKey::PageUp,
529        keysyms::KP_Page_Up => NamedKey::PageUp,
530        // keysyms::KP_Next => NamedKey::PageDown,
531        keysyms::KP_Page_Down => NamedKey::PageDown,
532        keysyms::KP_End => NamedKey::End,
533        // This is the key labeled "5" on the numpad when NumLock is off.
534        // keysyms::KP_Begin => NamedKey::Begin,
535        keysyms::KP_Insert => NamedKey::Insert,
536        keysyms::KP_Delete => NamedKey::Delete,
537        // keysyms::KP_Equal => NamedKey::Equal,
538        // keysyms::KP_Multiply => NamedKey::Multiply,
539        // keysyms::KP_Add => NamedKey::Add,
540        // keysyms::KP_Separator => NamedKey::Separator,
541        // keysyms::KP_Subtract => NamedKey::Subtract,
542        // keysyms::KP_Decimal => NamedKey::Decimal,
543        // keysyms::KP_Divide => NamedKey::Divide,
544
545        // keysyms::KP_0 => return Key::Character("0"),
546        // keysyms::KP_1 => return Key::Character("1"),
547        // keysyms::KP_2 => return Key::Character("2"),
548        // keysyms::KP_3 => return Key::Character("3"),
549        // keysyms::KP_4 => return Key::Character("4"),
550        // keysyms::KP_5 => return Key::Character("5"),
551        // keysyms::KP_6 => return Key::Character("6"),
552        // keysyms::KP_7 => return Key::Character("7"),
553        // keysyms::KP_8 => return Key::Character("8"),
554        // keysyms::KP_9 => return Key::Character("9"),
555
556        // Function keys
557        keysyms::F1 => NamedKey::F1,
558        keysyms::F2 => NamedKey::F2,
559        keysyms::F3 => NamedKey::F3,
560        keysyms::F4 => NamedKey::F4,
561        keysyms::F5 => NamedKey::F5,
562        keysyms::F6 => NamedKey::F6,
563        keysyms::F7 => NamedKey::F7,
564        keysyms::F8 => NamedKey::F8,
565        keysyms::F9 => NamedKey::F9,
566        keysyms::F10 => NamedKey::F10,
567        keysyms::F11 => NamedKey::F11,
568        keysyms::F12 => NamedKey::F12,
569        keysyms::F13 => NamedKey::F13,
570        keysyms::F14 => NamedKey::F14,
571        keysyms::F15 => NamedKey::F15,
572        keysyms::F16 => NamedKey::F16,
573        keysyms::F17 => NamedKey::F17,
574        keysyms::F18 => NamedKey::F18,
575        keysyms::F19 => NamedKey::F19,
576        keysyms::F20 => NamedKey::F20,
577        keysyms::F21 => NamedKey::F21,
578        keysyms::F22 => NamedKey::F22,
579        keysyms::F23 => NamedKey::F23,
580        keysyms::F24 => NamedKey::F24,
581        keysyms::F25 => NamedKey::F25,
582        keysyms::F26 => NamedKey::F26,
583        keysyms::F27 => NamedKey::F27,
584        keysyms::F28 => NamedKey::F28,
585        keysyms::F29 => NamedKey::F29,
586        keysyms::F30 => NamedKey::F30,
587        keysyms::F31 => NamedKey::F31,
588        keysyms::F32 => NamedKey::F32,
589        keysyms::F33 => NamedKey::F33,
590        keysyms::F34 => NamedKey::F34,
591        keysyms::F35 => NamedKey::F35,
592
593        // Modifiers
594        keysyms::Shift_L => NamedKey::Shift,
595        keysyms::Shift_R => NamedKey::Shift,
596        keysyms::Control_L => NamedKey::Control,
597        keysyms::Control_R => NamedKey::Control,
598        keysyms::Caps_Lock => NamedKey::CapsLock,
599        // keysyms::Shift_Lock => NamedKey::ShiftLock,
600
601        // keysyms::Meta_L => NamedKey::Meta,
602        // keysyms::Meta_R => NamedKey::Meta,
603        keysyms::Alt_L => NamedKey::Alt,
604        keysyms::Alt_R => NamedKey::Alt,
605        keysyms::Super_L => NamedKey::Super,
606        keysyms::Super_R => NamedKey::Super,
607        keysyms::Hyper_L => NamedKey::Hyper,
608        keysyms::Hyper_R => NamedKey::Hyper,
609
610        // XKB function and modifier keys
611        // keysyms::ISO_Lock => NamedKey::IsoLock,
612        // keysyms::ISO_Level2_Latch => NamedKey::IsoLevel2Latch,
613        keysyms::ISO_Level3_Shift => NamedKey::AltGraph,
614        keysyms::ISO_Level3_Latch => NamedKey::AltGraph,
615        keysyms::ISO_Level3_Lock => NamedKey::AltGraph,
616        // keysyms::ISO_Level5_Shift => NamedKey::IsoLevel5Shift,
617        // keysyms::ISO_Level5_Latch => NamedKey::IsoLevel5Latch,
618        // keysyms::ISO_Level5_Lock => NamedKey::IsoLevel5Lock,
619        // keysyms::ISO_Group_Shift => NamedKey::IsoGroupShift,
620        // keysyms::ISO_Group_Latch => NamedKey::IsoGroupLatch,
621        // keysyms::ISO_Group_Lock => NamedKey::IsoGroupLock,
622        keysyms::ISO_Next_Group => NamedKey::GroupNext,
623        // keysyms::ISO_Next_Group_Lock => NamedKey::GroupNextLock,
624        keysyms::ISO_Prev_Group => NamedKey::GroupPrevious,
625        // keysyms::ISO_Prev_Group_Lock => NamedKey::GroupPreviousLock,
626        keysyms::ISO_First_Group => NamedKey::GroupFirst,
627        // keysyms::ISO_First_Group_Lock => NamedKey::GroupFirstLock,
628        keysyms::ISO_Last_Group => NamedKey::GroupLast,
629        // keysyms::ISO_Last_Group_Lock => NamedKey::GroupLastLock,
630        keysyms::ISO_Left_Tab => NamedKey::Tab,
631        // keysyms::ISO_Move_Line_Up => NamedKey::IsoMoveLineUp,
632        // keysyms::ISO_Move_Line_Down => NamedKey::IsoMoveLineDown,
633        // keysyms::ISO_Partial_Line_Up => NamedKey::IsoPartialLineUp,
634        // keysyms::ISO_Partial_Line_Down => NamedKey::IsoPartialLineDown,
635        // keysyms::ISO_Partial_Space_Left => NamedKey::IsoPartialSpaceLeft,
636        // keysyms::ISO_Partial_Space_Right => NamedKey::IsoPartialSpaceRight,
637        // keysyms::ISO_Set_Margin_Left => NamedKey::IsoSetMarginLeft,
638        // keysyms::ISO_Set_Margin_Right => NamedKey::IsoSetMarginRight,
639        // keysyms::ISO_Release_Margin_Left => NamedKey::IsoReleaseMarginLeft,
640        // keysyms::ISO_Release_Margin_Right => NamedKey::IsoReleaseMarginRight,
641        // keysyms::ISO_Release_Both_Margins => NamedKey::IsoReleaseBothMargins,
642        // keysyms::ISO_Fast_Cursor_Left => NamedKey::IsoFastCursorLeft,
643        // keysyms::ISO_Fast_Cursor_Right => NamedKey::IsoFastCursorRight,
644        // keysyms::ISO_Fast_Cursor_Up => NamedKey::IsoFastCursorUp,
645        // keysyms::ISO_Fast_Cursor_Down => NamedKey::IsoFastCursorDown,
646        // keysyms::ISO_Continuous_Underline => NamedKey::IsoContinuousUnderline,
647        // keysyms::ISO_Discontinuous_Underline => NamedKey::IsoDiscontinuousUnderline,
648        // keysyms::ISO_Emphasize => NamedKey::IsoEmphasize,
649        // keysyms::ISO_Center_Object => NamedKey::IsoCenterObject,
650        keysyms::ISO_Enter => NamedKey::Enter,
651
652        // dead_grave..dead_currency
653
654        // dead_lowline..dead_longsolidusoverlay
655
656        // dead_a..dead_capital_schwa
657
658        // dead_greek
659
660        // First_Virtual_Screen..Terminate_Server
661
662        // AccessX_Enable..AudibleBell_Enable
663
664        // Pointer_Left..Pointer_Drag5
665
666        // Pointer_EnableKeys..Pointer_DfltBtnPrev
667
668        // ch..C_H
669
670        // 3270 terminal keys
671        // keysyms::3270_Duplicate => NamedKey::Duplicate,
672        // keysyms::3270_FieldMark => NamedKey::FieldMark,
673        // keysyms::3270_Right2 => NamedKey::Right2,
674        // keysyms::3270_Left2 => NamedKey::Left2,
675        // keysyms::3270_BackTab => NamedKey::BackTab,
676        keysyms::_3270_EraseEOF => NamedKey::EraseEof,
677        // keysyms::3270_EraseInput => NamedKey::EraseInput,
678        // keysyms::3270_Reset => NamedKey::Reset,
679        // keysyms::3270_Quit => NamedKey::Quit,
680        // keysyms::3270_PA1 => NamedKey::Pa1,
681        // keysyms::3270_PA2 => NamedKey::Pa2,
682        // keysyms::3270_PA3 => NamedKey::Pa3,
683        // keysyms::3270_Test => NamedKey::Test,
684        keysyms::_3270_Attn => NamedKey::Attn,
685        // keysyms::3270_CursorBlink => NamedKey::CursorBlink,
686        // keysyms::3270_AltCursor => NamedKey::AltCursor,
687        // keysyms::3270_KeyClick => NamedKey::KeyClick,
688        // keysyms::3270_Jump => NamedKey::Jump,
689        // keysyms::3270_Ident => NamedKey::Ident,
690        // keysyms::3270_Rule => NamedKey::Rule,
691        // keysyms::3270_Copy => NamedKey::Copy,
692        keysyms::_3270_Play => NamedKey::Play,
693        // keysyms::3270_Setup => NamedKey::Setup,
694        // keysyms::3270_Record => NamedKey::Record,
695        // keysyms::3270_ChangeScreen => NamedKey::ChangeScreen,
696        // keysyms::3270_DeleteWord => NamedKey::DeleteWord,
697        keysyms::_3270_ExSelect => NamedKey::ExSel,
698        keysyms::_3270_CursorSelect => NamedKey::CrSel,
699        keysyms::_3270_PrintScreen => NamedKey::PrintScreen,
700        keysyms::_3270_Enter => NamedKey::Enter,
701
702        keysyms::space => NamedKey::Space,
703        // exclam..Sinh_kunddaliya
704
705        // XFree86
706        // keysyms::XF86_ModeLock => NamedKey::ModeLock,
707
708        // XFree86 - Backlight controls
709        keysyms::XF86_MonBrightnessUp => NamedKey::BrightnessUp,
710        keysyms::XF86_MonBrightnessDown => NamedKey::BrightnessDown,
711        // keysyms::XF86_KbdLightOnOff => NamedKey::LightOnOff,
712        // keysyms::XF86_KbdBrightnessUp => NamedKey::KeyboardBrightnessUp,
713        // keysyms::XF86_KbdBrightnessDown => NamedKey::KeyboardBrightnessDown,
714
715        // XFree86 - "Internet"
716        keysyms::XF86_Standby => NamedKey::Standby,
717        keysyms::XF86_AudioLowerVolume => NamedKey::AudioVolumeDown,
718        keysyms::XF86_AudioRaiseVolume => NamedKey::AudioVolumeUp,
719        keysyms::XF86_AudioPlay => NamedKey::MediaPlay,
720        keysyms::XF86_AudioStop => NamedKey::MediaStop,
721        keysyms::XF86_AudioPrev => NamedKey::MediaTrackPrevious,
722        keysyms::XF86_AudioNext => NamedKey::MediaTrackNext,
723        keysyms::XF86_HomePage => NamedKey::BrowserHome,
724        keysyms::XF86_Mail => NamedKey::LaunchMail,
725        // keysyms::XF86_Start => NamedKey::Start,
726        keysyms::XF86_Search => NamedKey::BrowserSearch,
727        keysyms::XF86_AudioRecord => NamedKey::MediaRecord,
728
729        // XFree86 - PDA
730        keysyms::XF86_Calculator => NamedKey::LaunchApplication2,
731        // keysyms::XF86_Memo => NamedKey::Memo,
732        // keysyms::XF86_ToDoList => NamedKey::ToDoList,
733        keysyms::XF86_Calendar => NamedKey::LaunchCalendar,
734        keysyms::XF86_PowerDown => NamedKey::Power,
735        // keysyms::XF86_ContrastAdjust => NamedKey::AdjustContrast,
736        // keysyms::XF86_RockerUp => NamedKey::RockerUp,
737        // keysyms::XF86_RockerDown => NamedKey::RockerDown,
738        // keysyms::XF86_RockerEnter => NamedKey::RockerEnter,
739
740        // XFree86 - More "Internet"
741        keysyms::XF86_Back => NamedKey::BrowserBack,
742        keysyms::XF86_Forward => NamedKey::BrowserForward,
743        // keysyms::XF86_Stop => NamedKey::Stop,
744        keysyms::XF86_Refresh => NamedKey::BrowserRefresh,
745        keysyms::XF86_PowerOff => NamedKey::Power,
746        keysyms::XF86_WakeUp => NamedKey::WakeUp,
747        keysyms::XF86_Eject => NamedKey::Eject,
748        keysyms::XF86_ScreenSaver => NamedKey::LaunchScreenSaver,
749        keysyms::XF86_WWW => NamedKey::LaunchWebBrowser,
750        keysyms::XF86_Sleep => NamedKey::Standby,
751        keysyms::XF86_Favorites => NamedKey::BrowserFavorites,
752        keysyms::XF86_AudioPause => NamedKey::MediaPause,
753        // keysyms::XF86_AudioMedia => NamedKey::AudioMedia,
754        keysyms::XF86_MyComputer => NamedKey::LaunchApplication1,
755        // keysyms::XF86_VendorHome => NamedKey::VendorHome,
756        // keysyms::XF86_LightBulb => NamedKey::LightBulb,
757        // keysyms::XF86_Shop => NamedKey::BrowserShop,
758        // keysyms::XF86_History => NamedKey::BrowserHistory,
759        // keysyms::XF86_OpenURL => NamedKey::OpenUrl,
760        // keysyms::XF86_AddFavorite => NamedKey::AddFavorite,
761        // keysyms::XF86_HotLinks => NamedKey::HotLinks,
762        // keysyms::XF86_BrightnessAdjust => NamedKey::BrightnessAdjust,
763        // keysyms::XF86_Finance => NamedKey::BrowserFinance,
764        // keysyms::XF86_Community => NamedKey::BrowserCommunity,
765        keysyms::XF86_AudioRewind => NamedKey::MediaRewind,
766        // keysyms::XF86_BackForward => Key::???,
767        // XF86_Launch0..XF86_LaunchF
768
769        // XF86_ApplicationLeft..XF86_CD
770        keysyms::XF86_Calculater => NamedKey::LaunchApplication2, // Nice typo, libxkbcommon :)
771        // XF86_Clear
772        keysyms::XF86_Close => NamedKey::Close,
773        keysyms::XF86_Copy => NamedKey::Copy,
774        keysyms::XF86_Cut => NamedKey::Cut,
775        // XF86_Display..XF86_Documents
776        keysyms::XF86_Excel => NamedKey::LaunchSpreadsheet,
777        // XF86_Explorer..XF86iTouch
778        keysyms::XF86_LogOff => NamedKey::LogOff,
779        // XF86_Market..XF86_MenuPB
780        keysyms::XF86_MySites => NamedKey::BrowserFavorites,
781        keysyms::XF86_New => NamedKey::New,
782        // XF86_News..XF86_OfficeHome
783        keysyms::XF86_Open => NamedKey::Open,
784        // XF86_Option
785        keysyms::XF86_Paste => NamedKey::Paste,
786        keysyms::XF86_Phone => NamedKey::LaunchPhone,
787        // XF86_Q
788        keysyms::XF86_Reply => NamedKey::MailReply,
789        keysyms::XF86_Reload => NamedKey::BrowserRefresh,
790        // XF86_RotateWindows..XF86_RotationKB
791        keysyms::XF86_Save => NamedKey::Save,
792        // XF86_ScrollUp..XF86_ScrollClick
793        keysyms::XF86_Send => NamedKey::MailSend,
794        keysyms::XF86_Spell => NamedKey::SpellCheck,
795        keysyms::XF86_SplitScreen => NamedKey::SplitScreenToggle,
796        // XF86_Support..XF86_User2KB
797        keysyms::XF86_Video => NamedKey::LaunchMediaPlayer,
798        // XF86_WheelButton
799        keysyms::XF86_Word => NamedKey::LaunchWordProcessor,
800        // XF86_Xfer
801        keysyms::XF86_ZoomIn => NamedKey::ZoomIn,
802        keysyms::XF86_ZoomOut => NamedKey::ZoomOut,
803
804        // XF86_Away..XF86_Messenger
805        keysyms::XF86_WebCam => NamedKey::LaunchWebCam,
806        keysyms::XF86_MailForward => NamedKey::MailForward,
807        // XF86_Pictures
808        keysyms::XF86_Music => NamedKey::LaunchMusicPlayer,
809
810        // XF86_Battery..XF86_UWB
811        keysyms::XF86_AudioForward => NamedKey::MediaFastForward,
812        // XF86_AudioRepeat
813        keysyms::XF86_AudioRandomPlay => NamedKey::RandomToggle,
814        keysyms::XF86_Subtitle => NamedKey::Subtitle,
815        keysyms::XF86_AudioCycleTrack => NamedKey::MediaAudioTrack,
816        // XF86_CycleAngle..XF86_Blue
817        keysyms::XF86_Suspend => NamedKey::Standby,
818        keysyms::XF86_Hibernate => NamedKey::Hibernate,
819        // XF86_TouchpadToggle..XF86_TouchpadOff
820        keysyms::XF86_AudioMute => NamedKey::AudioVolumeMute,
821
822        // XF86_Switch_VT_1..XF86_Switch_VT_12
823
824        // XF86_Ungrab..XF86_ClearGrab
825        keysyms::XF86_Next_VMode => NamedKey::VideoModeNext,
826        // keysyms::XF86_Prev_VMode => NamedKey::VideoModePrevious,
827        // XF86_LogWindowTree..XF86_LogGrabInfo
828
829        // SunFA_Grave..SunFA_Cedilla
830
831        // keysyms::SunF36 => NamedKey::F36 | NamedKey::F11,
832        // keysyms::SunF37 => NamedKey::F37 | NamedKey::F12,
833
834        // keysyms::SunSys_Req => NamedKey::PrintScreen,
835        // The next couple of xkb (until SunStop) are already handled.
836        // SunPrint_Screen..SunPageDown
837
838        // SunUndo..SunFront
839        keysyms::SUN_Copy => NamedKey::Copy,
840        keysyms::SUN_Open => NamedKey::Open,
841        keysyms::SUN_Paste => NamedKey::Paste,
842        keysyms::SUN_Cut => NamedKey::Cut,
843
844        // SunPowerSwitch
845        keysyms::SUN_AudioLowerVolume => NamedKey::AudioVolumeDown,
846        keysyms::SUN_AudioMute => NamedKey::AudioVolumeMute,
847        keysyms::SUN_AudioRaiseVolume => NamedKey::AudioVolumeUp,
848        // SUN_VideoDegauss
849        keysyms::SUN_VideoLowerBrightness => NamedKey::BrightnessDown,
850        keysyms::SUN_VideoRaiseBrightness => NamedKey::BrightnessUp,
851        // SunPowerSwitchShift
852        0 => return Key::Unidentified(NativeKey::Unidentified),
853        _ => return Key::Unidentified(NativeKey::Xkb(keysym)),
854    })
855}
856
857pub fn keysym_location(keysym: u32) -> KeyLocation {
858    use xkbcommon_dl::keysyms;
859    match keysym {
860        keysyms::Shift_L
861        | keysyms::Control_L
862        | keysyms::Meta_L
863        | keysyms::Alt_L
864        | keysyms::Super_L
865        | keysyms::Hyper_L => KeyLocation::Left,
866        keysyms::Shift_R
867        | keysyms::Control_R
868        | keysyms::Meta_R
869        | keysyms::Alt_R
870        | keysyms::Super_R
871        | keysyms::Hyper_R => KeyLocation::Right,
872        keysyms::KP_0
873        | keysyms::KP_1
874        | keysyms::KP_2
875        | keysyms::KP_3
876        | keysyms::KP_4
877        | keysyms::KP_5
878        | keysyms::KP_6
879        | keysyms::KP_7
880        | keysyms::KP_8
881        | keysyms::KP_9
882        | keysyms::KP_Space
883        | keysyms::KP_Tab
884        | keysyms::KP_Enter
885        | keysyms::KP_F1
886        | keysyms::KP_F2
887        | keysyms::KP_F3
888        | keysyms::KP_F4
889        | keysyms::KP_Home
890        | keysyms::KP_Left
891        | keysyms::KP_Up
892        | keysyms::KP_Right
893        | keysyms::KP_Down
894        | keysyms::KP_Page_Up
895        | keysyms::KP_Page_Down
896        | keysyms::KP_End
897        | keysyms::KP_Begin
898        | keysyms::KP_Insert
899        | keysyms::KP_Delete
900        | keysyms::KP_Equal
901        | keysyms::KP_Multiply
902        | keysyms::KP_Add
903        | keysyms::KP_Separator
904        | keysyms::KP_Subtract
905        | keysyms::KP_Decimal
906        | keysyms::KP_Divide => KeyLocation::Numpad,
907        _ => KeyLocation::Standard,
908    }
909}
910
911#[derive(Debug)]
912pub struct XkbKeymap {
913    keymap: NonNull<xkb_keymap>,
914    _mods_indices: ModsIndices,
915    pub _core_keyboard_id: i32,
916}
917
918impl XkbKeymap {
919    #[cfg(wayland_platform)]
920    pub fn from_fd(context: &XkbContext, fd: OwnedFd, size: usize) -> Option<Self> {
921        let map = unsafe { MmapOptions::new().len(size).map_copy_read_only(&fd).ok()? };
922
923        let keymap = unsafe {
924            let keymap = (XKBH.xkb_keymap_new_from_string)(
925                (*context).as_ptr(),
926                map.as_ptr() as *const _,
927                xkb::xkb_keymap_format::XKB_KEYMAP_FORMAT_TEXT_V1,
928                xkb_keymap_compile_flags::XKB_KEYMAP_COMPILE_NO_FLAGS,
929            );
930            NonNull::new(keymap)?
931        };
932
933        Some(Self::new_inner(keymap, 0))
934    }
935
936    #[cfg(x11_platform)]
937    pub fn from_x11_keymap(
938        context: &XkbContext,
939        xcb: *mut xcb_connection_t,
940        core_keyboard_id: i32,
941    ) -> Option<Self> {
942        let keymap = unsafe {
943            (XKBXH.xkb_x11_keymap_new_from_device)(
944                context.as_ptr(),
945                xcb,
946                core_keyboard_id,
947                xkb_keymap_compile_flags::XKB_KEYMAP_COMPILE_NO_FLAGS,
948            )
949        };
950        let keymap = NonNull::new(keymap)?;
951        Some(Self::new_inner(keymap, core_keyboard_id))
952    }
953
954    fn new_inner(keymap: NonNull<xkb_keymap>, _core_keyboard_id: i32) -> Self {
955        let mods_indices = ModsIndices {
956            shift: mod_index_for_name(keymap, xkb::XKB_MOD_NAME_SHIFT),
957            caps: mod_index_for_name(keymap, xkb::XKB_MOD_NAME_CAPS),
958            ctrl: mod_index_for_name(keymap, xkb::XKB_MOD_NAME_CTRL),
959            alt: mod_index_for_name(keymap, xkb::XKB_MOD_NAME_ALT),
960            num: mod_index_for_name(keymap, xkb::XKB_MOD_NAME_NUM),
961            mod3: mod_index_for_name(keymap, b"Mod3\0"),
962            logo: mod_index_for_name(keymap, xkb::XKB_MOD_NAME_LOGO),
963            mod5: mod_index_for_name(keymap, b"Mod5\0"),
964        };
965
966        Self { keymap, _mods_indices: mods_indices, _core_keyboard_id }
967    }
968
969    #[cfg(x11_platform)]
970    pub fn mods_indices(&self) -> ModsIndices {
971        self._mods_indices
972    }
973
974    pub fn first_keysym_by_level(
975        &mut self,
976        layout: xkb_layout_index_t,
977        keycode: xkb_keycode_t,
978    ) -> xkb_keysym_t {
979        unsafe {
980            let mut keysyms = ptr::null();
981            let count = (XKBH.xkb_keymap_key_get_syms_by_level)(
982                self.keymap.as_ptr(),
983                keycode,
984                layout,
985                // NOTE: The level should be zero to ignore modifiers.
986                0,
987                &mut keysyms,
988            );
989
990            if count == 1 {
991                *keysyms
992            } else {
993                0
994            }
995        }
996    }
997
998    /// Check whether the given key repeats.
999    pub fn key_repeats(&mut self, keycode: xkb_keycode_t) -> bool {
1000        unsafe { (XKBH.xkb_keymap_key_repeats)(self.keymap.as_ptr(), keycode) == 1 }
1001    }
1002}
1003
1004impl Drop for XkbKeymap {
1005    fn drop(&mut self) {
1006        unsafe {
1007            (XKBH.xkb_keymap_unref)(self.keymap.as_ptr());
1008        };
1009    }
1010}
1011
1012impl Deref for XkbKeymap {
1013    type Target = NonNull<xkb_keymap>;
1014
1015    fn deref(&self) -> &Self::Target {
1016        &self.keymap
1017    }
1018}
1019
1020/// Modifier index in the keymap.
1021#[cfg_attr(not(x11_platform), allow(dead_code))]
1022#[derive(Default, Debug, Clone, Copy)]
1023pub struct ModsIndices {
1024    pub shift: Option<xkb_mod_index_t>,
1025    pub caps: Option<xkb_mod_index_t>,
1026    pub ctrl: Option<xkb_mod_index_t>,
1027    pub alt: Option<xkb_mod_index_t>,
1028    pub num: Option<xkb_mod_index_t>,
1029    pub mod3: Option<xkb_mod_index_t>,
1030    pub logo: Option<xkb_mod_index_t>,
1031    pub mod5: Option<xkb_mod_index_t>,
1032}
1033
1034fn mod_index_for_name(keymap: NonNull<xkb_keymap>, name: &[u8]) -> Option<xkb_mod_index_t> {
1035    unsafe {
1036        let mod_index =
1037            (XKBH.xkb_keymap_mod_get_index)(keymap.as_ptr(), name.as_ptr() as *const c_char);
1038        if mod_index == XKB_MOD_INVALID {
1039            None
1040        } else {
1041            Some(mod_index)
1042        }
1043    }
1044}