Reputation: 1951
I am trying to use the XKB extension to XCB to capture keyboard input. The particular implementation that I'm writing is in rust, however the erroneous part of the code is mostly just calls through FFI. My goal is to be able to process keyboard events, such as when a key is pressed, released, etc., and to be able to convert the keycodes into unicode. Currently I am trying to get this example from the libxkbcommon quick guide working.
Below is the code I tried:
let (conn, screen_num) = Connection::connect(None)?;
// Other code...
let raw_conn = conn.get_raw_conn() as *mut xkbcommon_sys::xcb_connection_t;
let context = unsafe { xkb_context_new(XKB_CONTEXT_NO_FLAGS) };
if context.is_null() {
return Err(Error::XkbContextInit);
}
let device_id = unsafe { xkb_x11_get_core_keyboard_device_id(raw_conn) };
// This branch is taken
if device_id == -1 {
unsafe { xkb_context_unref(context); }
return Err(Error::XkbGetCoreKbDev);
}
I expected to be able to get the device ID of the core keyboard, however instead the function returned -1
, signaling an error.
After some experimenting and digging around, I found that the xkb_x11_get_core_keyboard_device_id
function was specifically failing on this request, which used XCB_XKB_ID_USE_CORE_KBD
as the value for the device spec. Since I don't get much error information from this function, I translated the request to the X server into rust, and got the following error:
// Output from debugging the returned error enum
Protocol(
X(
Access(
RequestError {
response_type: 0,
error_code: 10,
sequence: 3,
bad_value: 2003,
minor_opcode: 1,
major_opcode: 130,
pad: 1
}
)
)
)
I also tried some of the other values for the device spec listed here, but received the same error.
Unsure whether this was an issue with the X server, I tried it on my installation of Kali as well as an Ubuntu 20.04 VM, both of which yielded the same error (although with different values for the bad_value
field). Furthermore, any time I use XCB_XKB_ID_USE_CORE_KBD
where a device spec is required, I get this error. I'm not really sure what could be causing this issue. This seems to be specifically related to XKB since I am also using XCB to capture the screen, and I have not had any errors with that so far. Any help or guidance would be appreciated.
Upvotes: 1
Views: 339
Reputation: 11
If you are using the xcb and xkbcommon crates, they have an example using the (currently) beta versions of the crates that do this using the API instead of unsafe functions:
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let device_id = xkb::x11::get_core_keyboard_device_id(&connection);
let keymap = xkb::x11::keymap_new_from_device(
&context,
&connection,
device_id,
xkb::KEYMAP_COMPILE_NO_FLAGS,
);
let state = xkb::x11::state_new_from_device(&keymap, &connection, device_id);
https://github.com/rust-x-bindings/toy_xcb/blob/master/src/keyboard.rs
Upvotes: 1
Reputation: 1951
After searching around for a while, I found this post which linked to some documentation which made me realize that I was never setting up the XKB extension. Adding the following code fixed the issue:
let res = unsafe {
xkb_x11_setup_xkb_extension(
raw_conn,
MAJOR_VERSION as u16,
MINOR_VERSION as u16,
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut()
)
};
if res == 0 {
return Err(Error::XkbInit);
}
Upvotes: 1