src/video/x11/SDL_x11keyboard.c
author Alex Baines <alex@abaines.me.uk>
Fri, 28 Oct 2016 01:28:58 +0100
changeset 10562 b48d8a98e261
parent 10548 aea47b61c640
child 10569 9429d331668e
permissions -rw-r--r--
Fix double events / no repeat flag on key events when built withoutibus/fcitx

Uses XkbSetDetectableKeyRepeat, and falls back to forcing @im=none if it's not
supported.
slouken@1950
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@9998
     3
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
slouken@1950
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1950
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1950
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1950
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@1950
    22
slouken@5481
    23
#if SDL_VIDEO_DRIVER_X11
slouken@5481
    24
slouken@1950
    25
#include "SDL_x11video.h"
slouken@1950
    26
slouken@1950
    27
#include "../../events/SDL_keyboard_c.h"
slouken@2305
    28
#include "../../events/scancodes_darwin.h"
slouken@2305
    29
#include "../../events/scancodes_xfree86.h"
slouken@1950
    30
bob@2295
    31
#include <X11/keysym.h>
jwyatt@9842
    32
#include <X11/XKBlib.h>
bob@2295
    33
bob@2295
    34
#include "imKStoUCS.h"
bob@2295
    35
alex@10562
    36
#ifdef X_HAVE_UTF8_STRING
alex@10562
    37
#include <locale.h>
alex@10562
    38
#endif
alex@10562
    39
slouken@3001
    40
/* *INDENT-OFF* */
slouken@3162
    41
