Beispiel #1
0
int
X11_InitKeyboard(_THIS)
{
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    int i = 0;
    int j = 0;
    int min_keycode, max_keycode;
    struct {
        SDL_Scancode scancode;
        KeySym keysym;
        int value;
    } fingerprint[] = {
        { SDL_SCANCODE_HOME, XK_Home, 0 },
        { SDL_SCANCODE_PAGEUP, XK_Prior, 0 },
        { SDL_SCANCODE_UP, XK_Up, 0 },
        { SDL_SCANCODE_LEFT, XK_Left, 0 },
        { SDL_SCANCODE_DELETE, XK_Delete, 0 },
        { SDL_SCANCODE_KP_ENTER, XK_KP_Enter, 0 },
    };
    int best_distance;
    int best_index;
    int distance;
    BOOL xkb_repeat = 0;
    
    X11_XAutoRepeatOn(data->display);

#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
    {
        int xkb_major = XkbMajorVersion;
        int xkb_minor = XkbMinorVersion;

        if (X11_XkbQueryExtension(data->display, NULL, NULL, NULL, &xkb_major, &xkb_minor)) {
            data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd);
        }

        /* This will remove KeyRelease events for held keys */
        X11_XkbSetDetectableAutoRepeat(data->display, True, &xkb_repeat);
    }
#endif
    
    /* Open a connection to the X input manager */
#ifdef X_HAVE_UTF8_STRING
    if (SDL_X11_HAVE_UTF8) {
        /* Set the locale, and call XSetLocaleModifiers before XOpenIM so that 
           Compose keys will work correctly. */
        char *prev_locale = setlocale(LC_ALL, NULL);
        char *prev_xmods  = X11_XSetLocaleModifiers(NULL);
        const char *new_xmods = "";
#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
        const char *env_xmods = SDL_getenv("XMODIFIERS");
#endif
        SDL_bool has_dbus_ime_support = SDL_FALSE;

        if (prev_locale) {
            prev_locale = SDL_strdup(prev_locale);
        }

        if (prev_xmods) {
            prev_xmods = SDL_strdup(prev_xmods);
        }

        /* IBus resends some key events that were filtered by XFilterEvents
           when it is used via XIM which causes issues. Prevent this by forcing
           @im=none if XMODIFIERS contains @im=ibus. IBus can still be used via 
           the DBus implementation, which also has support for pre-editing. */
#ifdef HAVE_IBUS_IBUS_H
        if (env_xmods && SDL_strstr(env_xmods, "@im=ibus") != NULL) {
            has_dbus_ime_support = SDL_TRUE;
        }
#endif
#ifdef HAVE_FCITX_FRONTEND_H
        if (env_xmods && SDL_strstr(env_xmods, "@im=fcitx") != NULL) {
            has_dbus_ime_support = SDL_TRUE;
        }
#endif
        if (has_dbus_ime_support || !xkb_repeat) {
            new_xmods = "@im=none";
        }

        setlocale(LC_ALL, "");
        X11_XSetLocaleModifiers(new_xmods);

        data->im = X11_XOpenIM(data->display, NULL, data->classname, data->classname);

        /* Reset the locale + X locale modifiers back to how they were,
           locale first because the X locale modifiers depend on it. */
        setlocale(LC_ALL, prev_locale);
        X11_XSetLocaleModifiers(prev_xmods);

        if (prev_locale) {
            SDL_free(prev_locale);
        }

        if (prev_xmods) {
            SDL_free(prev_xmods);
        }
    }
#endif
    /* Try to determine which scancodes are being used based on fingerprint */
    best_distance = SDL_arraysize(fingerprint) + 1;
    best_index = -1;
    X11_XDisplayKeycodes(data->display, &min_keycode, &max_keycode);
    for (i = 0; i < SDL_arraysize(fingerprint); ++i) {
        fingerprint[i].value =
            X11_XKeysymToKeycode(data->display, fingerprint[i].keysym) -
            min_keycode;
    }
    for (i = 0; i < SDL_arraysize(scancode_set); ++i) {
        /* Make sure the scancode set isn't too big */
        if ((max_keycode - min_keycode + 1) <= scancode_set[i].table_size) {
            continue;
        }
        distance = 0;
        for (j = 0; j < SDL_arraysize(fingerprint); ++j) {
            if (fingerprint[j].value < 0
                || fingerprint[j].value >= scancode_set[i].table_size) {
                distance += 1;
            } else if (scancode_set[i].table[fingerprint[j].value] != fingerprint[j].scancode) {
                distance += 1;
            }
        }
        if (distance < best_distance) {
            best_distance = distance;
            best_index = i;
        }
    }
    if (best_index >= 0 && best_distance <= 2) {
#ifdef DEBUG_KEYBOARD
        printf("Using scancode set %d, min_keycode = %d, max_keycode = %d, table_size = %d\n", best_index, min_keycode, max_keycode, scancode_set[best_index].table_size);
#endif
        SDL_memcpy(&data->key_layout[min_keycode], scancode_set[best_index].table,
                   sizeof(SDL_Scancode) * scancode_set[best_index].table_size);
    } else {
        SDL_Keycode keymap[SDL_NUM_SCANCODES];

        printf
            ("Keyboard layout unknown, please send the following to the SDL mailing list ([email protected]):\n");

        /* Determine key_layout - only works on US QWERTY layout */
        SDL_GetDefaultKeymap(keymap);
        for (i = min_keycode; i <= max_keycode; ++i) {
            KeySym sym;
            sym = X11_KeyCodeToSym(_this, (KeyCode) i, 0);
            if (sym != NoSymbol) {
                SDL_Scancode scancode;
                printf("code = %d, sym = 0x%X (%s) ", i - min_keycode,
                       (unsigned int) sym, X11_XKeysymToString(sym));
                scancode = X11_KeyCodeToSDLScancode(_this, i);
                data->key_layout[i] = scancode;
                if (scancode == SDL_SCANCODE_UNKNOWN) {
                    printf("scancode not found\n");
                } else {
                    printf("scancode = %d (%s)\n", scancode, SDL_GetScancodeName(scancode));
                }
            }
        }
    }

    X11_UpdateKeymap(_this);

    SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");

