int X11_VideoInit(_THIS) { SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; /* Get the window class name, usually the name of the application */ data->classname = get_classname(); /* Get the process PID to be associated to the window */ data->pid = getpid(); /* I have no idea how random this actually is, or has to be. */ data->window_group = (XID) (((size_t) data->pid) ^ ((size_t) _this)); /* 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) { 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 /* Look up some useful Atoms */ #define GET_ATOM(X) data->X = X11_XInternAtom(data->display, #X, False) GET_ATOM(WM_PROTOCOLS); GET_ATOM(WM_DELETE_WINDOW); GET_ATOM(WM_TAKE_FOCUS); GET_ATOM(_NET_WM_STATE); GET_ATOM(_NET_WM_STATE_HIDDEN); GET_ATOM(_NET_WM_STATE_FOCUSED); GET_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); GET_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); GET_ATOM(_NET_WM_STATE_FULLSCREEN); GET_ATOM(_NET_WM_STATE_ABOVE); GET_ATOM(_NET_WM_STATE_SKIP_TASKBAR); GET_ATOM(_NET_WM_STATE_SKIP_PAGER); GET_ATOM(_NET_WM_ALLOWED_ACTIONS); GET_ATOM(_NET_WM_ACTION_FULLSCREEN); GET_ATOM(_NET_WM_NAME); GET_ATOM(_NET_WM_ICON_NAME); GET_ATOM(_NET_WM_ICON); GET_ATOM(_NET_WM_PING); GET_ATOM(_NET_WM_WINDOW_OPACITY); GET_ATOM(_NET_WM_USER_TIME); GET_ATOM(_NET_ACTIVE_WINDOW); GET_ATOM(_NET_FRAME_EXTENTS); GET_ATOM(UTF8_STRING); GET_ATOM(PRIMARY); GET_ATOM(XdndEnter); GET_ATOM(XdndPosition); GET_ATOM(XdndStatus); GET_ATOM(XdndTypeList); GET_ATOM(XdndActionCopy); GET_ATOM(XdndDrop); GET_ATOM(XdndFinished); GET_ATOM(XdndSelection); GET_ATOM(XKLAVIER_STATE); /* Detect the window manager */ X11_CheckWindowManager(_this); if (X11_InitModes(_this) < 0) { return -1; } X11_InitXinput2(_this); if (X11_InitKeyboard(_this) != 0) { return -1; } X11_InitMouse(_this); X11_InitTouch(_this); #if SDL_USE_LIBDBUS SDL_DBus_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; 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; }