static const struct {
slouken@3001
    42
    KeySym keysym;
slouken@7580
    43
    SDL_Scancode scancode;
slouken@7580
    44
} KeySymToSDLScancode[] = {
slouken@7580
    45
    { XK_Return, SDL_SCANCODE_RETURN },
slouken@7580
    46
    { XK_Escape, SDL_SCANCODE_ESCAPE },
slouken@7580
    47
    { XK_BackSpace, SDL_SCANCODE_BACKSPACE },
slouken@7580
    48
    { XK_Tab, SDL_SCANCODE_TAB },
slouken@7580
    49
    { XK_Caps_Lock, SDL_SCANCODE_CAPSLOCK },
slouken@7580
    50
    { XK_F1, SDL_SCANCODE_F1 },
slouken@7580
    51
    { XK_F2, SDL_SCANCODE_F2 },
slouken@7580
    52
    { XK_F3, SDL_SCANCODE_F3 },
slouken@7580
    53
    { XK_F4, SDL_SCANCODE_F4 },
slouken@7580
    54
    { XK_F5, SDL_SCANCODE_F5 },
slouken@7580
    55
    { XK_F6, SDL_SCANCODE_F6 },
slouken@7580
    56
    { XK_F7, SDL_SCANCODE_F7 },
slouken@7580
    57
    { XK_F8, SDL_SCANCODE_F8 },
slouken@7580
    58
    { XK_F9, SDL_SCANCODE_F9 },
slouken@7580
    59
    { XK_F10, SDL_SCANCODE_F10 },
slouken@7580
    60
    { XK_F11, SDL_SCANCODE_F11 },
slouken@7580
    61
    { XK_F12, SDL_SCANCODE_F12 },
slouken@7580
    62
    { XK_Print, SDL_SCANCODE_PRINTSCREEN },
slouken@7580
    63
    { XK_Scroll_Lock, SDL_SCANCODE_SCROLLLOCK },
slouken@7580
    64
    { XK_Pause, SDL_SCANCODE_PAUSE },
slouken@7580
    65
    { XK_Insert, SDL_SCANCODE_INSERT },
slouken@7580
    66
    { XK_Home, SDL_SCANCODE_HOME },
slouken@7580
    67
    { XK_Prior, SDL_SCANCODE_PAGEUP },
slouken@7580
    68
    { XK_Delete, SDL_SCANCODE_DELETE },
slouken@7580
    69
    { XK_End, SDL_SCANCODE_END },
slouken@7580
    70
    { XK_Next, SDL_SCANCODE_PAGEDOWN },
slouken@7580
    71
    { XK_Right, SDL_SCANCODE_RIGHT },
slouken@7580
    72
    { XK_Left, SDL_SCANCODE_LEFT },
slouken@7580
    73
    { XK_Down, SDL_SCANCODE_DOWN },
slouken@7580
    74
    { XK_Up, SDL_SCANCODE_UP },
slouken@7580
    75
    { XK_Num_Lock, SDL_SCANCODE_NUMLOCKCLEAR },
slouken@7580
    76
    { XK_KP_Divide, SDL_SCANCODE_KP_DIVIDE },
slouken@7580
    77
    { XK_KP_Multiply, SDL_SCANCODE_KP_MULTIPLY },
slouken@7580
    78
    { XK_KP_Subtract, SDL_SCANCODE_KP_MINUS },
slouken@7580
    79
    { XK_KP_Add, SDL_SCANCODE_KP_PLUS },
slouken@7580
    80
    { XK_KP_Enter, SDL_SCANCODE_KP_ENTER },
slouken@7580
    81
    { XK_KP_Delete, SDL_SCANCODE_KP_PERIOD },
slouken@7580
    82
    { XK_KP_End, SDL_SCANCODE_KP_1 },
slouken@7580
    83
    { XK_KP_Down, SDL_SCANCODE_KP_2 },
slouken@7580
    84
    { XK_KP_Next, SDL_SCANCODE_KP_3 },
slouken@7580
    85
    { XK_KP_Left, SDL_SCANCODE_KP_4 },
slouken@7580
    86
    { XK_KP_Begin, SDL_SCANCODE_KP_5 },
slouken@7580
    87
    { XK_KP_Right, SDL_SCANCODE_KP_6 },
slouken@7580
    88
    { XK_KP_Home, SDL_SCANCODE_KP_7 },
slouken@7580
    89
    { XK_KP_Up, SDL_SCANCODE_KP_8 },
slouken@7580
    90
    { XK_KP_Prior, SDL_SCANCODE_KP_9 },
slouken@7580
    91
    { XK_KP_Insert, SDL_SCANCODE_KP_0 },
slouken@7580
    92
    { XK_KP_Decimal, SDL_SCANCODE_KP_PERIOD },
slouken@7580
    93
    { XK_KP_1, SDL_SCANCODE_KP_1 },
slouken@7580
    94
    { XK_KP_2, SDL_SCANCODE_KP_2 },
slouken@7580
    95
    { XK_KP_3, SDL_SCANCODE_KP_3 },
slouken@7580
    96
    { XK_KP_4, SDL_SCANCODE_KP_4 },
slouken@7580
    97
    { XK_KP_5, SDL_SCANCODE_KP_5 },
slouken@7580
    98
    { XK_KP_6, SDL_SCANCODE_KP_6 },
slouken@7580
    99
    { XK_KP_7, SDL_SCANCODE_KP_7 },
slouken@7580
   100
    { XK_KP_8, SDL_SCANCODE_KP_8 },
slouken@7580
   101
    { XK_KP_9, SDL_SCANCODE_KP_9 },
slouken@7580
   102
    { XK_KP_0, SDL_SCANCODE_KP_0 },
slouken@7580
   103
    { XK_KP_Decimal, SDL_SCANCODE_KP_PERIOD },
slouken@7580
   104
    { XK_Hyper_R, SDL_SCANCODE_APPLICATION },
slouken@7580
   105
    { XK_KP_Equal, SDL_SCANCODE_KP_EQUALS },
slouken@7580
   106
    { XK_F13, SDL_SCANCODE_F13 },
slouken@7580
   107
    { XK_F14, SDL_SCANCODE_F14 },
slouken@7580
   108
    { XK_F15, SDL_SCANCODE_F15 },
slouken@7580
   109
    { XK_F16, SDL_SCANCODE_F16 },
slouken@7580
   110
    { XK_F17, SDL_SCANCODE_F17 },
slouken@7580
   111
    { XK_F18, SDL_SCANCODE_F18 },
slouken@7580
   112
    { XK_F19, SDL_SCANCODE_F19 },
slouken@7580
   113
    { XK_F20, SDL_SCANCODE_F20 },
slouken@7580
   114
    { XK_F21, SDL_SCANCODE_F21 },
slouken@7580
   115
    { XK_F22, SDL_SCANCODE_F22 },
slouken@7580
   116
    { XK_F23, SDL_SCANCODE_F23 },
slouken@7580
   117
    { XK_F24, SDL_SCANCODE_F24 },
slouken@7580
   118
    { XK_Execute, SDL_SCANCODE_EXECUTE },
slouken@7580
   119
    { XK_Help, SDL_SCANCODE_HELP },
slouken@7580
   120
    { XK_Menu, SDL_SCANCODE_MENU },
slouken@7580
   121
    { XK_Select, SDL_SCANCODE_SELECT },
slouken@7580
   122
    { XK_Cancel, SDL_SCANCODE_STOP },
slouken@7580
   123
    { XK_Redo, SDL_SCANCODE_AGAIN },
slouken@7580
   124
    { XK_Undo, SDL_SCANCODE_UNDO },
slouken@7580
   125
    { XK_Find, SDL_SCANCODE_FIND },
slouken@7580
   126
    { XK_KP_Separator, SDL_SCANCODE_KP_COMMA },
slouken@7580
   127
    { XK_Sys_Req, SDL_SCANCODE_SYSREQ },
slouken@7580
   128
    { XK_Control_L, SDL_SCANCODE_LCTRL },
slouken@7580
   129
    { XK_Shift_L, SDL_SCANCODE_LSHIFT },
slouken@7580
   130
    { XK_Alt_L, SDL_SCANCODE_LALT },
slouken@7580
   131
    { XK_Meta_L, SDL_SCANCODE_LGUI },
slouken@7580
   132
    { XK_Super_L, SDL_SCANCODE_LGUI },
slouken@7580
   133
    { XK_Control_R, SDL_SCANCODE_RCTRL },
slouken@7580
   134
    { XK_Shift_R, SDL_SCANCODE_RSHIFT },
slouken@7580
   135
    { XK_Alt_R, SDL_SCANCODE_RALT },
slime73@10059
   136
    { XK_ISO_Level3_Shift, SDL_SCANCODE_RALT },
slouken@7580
   137
    { XK_Meta_R, SDL_SCANCODE_RGUI },
slouken@7580
   138
    { XK_Super_R, SDL_SCANCODE_RGUI },
slouken@7580
   139
    { XK_Mode_switch, SDL_SCANCODE_MODE },
william@10493
   140
    { XK_period, SDL_SCANCODE_PERIOD },
william@10493
   141
    { XK_comma, SDL_SCANCODE_COMMA },
william@10493
   142
    { XK_slash, SDL_SCANCODE_SLASH },
william@10493
   143
    { XK_backslash, SDL_SCANCODE_BACKSLASH },
william@10493
   144
    { XK_minus, SDL_SCANCODE_MINUS },
william@10493
   145
    { XK_equal, SDL_SCANCODE_EQUALS },
william@10493
   146
    { XK_space, SDL_SCANCODE_SPACE },
william@10493
   147
    { XK_grave, SDL_SCANCODE_GRAVE },
william@10493
   148
    { XK_apostrophe, SDL_SCANCODE_APOSTROPHE },
william@10493
   149
    { XK_bracketleft, SDL_SCANCODE_LEFTBRACKET },
william@10493
   150
    { XK_bracketright, SDL_SCANCODE_RIGHTBRACKET },
bob@2295
   151
};
bob@2295
   152
