X11: XKB (2) - XKB 詳細データ

XKB 詳細データ
XKB では、キーボードに関する色々な設定を細かく変更できるので、クライアントがそれらをまとめて取得したり、変更できるように、すべての関連データを一つの構造体に格納することができます。

それが XkbDescRec 構造体です (そのポインタ型は XkbDescPtr)。
XkbDescRec 構造体
typedef struct {
    struct _XDisplay *  display;
    unsigned short      flags;
    unsigned short      device_spec;
    KeyCode             min_key_code;
    KeyCode             max_key_code;
    XkbControlsPtr      ctrls;
    XkbServerMapPtr     server;
    XkbClientMapPtr     map;
    XkbIndicatorPtr     indicators;
    XkbNamesPtr         names;
    XkbCompatMapPtr     compat;
    XkbGeometryPtr      geom;
} XkbDescRec, *XkbDescPtr;

flagsプライベート値。変更しないこと
device_specキーボードのデバイスID または XkbUseCoreKbd
min_key_code
max_key_code
指定デバイスの、最小キーコードと最大キーコード
ctrls機能のコントロール関連
serverサーバー用のマップ
mapクライアント用のマップ
indicatorsインディケータ (LED) 関連
names各名前の情報
compat互換性マップ
geomキーボードのジオメトリ関連 (物理的なキー配置)

Xkb*Ptr の各データは、必要なデータのみ確保してセットすることができます。
指定デバイスの詳細データを取得
XkbDescPtr XkbGetKeyboard(Display *display, unsigned int which, unsigned int device_spec);

//which
#define XkbClientMapMask        (1L << 0)
#define XkbServerMapMask        (1L << 1)
#define XkbCompatMapMask        (1L << 2)
#define XkbIndicatorMapMask     (1L << 3)
#define XkbNamesMask            (1L << 4)
#define XkbGeometryMask         (1L << 5)
#define XkbControlsMask         (1L << 6)
#define XkbAllComponentsMask    (0x7f)

device_spec で指定したデバイスの詳細データを、確保して返します。
which は、Xkb*Ptr の各データのうち、取得するもののマスクです。
解放
void XkbFreeKeyboard(XkbDescPtr xkb, unsigned int which, Bool free_all);

XkbDescRec 構造体のデータを解放します。

which は、上記と同じです。解放するデータのマスクを指定します。
各データを解放した上で、ポインタを NULL に設定します。

free_all が True の場合は、xkb 自身も含めて、すべてのデータを解放します。which は無視されます。
名前
XkbDescRec 構造体の XkbNamesPtr names には、XKB に関する各名前のデータが格納されています。

Atom もしくは、4文字のキー名が含まれています。

#define  XkbKeyNameLength      4
#define  XkbKeyNumVirtualMods  16
#define  XkbKeyNumIndicators   32
#define  XkbKeyNumKbdGroups    4
#define  XkbMaxRadioGroups     32

typedef struct {
    char  name[XkbKeyNameLength];
} XkbKeyNameRec, *XkbKeyNamePtr;

typedef struct {
    char  real[XkbKeyNameLength];
    char  alias[XkbKeyNameLength];
} XkbKeyAliasRec, *XkbKeyAliasPtr;

typedef struct _XkbNamesRec {
    Atom            keycodes;
    Atom            geometry;
    Atom            symbols;
    Atom            types;
    Atom            compat;
    Atom            vmods[XkbNumVirtualMods];
    Atom            indicators[XkbNumIndicators];
    Atom            groups[XkbNumKbdGroups];
    XkbKeyNamePtr   keys;
    XkbKeyAliasPtr  key_aliases;
    Atom *          radio_groups;
    Atom            phys_symbols;
    unsigned char   num_keys;
    unsigned char   num_key_aliases;
    unsigned short  num_rg;
} XkbNamesRec, *XkbNamesPtr;

vmods各仮想修飾子の名前
indicators各インディケータ (LED) の名前
groups各グループの名前
keysnum_keys 個の配列。
キーコードをインデックスとした、各キーの名前 (4byte)。
key_aliasesnum_key_aliases 個の配列。
実際のキー名と、エイリアス (別名) のキー名のペア。

