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