slouken@3162
   153
static const struct
bob@2295
   154
{
slouken@7882
   155
    SDL_Scancode const *table;
slouken@2305
   156
    int table_size;
slouken@2305
   157
} scancode_set[] = {
slouken@2308
   158
    { darwin_scancode_table, SDL_arraysize(darwin_scancode_table) },
slouken@2308
   159
    { xfree86_scancode_table, SDL_arraysize(xfree86_scancode_table) },
slouken@2825
   160
    { xfree86_scancode_table2, SDL_arraysize(xfree86_scancode_table2) },
alex@10494
   161
    { xvnc_scancode_table, SDL_arraysize(xvnc_scancode_table) },
slouken@2308
   162
};
slouken@2308
   163
/* *INDENT-OFF* */
bob@2295
   164
slouken@7580
   165
/* This function only works for keyboards in US QWERTY layout */
slouken@7580
   166
static SDL_Scancode
alex@10494
   167
X11_KeyCodeToSDLScancode(_THIS, KeyCode keycode)
slouken@3001
   168
{
slouken@3001
   169
    KeySym keysym;
slouken@3001
   170
    int i;
slouken@3001
   171
alex@10494
   172
    keysym = X11_KeyCodeToSym(_this, keycode, 0);
slouken@3001
   173
    if (keysym == NoSymbol) {
slouken@7580
   174
        return SDL_SCANCODE_UNKNOWN;
slouken@3001
   175
    }
slouken@3001
   176
william@10493
   177
    if (keysym >= XK_a && keysym <= XK_z) {
william@10493
   178
        return SDL_SCANCODE_A + (keysym - XK_a);
william@10493
   179
    }
slouken@7580
   180
    if (keysym >= XK_A && keysym <= XK_Z) {
slouken@7580
   181
        return SDL_SCANCODE_A + (keysym - XK_A);
slouken@3001
   182
    }
slouken@3001
   183
william@10493
   184
    if (keysym == XK_0) {
william@10493
   185
        return SDL_SCANCODE_0;
william@10493
   186
    }
william@10493
   187
    if (keysym >= XK_1 && keysym <= XK_9) {
william@10493
   188
        return SDL_SCANCODE_1 + (keysym - XK_1);
slouken@7580
   189
    }
slouken@7580
   190
slouken@7580
   191
    for (i = 0; i < SDL_arraysize(KeySymToSDLScancode); ++i) {
slouken@7580
   192
        if (keysym == KeySymToSDLScancode[i].keysym) {
slouken@7580
   193
            return KeySymToSDLScancode[i].scancode;
slouken@3001
   194
        }
slouken@3001
   195
    }
slouken@7580
   196
    return SDL_SCANCODE_UNKNOWN;
slouken@7580
   197
}
slouken@7580
   198
