Skip to main content

xmodmap_pke/
lib.rs

1use std::collections::HashMap;
2use std::ffi::CStr;
3use x11::xlib::{
4    Display, KeyCode, KeySym, XCloseDisplay, XDisplayKeycodes, XFree, XGetKeyboardMapping,
5    XKeysymToString, XOpenDisplay,
6};
7
8pub type XmodmapPke = HashMap<u8, Vec<String>>;
9
10/// Return `HashMap` with `KeyCode` as key and vector of `KeySyms` as value
11/// (This block of code was taken from original `xmodmap` source code)
12pub fn xmodmap_pke() -> Result<XmodmapPke, String> {
13    let dpy: *mut Display = unsafe { XOpenDisplay(std::ptr::null::<libc::c_char>()) };
14    let mut xmodmap_pke_table: XmodmapPke = HashMap::new();
15    let mut min_keycode = 0;
16    let mut max_keycode = 0;
17    let mut keysyms_per_keycode = 0;
18    let mut keymap: *mut KeySym;
19    let origkeymap: *mut KeySym;
20    unsafe {
21        XDisplayKeycodes(dpy, &mut min_keycode, &mut max_keycode);
22    }
23    origkeymap = unsafe {
24        XGetKeyboardMapping(
25            dpy,
26            min_keycode as KeyCode,
27            max_keycode - min_keycode + 1_i32,
28            &mut keysyms_per_keycode,
29        )
30    };
31    if origkeymap.is_null() {
32        return Err("unable to get keyboard mapping table.".to_string());
33    }
34    keymap = origkeymap;
35    for i in min_keycode..=max_keycode {
36        let mut max = keysyms_per_keycode - 1;
37        while max >= 0 && unsafe { *keymap.offset(max as isize) } == 0_u64 {
38            max -= 1
39        }
40        let mut ksyms: Vec<String> = Vec::new();
41        for j in 0..=max {
42            let ks: KeySym = unsafe { *keymap.offset(j as isize) };
43            let s = if ks == 0_u64 {
44                "NoSymbol"
45            } else {
46                unsafe { CStr::from_ptr(XKeysymToString(ks)) }
47                    .to_str()
48                    .unwrap()
49            };
50            if s.is_empty() {
51                ksyms.push(format!("{:0>4x}", ks));
52            } else {
53                ksyms.push(s.to_string());
54            }
55        }
56        keymap = unsafe { keymap.offset(keysyms_per_keycode as isize) };
57        xmodmap_pke_table.insert(i as u8, ksyms);
58    }
59    unsafe {
60        XFree(origkeymap.cast::<i8>().cast::<libc::c_void>());
61        XCloseDisplay(dpy);
62    }
63    Ok(xmodmap_pke_table)
64}