linux - XKB : How to convert a keycode to keysym

标签 linux keyboard x11 keycode

我只是想获取一个 KeyCode 和一个修饰符掩码,然后使用 Xkb 扩展将其转换为 KeySym。我似乎无法弄清楚为什么这不起作用。很明显修饰符不匹配,但我不知道为什么。我什至不知道我是否正确地转换了组。

#include <stdio.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/XKBlib.h>

void check(XkbDescPtr keyboard_map, KeyCode keycode, unsigned int mask) {
    //What the hell is diff between XkbKeyGroupInfo and XkbKeyNumGroups?
    unsigned char info = XkbKeyGroupInfo(keyboard_map, keycode);
    int num_groups = XkbKeyNumGroups(keyboard_map, keycode);

    int key_width = XkbKeyGroupsWidth(keyboard_map, keycode);
    //int num_syms = XkbKeyNumSyms(keyboard_map, keycode);

    //Get the group
    unsigned int group = 0; // What should this default to?
    switch (XkbOutOfRangeGroupAction(info)) {
        case XkbRedirectIntoRange:
            /* If the RedirectIntoRange flag is set, the four least significant 
            * bits of the groups wrap control specify the index of a group to 
            * which all illegal groups correspond. If the specified group is 
            * also out of range, all illegal groups map to Group1.
            */
            printf("XkbRedirectIntoRange\n");
            group = XkbOutOfRangeGroupInfo(info);
            if (group >= num_groups) {
                group = 0;
            }
        break;

        case XkbClampIntoRange:
            /* If the ClampIntoRange flag is set, out-of-range groups correspond 
            * to the nearest legal group. Effective groups larger than the 
            * highest supported group are mapped to the highest supported group; 
            * effective groups less than Group1 are mapped to Group1 . For 
            * example, a key with two groups of symbols uses Group2 type and 
            * symbols if the global effective group is either Group3 or Group4.
            */
            printf("XkbClampIntoRange\n");
            group = num_groups - 1;
        break;

        case XkbWrapIntoRange:
            /* If neither flag is set, group is wrapped into range using integer 
            * modulus. For example, a key with two groups of symbols for which 
            * groups wrap uses Group1 symbols if the global effective group is 
            * Group3 or Group2 symbols if the global effective group is Group4.
            */
            printf("XkbWrapIntoRange\n");
        default:
            printf("Default\n");
            if (num_groups != 0) {
                group %= num_groups;
            }
        break;
    }
    printf("Group Info %d, %d, %d\n", group, num_groups, key_width);
    //printf("Mask Info %d, %d, %d, %d, %d, %d, %d, %d\n", ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask);

    XkbKeyTypePtr key_type = XkbKeyKeyType(keyboard_map, keycode, group);

    KeySym keysym = NoSymbol;
    int i;
    for (i = 0; i < key_type->map_count; i++) {
        if (key_type->map[i].active &&  key_type->map[i].mods.mask == mask) {
            keysym = XkbKeySymEntry(keyboard_map, keycode, i, group);
        }
    }

    //printf("%s\n", XKeysymToString(keysym));
    printf("KeyCode: %d\n", (int) keycode);
    printf("KeySym:  %d\n", (int) keysym);
}

int main(int argc, const char * argv[]) {
    Display * display;

    //Try to attach to the default X11 display.
    display = XOpenDisplay(NULL);
    if(display == NULL) {
        printf("Error: Could not open display!\n");
        return EXIT_FAILURE;
    }

    //Get the map
    XkbDescPtr keyboard_map = XkbGetMap(display, XkbAllClientInfoMask, XkbUseCoreKbd);

    KeyCode keycode = 56; // b
    check(keyboard_map, keycode, ShiftMask | LockMask | ControlMask);

    //Close the connection to the selected X11 display.
    XCloseDisplay(display);

    return EXIT_SUCCESS;
}

最佳答案

经过反复试验,我终于弄明白了。 XKeycodeToKeysym 显然已损坏,并且未为扩展索引定义索引值计算。

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/XKBlib.h>