slouken@7580
   199
static Uint32
alex@10494
   200
X11_KeyCodeToUcs4(_THIS, KeyCode keycode, unsigned char group)
slouken@7580
   201
{
alex@10494
   202
    KeySym keysym = X11_KeyCodeToSym(_this, keycode, group);
alex@10494
   203
alex@10494
   204
    if (keysym == NoSymbol) {
alex@10494
   205
        return 0;
alex@10494
   206
    }
alex@10494
   207
alex@10494
   208
    return X11_KeySymToUcs4(keysym);
alex@10494
   209
}
alex@10494
   210
alex@10494
   211
KeySym
alex@10494
   212
X11_KeyCodeToSym(_THIS, KeyCode keycode, unsigned char group)
alex@10494
   213
{
alex@10494
   214
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
slouken@7580
   215
    KeySym keysym;
slouken@7580
   216
slouken@7580
   217
#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
slouken@10439
   218
    if (data->xkb) {
slouken@10439
   219
        int num_groups     = XkbKeyNumGroups(data->xkb, keycode);
slouken@10439
   220
        unsigned char info = XkbKeyGroupInfo(data->xkb, keycode);
slouken@10439
   221
        
slouken@10439
   222
        if (num_groups && group >= num_groups) {
slouken@10439
   223
        
slouken@10439
   224
            int action = XkbOutOfRangeGroupAction(info);
slouken@10439
   225
            
slouken@10439
   226
            if (action == XkbRedirectIntoRange) {
slouken@10439
   227
                if ((group = XkbOutOfRangeGroupNumber(info)) >= num_groups) {
slouken@10439
   228
                    group = 0;
slouken@10439
   229
                }
slouken@10439
   230
            } else if (action == XkbClampIntoRange) {
slouken@10439
   231
                group = num_groups - 1;
slouken@10439
   232
            } else {
slouken@10439
   233
                group %= num_groups;
slouken@10439
   234
            }
slouken@10439
   235
        }
alex@10494
   236
        keysym = X11_XkbKeycodeToKeysym(data->display, keycode, group, 0);
slouken@10439
   237
    } else {
alex@10494
   238
        keysym = X11_XKeycodeToKeysym(data->display, keycode, 0);
slouken@10439
   239
    }
slouken@7580
   240
#else
slouken@10439
   241
    keysym = X11_XKeycodeToKeysym(data->display, keycode, 0);
slouken@7580
   242
#endif
slouken@7580
   243
alex@10494
   244
    return keysym;
slouken@3001
   245
}
slouken@3001
   246