#ifdef SDL_USE_IME
    SDL_IME_Init();
#endif

    return 0;
}
int
X11_InitKeyboard(_THIS)
{
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    int i = 0;
    int j = 0;
    int min_keycode, max_keycode;
    struct {
        SDL_Scancode scancode;
        KeySym keysym;
        int value;
    } fingerprint[] = {
        { SDL_SCANCODE_HOME, XK_Home, 0 },
        { SDL_SCANCODE_PAGEUP, XK_Prior, 0 },
        { SDL_SCANCODE_UP, XK_Up, 0 },
        { SDL_SCANCODE_LEFT, XK_Left, 0 },
        { SDL_SCANCODE_DELETE, XK_Delete, 0 },
        { SDL_SCANCODE_KP_ENTER, XK_KP_Enter, 0 },
    };
    int best_distance;
    int best_index;
    int distance;

    X11_XAutoRepeatOn(data->display);

    /* Try to determine which scancodes are being used based on fingerprint */
    best_distance = SDL_arraysize(fingerprint) + 1;
    best_index = -1;
    X11_XDisplayKeycodes(data->display, &min_keycode, &max_keycode);
    for (i = 0; i < SDL_arraysize(fingerprint); ++i) {
        fingerprint[i].value =
            X11_XKeysymToKeycode(data->display, fingerprint[i].keysym) -
            min_keycode;
    }
    for (i = 0; i < SDL_arraysize(scancode_set); ++i) {
        /* Make sure the scancode set isn't too big */
        if ((max_keycode - min_keycode + 1) <= scancode_set[i].table_size) {
            continue;
        }
        distance = 0;
        for (j = 0; j < SDL_arraysize(fingerprint); ++j) {
            if (fingerprint[j].value < 0
                || fingerprint[j].value >= scancode_set[i].table_size) {
                distance += 1;
            } else if (scancode_set[i].table[fingerprint[j].value] != fingerprint[j].scancode) {
                distance += 1;
            }
        }
        if (distance < best_distance) {
            best_distance = distance;
            best_index = i;
        }
    }
    if (best_index >= 0 && best_distance <= 2) {
#ifdef DEBUG_KEYBOARD
        printf("Using scancode set %d, min_keycode = %d, max_keycode = %d, table_size = %d\n", best_index, min_keycode, max_keycode, scancode_set[best_index].table_size);
#endif
        SDL_memcpy(&data->key_layout[min_keycode], scancode_set[best_index].table,
                   sizeof(SDL_Scancode) * scancode_set[best_index].table_size);
    } else {
        SDL_Keycode keymap[SDL_NUM_SCANCODES];

        printf
            ("Keyboard layout unknown, please send the following to the SDL mailing list ([email protected]):\n");

        /* Determine key_layout - only works on US QWERTY layout */
        SDL_GetDefaultKeymap(keymap);
        for (i = min_keycode; i <= max_keycode; ++i) {
            KeySym sym;
#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
            sym = X11_XkbKeycodeToKeysym(data->display, i, 0, 0);
#else
            sym = X11_XKeycodeToKeysym(data->display, i, 0);
#endif
            if (sym != NoSymbol) {
                SDL_Scancode scancode;
                printf("code = %d, sym = 0x%X (%s) ", i - min_keycode,
                       (unsigned int) sym, X11_XKeysymToString(sym));
                scancode = X11_KeyCodeToSDLScancode(data->display, i);
                data->key_layout[i] = scancode;
                if (scancode == SDL_SCANCODE_UNKNOWN) {
                    printf("scancode not found\n");
                } else {
                    printf("scancode = %d (%s)\n", scancode, SDL_GetScancodeName(scancode));
                }
            }
        }
    }

    X11_UpdateKeymap(_this);

    SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");

#ifdef SDL_USE_IBUS
    SDL_IBus_Init();
#endif

    return 0;
}