KeySym KeyCodeToKeySym(Display * display, KeyCode keycode, unsigned int event_mask) {
    KeySym keysym = NoSymbol;

    //Get the map
    XkbDescPtr keyboard_map = XkbGetMap(display, XkbAllClientInfoMask, XkbUseCoreKbd);
    if (keyboard_map) {
        //What is diff between XkbKeyGroupInfo and XkbKeyNumGroups?
        unsigned char info = XkbKeyGroupInfo(keyboard_map, keycode);
        unsigned int num_groups = XkbKeyNumGroups(keyboard_map, keycode);

        //Get the group
        unsigned int group = 0x00;
        switch (XkbOutOfRangeGroupAction(info)) {
            case XkbRedirectIntoRange:
                /* If the RedirectIntoRange flag is set, the four least significant
                 * bits of the groups wrap control specify the index of a group to
                 * which all illegal groups correspond. If the specified group is
                 * also out of range, all illegal groups map to Group1.
                 */
                group = XkbOutOfRangeGroupInfo(info);
                if (group >= num_groups) {
                    group = 0;
                }
            break;

            case XkbClampIntoRange:
                /* If the ClampIntoRange flag is set, out-of-range groups correspond
                 * to the nearest legal group. Effective groups larger than the
                 * highest supported group are mapped to the highest supported group;
                 * effective groups less than Group1 are mapped to Group1 . For
                 * example, a key with two groups of symbols uses Group2 type and
                 * symbols if the global effective group is either Group3 or Group4.
                 */
                group = num_groups - 1;
            break;

            case XkbWrapIntoRange:
                /* If neither flag is set, group is wrapped into range using integer
                 * modulus. For example, a key with two groups of symbols for which
                 * groups wrap uses Group1 symbols if the global effective group is
                 * Group3 or Group2 symbols if the global effective group is Group4.
                 */
            default:
                if (num_groups != 0) {
                    group %= num_groups;
                }
            break;
        }

        XkbKeyTypePtr key_type = XkbKeyKeyType(keyboard_map, keycode, group);
        unsigned int active_mods = event_mask & key_type->mods.mask;

        int i, level = 0;
        for (i = 0; i < key_type->map_count; i++) {
            if (key_type->map[i].active && key_type->map[i].mods.mask == active_mods) {
                level = key_type->map[i].level;
            }
        }

        keysym = XkbKeySymEntry(keyboard_map, keycode, level, group);
        XkbFreeClientMap(keyboard_map, XkbAllClientInfoMask, true);
    }

    return keysym;
}

int main(int argc, const char * argv[]) {
    Display * display;

    //Try to attach to the default X11 display.
    display = XOpenDisplay(NULL);
    if(display == NULL) {
        printf("Error: Could not open display!\n");
        return EXIT_FAILURE;
    }

    KeyCode keycode = 56; // b
    unsigned int event_mask = ShiftMask | LockMask;
    KeySym keysym = KeyCodeToKeySym(display, keycode, event_mask);

    printf("KeySym: %s\n", XKeysymToString(keysym));

    //Close the connection to the selected X11 display.
    XCloseDisplay(display);

    return EXIT_SUCCESS;
}

关于linux - XKB : How to convert a keycode to keysym,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10157826/

相关文章:

linux - 在 Linux/Unix 中显示多个文件

php - Codeigniter 通过命令行访问方法

python - 如何用Python同时记录鼠标和键盘的移动?

gnuplot - gnuplot 和 AquaTerm 有什么区别?

C&X11 : how to use graphic contexts

linux - 从 CloudFormation::Init 命令重新启动

linux - Linux 中的 TomEE plus 1.7.1 在 myfaces-impl-2.1.15.jar 上的服务器启动期间挂起

ios - 检查 UITextField 可见但在键盘后面

ios - 使用多个 UITextFields 关闭键盘?

r - 在 MAC 中使用 Microsoft R Open 3.3.1 时的警告消息