bob@2295
   247
int
slouken@1950
   248
X11_InitKeyboard(_THIS)
slouken@1950
   249
{
slouken@1950
   250
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
icculus@7672
   251
    int i = 0;
icculus@7672
   252
    int j = 0;
slouken@2305
   253
    int min_keycode, max_keycode;
slouken@3001
   254
    struct {
slouken@5218
   255
        SDL_Scancode scancode;
slouken@3001
   256
        KeySym keysym;
slouken@3001
   257
        int value;
slouken@3001
   258
    } fingerprint[] = {
slouken@3001
   259
        { SDL_SCANCODE_HOME, XK_Home, 0 },
slouken@3001
   260
        { SDL_SCANCODE_PAGEUP, XK_Prior, 0 },
slouken@8667
   261
        { SDL_SCANCODE_UP, XK_Up, 0 },
slouken@8667
   262
        { SDL_SCANCODE_LEFT, XK_Left, 0 },
slouken@8667
   263
        { SDL_SCANCODE_DELETE, XK_Delete, 0 },
slouken@8667
   264
        { SDL_SCANCODE_KP_ENTER, XK_KP_Enter, 0 },
slouken@2305
   265
    };
slouken@8667
   266
    int best_distance;
slouken@8667
   267
    int best_index;
slouken@8667
   268
    int distance;
alex@10562
   269
    BOOL xkb_repeat = 0;
alex@10562
   270
    
icculus@7827
   271
    X11_XAutoRepeatOn(data->display);
bob@2299
   272
alex@10494
   273
#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
alex@10494
   274
    {
alex@10562
   275
        int xkb_major = XkbMajorVersion;
alex@10562
   276
        int xkb_minor = XkbMinorVersion;
alex@10562
   277
alex@10562
   278
        if (X11_XkbQueryExtension(data->display, NULL, NULL, NULL, &xkb_major, &xkb_minor)) {
alex@10562
   279
            data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd);
alex@10562
   280
        }
alex@10562
   281
alex@10562
   282
        /* This will remove KeyRelease events for held keys */
alex@10562
   283
        X11_XkbSetDetectableAutoRepeat(data->display, True, &xkb_repeat);
alex@10562
   284
    }
alex@10494
   285
#endif
alex@10562
   286
    
alex@10562
   287
    /* Open a connection to the X input manager */
alex@10562
   288
#ifdef X_HAVE_UTF8_STRING
alex@10562
   289
    if (SDL_X11_HAVE_UTF8) {
alex@10562
   290
        /* Set the locale, and call XSetLocaleModifiers before XOpenIM so that 
alex@10562
   291
           Compose keys will work correctly. */
alex@10562
   292
        char *prev_locale = setlocale(LC_ALL, NULL);
alex@10562
   293
        char *prev_xmods  = X11_XSetLocaleModifiers(NULL);
alex@10562
   294
        const char *new_xmods = "";
alex@10562
   295
#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
alex@10562
   296
        const char *env_xmods = SDL_getenv("XMODIFIERS");
alex@10562
   297
#endif
alex@10562
   298
        SDL_bool has_dbus_ime_support = SDL_FALSE;
alex@10494
   299
alex@10562
   300
        if (prev_locale) {
alex@10562
   301
            prev_locale = SDL_strdup(prev_locale);
alex@10562
   302
        }
alex@10562
   303
alex@10562
   304
        if (prev_xmods) {
alex@10562
   305
            prev_xmods = SDL_strdup(prev_xmods);
alex@10562
   306
        }
alex@10562
   307
alex@10562
   308
        /* IBus resends some key events that were filtered by XFilterEvents
alex@10562
   309
           when it is used via XIM which causes issues. Prevent this by forcing
alex@10562
   310
           @im=none if XMODIFIERS contains @im=ibus. IBus can still be used via 
alex@10562
   311
           the DBus implementation, which also has support for pre-editing. */
alex@10562
   312
#ifdef HAVE_IBUS_IBUS_H
alex@10562
   313
        if (env_xmods && SDL_strstr(env_xmods, "@im=ibus") != NULL) {
alex@10562
   314
            has_dbus_ime_support = SDL_TRUE;
alex@10562
   315
        }
alex@10562
   316
#endif
alex@10562
   317
#ifdef HAVE_FCITX_FRONTEND_H
alex@10562
   318
        if (env_xmods && SDL_strstr(env_xmods, "@im=fcitx") != NULL) {
alex@10562
   319
            has_dbus_ime_support = SDL_TRUE;
alex@10562
   320
        }
alex@10562
   321
#endif
alex@10562
   322
        if (has_dbus_ime_support || !xkb_repeat) {
alex@10562
   323
            new_xmods = "@im=none";
alex@10562
   324
        }
alex@10562
   325
alex@10562
   326
        setlocale(LC_ALL, "");
alex@10562
   327
        X11_XSetLocaleModifiers(new_xmods);
alex@10562
   328
alex@10562
   329
        data->im = X11_XOpenIM(data->display, NULL, data->classname, data->classname);
alex@10562
   330
alex@10562
   331
        /* Reset the locale + X locale modifiers back to how they were,
alex@10562
   332
           locale first because the X locale modifiers depend on it. */
alex@10562
   333
        setlocale(LC_ALL, prev_locale);
alex@10562
   334
        X11_XSetLocaleModifiers(prev_xmods);
alex@10562
   335
alex@10562
   336
        if (prev_locale) {
alex@10562
   337
            SDL_free(prev_locale);
alex@10562
   338
        }
alex@10562
   339
alex@10562
   340
        if (prev_xmods) {
alex@10562
   341
            SDL_free(prev_xmods);
alex@10562
   342
        }
alex@10562
   343
    }