real は keys 内にある名前で、alias はその別名の名前です。
radio_groupsnum_rg 個の配列。
キーをラジオグループとして扱う場合の、各グループの名前
プログラム
XKB の名前の情報を表示します。

※XkbGetKeyboard 関数で、which に XkbNamesMask だけを指定すると、NULL が返ります。名前の情報を取得するには、他のデータも必要となるので、ここではすべてのデータを取得しています。

$ cc -o run e12-xkb2.c util.c -lXlib

<e12-xkb2.c>
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/XKBlib.h>
#include "util.h"

static void _put_names(XkbNamesPtr p)
{
    int i;

    put_atom_name_line("keycodes: ", p->keycodes);
    put_atom_name_line("geometry: ", p->geometry);
    put_atom_name_line("symbols: ", p->symbols);
    put_atom_name_line("types: ", p->types);
    put_atom_name_line("compat: ", p->compat);
    put_atom_name_line("phys_symbols: ", p->phys_symbols);

    //vmods

    printf("--- vmods ---\n");

    for(i = 0; i < XkbNumVirtualMods; i++)
    {
        if(p->vmods[i])
        {
            printf("[%d] ", i);
            put_atom_name_line(NULL, p->vmods[i]);
        }
    }

    //indicators

    printf("--- indicators ---\n");

    for(i = 0; i < XkbNumIndicators; i++)
    {
        if(p->indicators[i])
        {
            printf("[%d] ", i);
            put_atom_name_line(NULL, p->indicators[i]);
        }
    }

    //groups

    printf("--- groups ---\n");

    for(i = 0; i < XkbNumKbdGroups; i++)
    {
        if(p->groups[i])
        {
            printf("[%d] ", i);
            put_atom_name_line(NULL, p->groups[i]);
        }
    }

    //keys

    printf("--- keys ---\n");

    for(i = 0; i < p->num_keys; i++)
        printf("[%d] %.4s\n", i, p->keys[i].name);

    //key_aliases

    printf("--- key_aliases ---\n");

    for(i = 0; i < p->num_key_aliases; i++)
    {
        printf("[%d] real(%.4s) alias(%.4s)\n",
            i, p->key_aliases[i].real, p->key_aliases[i].alias);
    }

    //radio_groups

    printf("--- radio_groups ---\n");

    for(i = 0; i < p->num_rg; i++)
    {
        printf("[%d] ", i);
        put_atom_name_line(NULL, p->radio_groups[i]);
    }
}

int main(int argc,char **argv)
{
    Display *disp;
    XkbDescPtr desc;
    
    disp = XOpenDisplay(NULL);
    if(!disp) return 1;

    set_display(disp);

    //XKB 初期化

    if(init_xkb(disp, NULL))
        return 1;

    //データ取得

    desc = XkbGetKeyboard(disp, XkbAllComponentsMask, XkbUseCoreKbd);

    _put_names(desc->names);

    XkbFreeKeyboard(desc, 0, True);

    XCloseDisplay(disp);

    return 0;
}
実行例
keycodes: "evdev_aliases(qwerty)"
geometry: <None>
symbols: "pc_jp_inet(evdev)"
types: "complete"
compat: "complete_japan"
phys_symbols: "pc_jp_inet(evdev)"
--- vmods ---
[0] "NumLock"
[1] "Alt"
[2] "LevelThree"
[3] "LevelFive"
[4] "Meta"
[5] "Super"
[6] "Hyper"
[7] "ScrollLock"
--- indicators ---
[0] "Caps Lock"
[1] "Num Lock"
[2] "Scroll Lock"
[3] "Compose"
[4] "Kana"
[5] "Sleep"
[6] "Suspend"
[7] "Mute"
[8] "Misc"
[9] "Mail"
[10] "Charging"
[11] "Shift Lock"
[12] "Group 2"
[13] "Mouse Keys"
--- groups ---
[0] "Japanese"
--- keys ---
[0] 
[1] 
[2] 
[3] 
[4] 
[5] 
[6] 
[7] 
[8] 
[9] ESC
[10] AE01
[11] AE02
[12] AE03
...
--- key_aliases ---
[0] real(BKSL) alias(AC12)
[1] real(RALT) alias(ALGR)
[2] real(COMP) alias(MENU)
[3] real(TLDE) alias(HZTG)
[4] real(LWIN) alias(LMTA)
...