Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Obtain keyboard layout and keysyms with XCB

Tags:

keyboard

xcb

I'm creating an on-screen keyboard for Linux integrated in a simple Window Manager. I'm currently using XCB, and now I want to make the fake keystrokes. Everything works fine using xtest extension, except for the detail that I can't get the true keycodes from the keysyms I want to put.

Currently I'm using xcb_key_symbols_get_keycode, and then I use xcb_key_symbols_get_keysym to know which modifier I need to get that symbol. This works fine when the configured keyboard is the USA one. But I have a spanish keyboard, and this call only returns the USA configurations. In spanish keyboards several symbols are obtained with the right alt (altgr), but the former calls doesn't seem to support it.

So, how can I get the keycodes needed to get any keysym? I presume that I need the XKB extensions, but I've been unable to find them for XCB, and I don't want to rewrite the whole window manager for XLib.

Thanks.

like image 438
Rastersoft Avatar asked Sep 09 '13 00:09

Rastersoft


2 Answers

It's probably an outdated issue, but I find it still valid.

You can enable xkb extensions via xcb and then get the keymap, it's layout and the appropriate keysym for that layout via the xcb API (or more specifically from the xkb keymap's state).

Links:

  • libxkbcommon Quick Start
  • X11 Support to setup the xkb extension and to get the device id (see the previous link: You have to create the extension before trying to access any xcb_x11 calls). (with the device id you can call xkb_x11_keymap_new_from_device to return a xkb_keymap pointer).
  • xkb_keymap struct
  • Keyboard State (and more importantly xkb_state_key_get_sym()) here you can use the xkb_state to get the sym for the corresponding key.

I have to admit, that I did not actually do this in full, yet (only up to the keymap/layout/state thing). But it should be enough to get you started. :)

like image 75
fleischie Avatar answered Sep 20 '22 18:09

fleischie


The following code will print the whole keycode-to-keysym mapping. It is equivalent to xmodmap -pk or xmodmap -pke. That is, given any keycode, it gives you the keysyms associated to that keycode.

(Except that it only shows keysym values, not keysym names, which you can find in /usr/include/X11/keysymdef.h or using Xlib's XKeysymToString(), and I don't think there exists an XCB port of that function, but you could write your own based on keysymdef.h.) (On my X server, there's 7 keysyms per keycode, and I'd like to know if the X server can support more than that...)

/*
gcc keymap.c -o keymap -lxcb && ./keymap
*/
#include <stdlib.h>
#include <stdio.h>
#include <xcb/xcb.h>

void xcb_show_keyboard_mapping(xcb_connection_t* connection, const xcb_setup_t* setup){
  xcb_get_keyboard_mapping_reply_t* keyboard_mapping =
    xcb_get_keyboard_mapping_reply(
      connection,
      xcb_get_keyboard_mapping(
        connection,
        setup->min_keycode,
        setup->max_keycode - setup->min_keycode + 1),
      NULL);

  int          nkeycodes = keyboard_mapping->length / keyboard_mapping->keysyms_per_keycode;
  int          nkeysyms  = keyboard_mapping->length;
  xcb_keysym_t* keysyms  = (xcb_keysym_t*)(keyboard_mapping + 1);  // `xcb_keycode_t` is just a `typedef u8`, and `xcb_keysym_t` is just a `typedef u32`
  printf("nkeycodes %u  nkeysyms %u  keysyms_per_keycode %u\n\n", nkeycodes, nkeysyms, keyboard_mapping->keysyms_per_keycode);

  for(int keycode_idx=0; keycode_idx < nkeycodes; ++keycode_idx){
    printf("keycode %3u ", setup->min_keycode + keycode_idx);
    for(int keysym_idx=0; keysym_idx < keyboard_mapping->keysyms_per_keycode; ++keysym_idx){
      printf(" %8x", keysyms[keysym_idx + keycode_idx * keyboard_mapping->keysyms_per_keycode]);
    }
    putchar('\n');
  }

  free(keyboard_mapping);
}

int main(){
  xcb_connection_t*  connection = xcb_connect(NULL, NULL);
  const xcb_setup_t* setup      = xcb_get_setup(connection);
  xcb_show_keyboard_mapping(connection, setup);
  xcb_disconnect(connection);
}

If you want the opposite mapping (keysyms-to-keycodes), you may want xcb_key_symbols_get_keycode(), I don't know.


And no, you don't need XKB to handle keyboard stuff. Most of the stuff you could possibly want can be done with the core X protocol, including but not limited to modifying the aforementioned keycode-to-keysym mapping, grabbing the keyboard, grabbing the mouse, sending keyboard/mouse input, using all 8 modifiers, and writing "pseudo Unicode" (ie. all the symbols you find in keysymdef.h, which I don't think is oficially Unicode but does contain a lot of stuff).

like image 37
étale-cohomology Avatar answered Sep 19 '22 18:09

étale-cohomology