alex@10562
   344
#endif
slouken@2305
   345
    /* Try to determine which scancodes are being used based on fingerprint */
slouken@8667
   346
    best_distance = SDL_arraysize(fingerprint) + 1;
slouken@8667
   347
    best_index = -1;
icculus@7827
   348
    X11_XDisplayKeycodes(data->display, &min_keycode, &max_keycode);
slouken@3001
   349
    for (i = 0; i < SDL_arraysize(fingerprint); ++i) {
slouken@3001
   350
        fingerprint[i].value =
icculus@7827
   351
            X11_XKeysymToKeycode(data->display, fingerprint[i].keysym) -
slouken@2305
   352
            min_keycode;
slouken@2305
   353
    }
slouken@2305
   354
    for (i = 0; i < SDL_arraysize(scancode_set); ++i) {
slouken@2305
   355
        /* Make sure the scancode set isn't too big */
slouken@2305
   356
        if ((max_keycode - min_keycode + 1) <= scancode_set[i].table_size) {
slouken@2305
   357
            continue;
slouken@2305
   358
        }
slouken@8667
   359
        distance = 0;
slouken@2305
   360
        for (j = 0; j < SDL_arraysize(fingerprint); ++j) {
slouken@3001
   361
            if (fingerprint[j].value < 0
slouken@3001
   362
                || fingerprint[j].value >= scancode_set[i].table_size) {
slouken@8667
   363
                distance += 1;
slouken@8667
   364
            } else if (scancode_set[i].table[fingerprint[j].value] != fingerprint[j].scancode) {
slouken@8667
   365
                distance += 1;
slouken@2305
   366
            }
slouken@2305
   367
        }
slouken@8667
   368
        if (distance < best_distance) {
slouken@8667
   369
            best_distance = distance;
slouken@8667
   370
            best_index = i;
slouken@2305
   371
        }
slouken@2305
   372
    }
slouken@8667
   373
    if (best_index >= 0 && best_distance <= 2) {
slouken@8667
   374
#ifdef DEBUG_KEYBOARD
slouken@8667
   375
        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);
slouken@8667
   376
#endif
slouken@8667
   377
        SDL_memcpy(&data->key_layout[min_keycode], scancode_set[best_index].table,
slouken@8667
   378
                   sizeof(SDL_Scancode) * scancode_set[best_index].table_size);
