cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_x11keyboard.c (11144B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 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
     33#include "imKStoUCS.h"
     34
     35/* *INDENT-OFF* */
     36static const struct {
     37    KeySym keysym;
     38    SDL_Scancode scancode;
     39} KeySymToSDLScancode[] = {
     40    { XK_Return, SDL_SCANCODE_RETURN },
     41    { XK_Escape, SDL_SCANCODE_ESCAPE },
     42    { XK_BackSpace, SDL_SCANCODE_BACKSPACE },
     43    { XK_Tab, SDL_SCANCODE_TAB },
     44    { XK_Caps_Lock, SDL_SCANCODE_CAPSLOCK },
     45    { XK_F1, SDL_SCANCODE_F1 },
     46    { XK_F2, SDL_SCANCODE_F2 },
     47    { XK_F3, SDL_SCANCODE_F3 },
     48    { XK_F4, SDL_SCANCODE_F4 },
     49    { XK_F5, SDL_SCANCODE_F5 },
     50    { XK_F6, SDL_SCANCODE_F6 },
     51    { XK_F7, SDL_SCANCODE_F7 },
     52    { XK_F8, SDL_SCANCODE_F8 },
     53    { XK_F9, SDL_SCANCODE_F9 },
     54    { XK_F10, SDL_SCANCODE_F10 },
     55    { XK_F11, SDL_SCANCODE_F11 },
     56    { XK_F12, SDL_SCANCODE_F12 },
     57    { XK_Print, SDL_SCANCODE_PRINTSCREEN },
     58    { XK_Scroll_Lock, SDL_SCANCODE_SCROLLLOCK },
     59    { XK_Pause, SDL_SCANCODE_PAUSE },
     60    { XK_Insert, SDL_SCANCODE_INSERT },
     61    { XK_Home, SDL_SCANCODE_HOME },
     62    { XK_Prior, SDL_SCANCODE_PAGEUP },
     63    { XK_Delete, SDL_SCANCODE_DELETE },
     64    { XK_End, SDL_SCANCODE_END },
     65    { XK_Next, SDL_SCANCODE_PAGEDOWN },
     66    { XK_Right, SDL_SCANCODE_RIGHT },
     67    { XK_Left, SDL_SCANCODE_LEFT },
     68    { XK_Down, SDL_SCANCODE_DOWN },
     69    { XK_Up, SDL_SCANCODE_UP },
     70    { XK_Num_Lock, SDL_SCANCODE_NUMLOCKCLEAR },
     71    { XK_KP_Divide, SDL_SCANCODE_KP_DIVIDE },
     72    { XK_KP_Multiply, SDL_SCANCODE_KP_MULTIPLY },
     73    { XK_KP_Subtract, SDL_SCANCODE_KP_MINUS },
     74    { XK_KP_Add, SDL_SCANCODE_KP_PLUS },
     75    { XK_KP_Enter, SDL_SCANCODE_KP_ENTER },
     76    { XK_KP_Delete, SDL_SCANCODE_KP_PERIOD },
     77    { XK_KP_End, SDL_SCANCODE_KP_1 },
     78    { XK_KP_Down, SDL_SCANCODE_KP_2 },
     79    { XK_KP_Next, SDL_SCANCODE_KP_3 },
     80    { XK_KP_Left, SDL_SCANCODE_KP_4 },
     81    { XK_KP_Begin, SDL_SCANCODE_KP_5 },
     82    { XK_KP_Right, SDL_SCANCODE_KP_6 },
     83    { XK_KP_Home, SDL_SCANCODE_KP_7 },
     84    { XK_KP_Up, SDL_SCANCODE_KP_8 },
     85    { XK_KP_Prior, SDL_SCANCODE_KP_9 },
     86    { XK_KP_Insert, SDL_SCANCODE_KP_0 },
     87    { XK_KP_Decimal, SDL_SCANCODE_KP_PERIOD },
     88    { XK_KP_1, SDL_SCANCODE_KP_1 },
     89    { XK_KP_2, SDL_SCANCODE_KP_2 },
     90    { XK_KP_3, SDL_SCANCODE_KP_3 },
     91    { XK_KP_4, SDL_SCANCODE_KP_4 },
     92    { XK_KP_5, SDL_SCANCODE_KP_5 },
     93    { XK_KP_6, SDL_SCANCODE_KP_6 },
     94    { XK_KP_7, SDL_SCANCODE_KP_7 },
     95    { XK_KP_8, SDL_SCANCODE_KP_8 },
     96    { XK_KP_9, SDL_SCANCODE_KP_9 },
     97    { XK_KP_0, SDL_SCANCODE_KP_0 },
     98    { XK_KP_Decimal, SDL_SCANCODE_KP_PERIOD },
     99    { XK_Hyper_R, SDL_SCANCODE_APPLICATION },
    100    { XK_KP_Equal, SDL_SCANCODE_KP_EQUALS },
    101    { XK_F13, SDL_SCANCODE_F13 },
    102    { XK_F14, SDL_SCANCODE_F14 },
    103    { XK_F15, SDL_SCANCODE_F15 },
    104    { XK_F16, SDL_SCANCODE_F16 },
    105    { XK_F17, SDL_SCANCODE_F17 },
    106    { XK_F18, SDL_SCANCODE_F18 },
    107    { XK_F19, SDL_SCANCODE_F19 },
    108    { XK_F20, SDL_SCANCODE_F20 },
    109    { XK_F21, SDL_SCANCODE_F21 },
    110    { XK_F22, SDL_SCANCODE_F22 },
    111    { XK_F23, SDL_SCANCODE_F23 },
    112    { XK_F24, SDL_SCANCODE_F24 },
    113    { XK_Execute, SDL_SCANCODE_EXECUTE },
    114    { XK_Help, SDL_SCANCODE_HELP },
    115    { XK_Menu, SDL_SCANCODE_MENU },
    116    { XK_Select, SDL_SCANCODE_SELECT },
    117    { XK_Cancel, SDL_SCANCODE_STOP },
    118    { XK_Redo, SDL_SCANCODE_AGAIN },
    119    { XK_Undo, SDL_SCANCODE_UNDO },
    120    { XK_Find, SDL_SCANCODE_FIND },
    121    { XK_KP_Separator, SDL_SCANCODE_KP_COMMA },
    122    { XK_Sys_Req, SDL_SCANCODE_SYSREQ },
    123    { XK_Control_L, SDL_SCANCODE_LCTRL },
    124    { XK_Shift_L, SDL_SCANCODE_LSHIFT },
    125    { XK_Alt_L, SDL_SCANCODE_LALT },
    126    { XK_Meta_L, SDL_SCANCODE_LGUI },
    127    { XK_Super_L, SDL_SCANCODE_LGUI },
    128    { XK_Control_R, SDL_SCANCODE_RCTRL },
    129    { XK_Shift_R, SDL_SCANCODE_RSHIFT },
    130    { XK_Alt_R, SDL_SCANCODE_RALT },
    131    { XK_Meta_R, SDL_SCANCODE_RGUI },
    132    { XK_Super_R, SDL_SCANCODE_RGUI },
    133    { XK_Mode_switch, SDL_SCANCODE_MODE },
    134};
    135
    136static const struct
    137{
    138    SDL_Scancode const *table;
    139    int table_size;
    140} scancode_set[] = {
    141    { darwin_scancode_table, SDL_arraysize(darwin_scancode_table) },
    142    { xfree86_scancode_table, SDL_arraysize(xfree86_scancode_table) },
    143    { xfree86_scancode_table2, SDL_arraysize(xfree86_scancode_table2) },
    144};
    145/* *INDENT-OFF* */
    146
    147/* This function only works for keyboards in US QWERTY layout */
    148static SDL_Scancode
    149X11_KeyCodeToSDLScancode(Display *display, KeyCode keycode)
    150{
    151    KeySym keysym;
    152    int i;
    153
    154#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
    155    keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0);
    156#else
    157    keysym = XKeycodeToKeysym(display, keycode, 0);
    158#endif
    159    if (keysym == NoSymbol) {
    160        return SDL_SCANCODE_UNKNOWN;
    161    }
    162
    163    if (keysym >= XK_A && keysym <= XK_Z) {
    164        return SDL_SCANCODE_A + (keysym - XK_A);
    165    }
    166
    167    if (keysym >= XK_0 && keysym <= XK_9) {
    168        return SDL_SCANCODE_0 + (keysym - XK_0);
    169    }
    170
    171    for (i = 0; i < SDL_arraysize(KeySymToSDLScancode); ++i) {
    172        if (keysym == KeySymToSDLScancode[i].keysym) {
    173            return KeySymToSDLScancode[i].scancode;
    174        }
    175    }
    176    return SDL_SCANCODE_UNKNOWN;
    177}
    178
    179static Uint32
    180X11_KeyCodeToUcs4(Display *display, KeyCode keycode)
    181{
    182    KeySym keysym;
    183
    184#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
    185    keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0);
    186#else
    187    keysym = XKeycodeToKeysym(display, keycode, 0);
    188#endif
    189    if (keysym == NoSymbol) {
    190        return 0;
    191    }
    192
    193    return X11_KeySymToUcs4(keysym);
    194}
    195
    196int
    197X11_InitKeyboard(_THIS)
    198{
    199    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    200    int i = 0;
    201    int j = 0;
    202    int min_keycode, max_keycode;
    203    struct {
    204        SDL_Scancode scancode;
    205        KeySym keysym;
    206        int value;
    207    } fingerprint[] = {
    208        { SDL_SCANCODE_HOME, XK_Home, 0 },
    209        { SDL_SCANCODE_PAGEUP, XK_Prior, 0 },
    210        { SDL_SCANCODE_UP, XK_Up, 0 },
    211        { SDL_SCANCODE_LEFT, XK_Left, 0 },
    212        { SDL_SCANCODE_DELETE, XK_Delete, 0 },
    213        { SDL_SCANCODE_KP_ENTER, XK_KP_Enter, 0 },
    214    };
    215    int best_distance;
    216    int best_index;
    217    int distance;
    218
    219    X11_XAutoRepeatOn(data->display);
    220
    221    /* Try to determine which scancodes are being used based on fingerprint */
    222    best_distance = SDL_arraysize(fingerprint) + 1;
    223    best_index = -1;
    224    X11_XDisplayKeycodes(data->display, &min_keycode, &max_keycode);
    225    for (i = 0; i < SDL_arraysize(fingerprint); ++i) {
    226        fingerprint[i].value =
    227            X11_XKeysymToKeycode(data->display, fingerprint[i].keysym) -
    228            min_keycode;
    229    }
    230    for (i = 0; i < SDL_arraysize(scancode_set); ++i) {
    231        /* Make sure the scancode set isn't too big */
    232        if ((max_keycode - min_keycode + 1) <= scancode_set[i].table_size) {
    233            continue;
    234        }
    235        distance = 0;
    236        for (j = 0; j < SDL_arraysize(fingerprint); ++j) {
    237            if (fingerprint[j].value < 0
    238                || fingerprint[j].value >= scancode_set[i].table_size) {
    239                distance += 1;
    240            } else if (scancode_set[i].table[fingerprint[j].value] != fingerprint[j].scancode) {
    241                distance += 1;
    242            }
    243        }
    244        if (distance < best_distance) {
    245            best_distance = distance;
    246            best_index = i;
    247        }
    248    }
    249    if (best_index >= 0 && best_distance <= 2) {
    250#ifdef DEBUG_KEYBOARD
    251        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);
    252#endif
    253        SDL_memcpy(&data->key_layout[min_keycode], scancode_set[best_index].table,
    254                   sizeof(SDL_Scancode) * scancode_set[best_index].table_size);
    255    }
    256    else {
    257        SDL_Keycode keymap[SDL_NUM_SCANCODES];
    258
    259        printf
    260            ("Keyboard layout unknown, please send the following to the SDL mailing list (sdl@libsdl.org):\n");
    261
    262        /* Determine key_layout - only works on US QWERTY layout */
    263        SDL_GetDefaultKeymap(keymap);
    264        for (i = min_keycode; i <= max_keycode; ++i) {
    265            KeySym sym;
    266#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
    267            sym = X11_XkbKeycodeToKeysym(data->display, i, 0, 0);
    268#else
    269            sym = XKeycodeToKeysym(data->display, i, 0);
    270#endif
    271            if (sym != NoSymbol) {
    272                SDL_Scancode scancode;
    273                printf("code = %d, sym = 0x%X (%s) ", i - min_keycode,
    274                       (unsigned int) sym, X11_XKeysymToString(sym));
    275                scancode = X11_KeyCodeToSDLScancode(data->display, i);
    276                data->key_layout[i] = scancode;
    277                if (scancode == SDL_SCANCODE_UNKNOWN) {
    278                    printf("scancode not found\n");
    279                } else {
    280                    printf("scancode = %d (%s)\n", scancode, SDL_GetScancodeName(scancode));
    281                }
    282            }
    283        }
    284    }
    285
    286    X11_UpdateKeymap(_this);
    287
    288    SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
    289
    290#ifdef SDL_USE_IBUS
    291    SDL_IBus_Init();
    292#endif
    293
    294    return 0;
    295}
    296
    297void
    298X11_UpdateKeymap(_THIS)
    299{
    300    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    301    int i;
    302    SDL_Scancode scancode;
    303    SDL_Keycode keymap[SDL_NUM_SCANCODES];
    304
    305    SDL_GetDefaultKeymap(keymap);
    306    for (i = 0; i < SDL_arraysize(data->key_layout); i++) {
    307        Uint32 key;
    308
    309        /* Make sure this is a valid scancode */
    310        scancode = data->key_layout[i];
    311        if (scancode == SDL_SCANCODE_UNKNOWN) {
    312            continue;
    313        }
    314
    315        /* See if there is a UCS keycode for this scancode */
    316        key = X11_KeyCodeToUcs4(data->display, (KeyCode)i);
    317        if (key) {
    318            keymap[scancode] = key;
    319        }
    320    }
    321    SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
    322}
    323
    324void
    325X11_QuitKeyboard(_THIS)
    326{
    327#ifdef SDL_USE_IBUS
    328    SDL_IBus_Quit();
    329#endif
    330}
    331
    332void
    333X11_StartTextInput(_THIS)
    334{
    335
    336}
    337
    338void
    339X11_StopTextInput(_THIS)
    340{
    341#ifdef SDL_USE_IBUS
    342    SDL_IBus_Reset();
    343#endif
    344}
    345
    346void
    347X11_SetTextInputRect(_THIS, SDL_Rect *rect)
    348{
    349    if (!rect) {
    350        SDL_InvalidParamError("rect");
    351        return;
    352    }
    353       
    354#ifdef SDL_USE_IBUS
    355    SDL_IBus_UpdateTextRect(rect);
    356#endif
    357}
    358
    359#endif /* SDL_VIDEO_DRIVER_X11 */
    360
    361/* vi: set ts=4 sw=4 expandtab: */