slouken@9678
   379
    } else {
slouken@5220
   380
        SDL_Keycode keymap[SDL_NUM_SCANCODES];
slouken@3001
   381
slouken@2305
   382
        printf
slouken@2305
   383
            ("Keyboard layout unknown, please send the following to the SDL mailing list (sdl@libsdl.org):\n");
slouken@2305
   384
slouken@2305
   385
        /* Determine key_layout - only works on US QWERTY layout */
slouken@3001
   386
        SDL_GetDefaultKeymap(keymap);
slouken@2305
   387
        for (i = min_keycode; i <= max_keycode; ++i) {
slouken@2305
   388
            KeySym sym;
alex@10494
   389
            sym = X11_KeyCodeToSym(_this, (KeyCode) i, 0);
slouken@3001
   390
            if (sym != NoSymbol) {
slouken@7580
   391
                SDL_Scancode scancode;
icculus@3667
   392
                printf("code = %d, sym = 0x%X (%s) ", i - min_keycode,
icculus@7827
   393
                       (unsigned int) sym, X11_XKeysymToString(sym));
alex@10494
   394
                scancode = X11_KeyCodeToSDLScancode(_this, i);
slouken@7580
   395
                data->key_layout[i] = scancode;
slouken@7580
   396
                if (scancode == SDL_SCANCODE_UNKNOWN) {
slouken@2305
   397
                    printf("scancode not found\n");
slouken@2305
   398
                } else {
slouken@7824
   399
                    printf("scancode = %d (%s)\n", scancode, SDL_GetScancodeName(scancode));
slouken@2305
   400
                }
slouken@2305
   401
            }
slouken@2305
   402
        }
slouken@2305
   403
    }
slouken@1950
   404
slouken@2306
   405
    X11_UpdateKeymap(_this);
bob@2295
   406
slouken@2305
   407
    SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
bob@2295
   408
slouken@10496
   409
#ifdef SDL_USE_IME
slouken@10496
   410
    SDL_IME_Init();
alex@8889
   411
#endif
alex@8889
   412
bob@2295
   413
    return 0;
bob@2295
   414
}
bob@2295
   415
slouken@2305
   416
void
slouken@2305
   417
X11_UpdateKeymap(_THIS)
bob@2295
   418
{
bob@2295
   419
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
slouken@2305
   420
    int i;
slouken@5218
   421
    SDL_Scancode scancode;
slouken@5220
   422
    SDL_Keycode keymap[SDL_NUM_SCANCODES];
jwyatt@9842
   423
    unsigned char group = 0;
bob@2295
   424
slouken@7580
   425
    SDL_GetDefaultKeymap(keymap);
alex@10494
   426
jwyatt@9842
   427
#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
alex@10494
   428
    if (data->xkb) {
slouken@10444
   429
        XkbStateRec state;
alex@10494
   430
        X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask, data->xkb);
slouken@10439
   431
icculus@9844
   432
        if (X11_XkbGetState(data->display, XkbUseCoreKbd, &state) == Success) {
icculus@9844
   433
            group = state.group;
icculus@9844
   434
        }
icculus@9843
   435
    }
jwyatt@9842
   436
#endif
jwyatt@9842
   437
jwyatt@9842
   438
slouken@2305
   439
    for (i = 0; i < SDL_arraysize(data->key_layout); i++) {
slouken@7580
   440
        Uint32 key;
slouken@2305
   441
slouken@3001
   442
        /* Make sure this is a valid scancode */
slouken@2305
   443
        scancode = data->key_layout[i];
slouken@3001
   444
        if (scancode == SDL_SCANCODE_UNKNOWN) {
slouken@2305
   445
            continue;
slouken@2305
   446
        }
slouken@2305
   447
slouken@7580
   448
        /* See if there is a UCS keycode for this scancode */
alex@10494
   449
        key = X11_KeyCodeToUcs4(_this, (KeyCode)i, group);
slouken@7580
   450
        if (key) {
slouken@7580
   451
            keymap[scancode] = key;
slouken@9678
   452
        } else {
alex@10494
   453
            SDL_Scancode keyScancode = X11_KeyCodeToSDLScancode(_this, (KeyCode)i);
slouken@9682
   454
slouken@9682
   455
            switch (keyScancode) {
slouken@9682
   456
                case SDL_SCANCODE_RETURN:
slouken@9682
   457
                    keymap[scancode] = SDLK_RETURN;
slouken@9682
   458
                    break;
slouken@9682
   459
                case SDL_SCANCODE_ESCAPE:
slouken@9682
   460
                    keymap[scancode] = SDLK_ESCAPE;
slouken@9682
   461
                    break;
slouken@9682
   462
                case SDL_SCANCODE_BACKSPACE:
slouken@9682
   463
                    keymap[scancode] = SDLK_BACKSPACE;
slouken@9682
   464
                    break;
slouken@9682
   465
                case SDL_SCANCODE_TAB:
slouken@9682
   466
                    keymap[scancode] = SDLK_TAB;
slouken@9682
   467
                    break;
slouken@9682
   468
                case SDL_SCANCODE_DELETE:
slouken@9682
   469
                    keymap[scancode] = SDLK_DELETE;
slouken@9682
   470
                    break;
slouken@9682
   471
                default:
slouken@9682
   472
                    keymap[scancode] = SDL_SCANCODE_TO_KEYCODE(keyScancode);
slouken@9682
   473
                    break;
slouken@9682
   474
            }
slouken@7580
   475
        }
bob@2295
   476
    }
slouken@4465
   477
    SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
slouken@1950
   478
}
slouken@1950
   479
slouken@1950
   480
void
slouken@1950
   481
X11_QuitKeyboard(_THIS)
slouken@1950
   482
{
slouken@10439
   483
    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
slouken@10439
   484
slouken@10439
   485
#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
slouken@10439
   486
    if (data->xkb) {
slouken@10439
   487
        X11_XkbFreeClientMap(data->xkb, 0, True);
alex@10494
   488
        data->xkb = NULL;
slouken@10439
   489
    }
slouken@10439
   490
#endif
slouken@10439
   491
slouken@10496
   492
#ifdef SDL_USE_IME
slouken@10496
   493
    SDL_IME_Quit();
alex@8889
   494
#endif
alex@8889
   495
}
alex@8889
   496
slouken@10548
   497
static void
slouken@10548
   498
X11_ResetXIM(_THIS)
slouken@10548
   499
{
slouken@10548
   500
#ifdef X_HAVE_UTF8_STRING
slouken@10548
   501
    SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
slouken@10548
   502
    int i;
slouken@10548
   503
slouken@10548
   504
    if (videodata && videodata->windowlist) {
slouken@10548
   505
        for (i = 0; i < videodata->numwindows; ++i) {
slouken@10548
   506
            SDL_WindowData *data = videodata->windowlist[i];
slouken@10548
   507
            if (data && data->ic) {
slouken@10548
   508
                /* Clear any partially entered dead keys */
slouken@10548
   509
                char *contents = X11_Xutf8ResetIC(data->ic);
slouken@10548
   510
                if (contents) {
slouken@10548
   511
                    X11_XFree(contents);
slouken@10548
   512
                }
slouken@10548
   513
            }
slouken@10548
   514
        }
slouken@10548
   515
    }
slouken@10548
   516
#endif
slouken@10548
   517
}
slouken@10548
   518
alex@8889
   519
void
alex@8889
   520
X11_StartTextInput(_THIS)
alex@8889
   521
{
slouken@10548
   522
    X11_ResetXIM(_this);
alex@8889
   523
}
alex@8889
   524
alex@8889
   525
void
alex@8889
   526
X11_StopTextInput(_THIS)
alex@8889
   527
{
slouken@10548
   528
    X11_ResetXIM(_this);
slouken@10496
   529
#ifdef SDL_USE_IME
slouken@10496
   530
    SDL_IME_Reset();
alex@8889
   531
#endif
alex@8889
   532
}
alex@8889
   533
alex@8889
   534
void
alex@8889
   535
X11_SetTextInputRect(_THIS, SDL_Rect *rect)
alex@8889
   536
{
alex@8889
   537
    if (!rect) {
alex@8889
   538
        SDL_InvalidParamError("rect");
alex@8889
   539
        return;
alex@8889
   540
    }
alex@8889
   541
       
slouken@10496
   542
#ifdef SDL_USE_IME
slouken@10496
   543
    SDL_IME_UpdateTextRect(rect);
alex@8889
   544
#endif
slouken@1950
   545
}
slouken@1950
   546
slouken@5481
   547
#endif /* SDL_VIDEO_DRIVER_X11 */
slouken@5481
   548
slouken@1950
   549
/* vi: set ts=4 sw=4 expandtab: */