Example #1
0
static bool _al_xwin_get_keyboard_mapping(void)
{
    int i;
    int count;
    int missing = 0;

    ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver();

    memset(used, 0, sizeof used);
    memset(keycode_to_scancode, 0, sizeof keycode_to_scancode);

    XDisplayKeycodes(system->x11display, &min_keycode, &max_keycode);
    count = 1 + max_keycode - min_keycode;

    if (keysyms) {
        XFree(keysyms);
    }
    keysyms = XGetKeyboardMapping(system->x11display, min_keycode,
                                  count, &sym_per_key);

    ALLEGRO_INFO("%i keys, %i symbols per key.\n", count, sym_per_key);

    if (sym_per_key <= 0) {
        return false;
    }

    missing = 0;

    for (i = min_keycode; i <= max_keycode; i++) {
        KeySym sym = keysyms[sym_per_key * (i - min_keycode)];
        KeySym sym2 =  keysyms[sym_per_key * (i - min_keycode) + 1];
        char *sym_str, *sym2_str;
        int allegro_key = 0;
        char str[1024];

        sym_str = XKeysymToString(sym);
        sym2_str = XKeysymToString(sym2);

        snprintf(str, sizeof str, "key [%i: %s %s]", i,
                 sym_str ? sym_str : "NULL", sym2_str ? sym2_str : "NULL");

        /* Hack for French keyboards, to correctly map ALLEGRO_KEY_0 to ALLEGRO_KEY_9. */
        if (sym2 >= XK_0 && sym2 <= XK_9) {
            allegro_key = find_allegro_key(sym2);
        }

        if (!allegro_key) {
            if (sym != NoSymbol) {
                allegro_key = find_allegro_key(sym);

                if (allegro_key == 0) {
                    missing++;
                    ALLEGRO_DEBUG("%s defering.\n", str);
                }
            }
            else {
                /* No KeySym for this key - ignore it. */
                keycode_to_scancode[i] = -1;
                ALLEGRO_DEBUG("%s not assigned.\n", str);
            }
        }

        if (allegro_key) {
            bool is_double = false;
            if (used[allegro_key]) {
                is_double = true;
            }
            keycode_to_scancode[i] = allegro_key;
            key_names[allegro_key] =
                XKeysymToString(keysyms[sym_per_key * (i - min_keycode)]);
            used[allegro_key] = 1;
            ALLEGRO_DEBUG("%s%s assigned to %i.\n", str,
                          is_double ? " *double*" : "", allegro_key);
        }
    }

    if (missing) {
        /* The keys still not assigned are just assigned arbitrarily now. */
        for (i = min_keycode; i <= max_keycode; i++) {
            if (keycode_to_scancode[i] == 0) {
                find_unknown_key_assignment(i);
            }
        }
    }

    if (xmodmap)
        XFreeModifiermap(xmodmap);
    xmodmap = XGetModifierMapping(system->x11display);
    for (i = 0; i < 8; i++) {
        int j;
        char str[1024];
        sprintf(str, "Modifier %d:", i + 1);
        for (j = 0; j < xmodmap->max_keypermod; j++) {
            KeyCode keycode = xmodmap->modifiermap[i * xmodmap->max_keypermod + j];
            // XKeycodeToKeysym is deprecated
            //KeySym sym = XKeycodeToKeysym(system->x11display, keycode, 0);
            KeySym sym = XkbKeycodeToKeysym(system->x11display, keycode, 0, 0);

            char *sym_str = XKeysymToString(sym);
            sprintf(str + strlen(str), " %s", sym_str ? sym_str : "NULL");
        }
        ALLEGRO_DEBUG("%s\n", str);
    }

    /* The [xkeymap] section can be useful, e.g. if trying to play a
     * game which has X and Y hardcoded as ALLEGRO_KEY_X and ALLEGRO_KEY_Y to mean
     * left/right movement, but on the X11 keyboard X and Y are far apart.
     * For normal use, a user never should have to touch [xkeymap] anymore
     * though, and proper written programs will not hardcode such mappings.
     */
    ALLEGRO_CONFIG *c = al_get_system_config();

    char const *key;
    ALLEGRO_CONFIG_ENTRY *it;
    key = al_get_first_config_entry(c, "xkeymap", &it);
    while (key) {
        char const *val;
        val = al_get_config_value(c, "xkeymap", key);
        int keycode = strtol(key, NULL, 10);
        int scancode = strtol(val, NULL, 10);
        if (keycode > 0 && scancode > 0) {
            keycode_to_scancode[keycode] = scancode;
            ALLEGRO_WARN("User override: KeySym %i assigned to %i.\n",
                         keycode, scancode);
        }
        key = al_get_next_config_entry(&it);
    }

    return true;
}
Example #2
0
/* x_get_keyboard_mapping:
 *  Generate a mapping from X11 keycodes to Allegro KEY_* codes. We have
 *  two goals: Every keypress should be mapped to a distinct Allegro KEY_*
 *  code. And we want the KEY_* codes to match the pressed
 *  key to some extent. To do the latter, the X11 KeySyms produced by a key
 *  are examined. If a match is found in the table above, the mapping is
 *  added to the mapping table. If no known KeySym is found for a key (or
 *  the same KeySym is found for more keys) - the remaining keys are
 *  distributed arbitrarily to the remaining KEY_* codes.
 *
 *  In a future version, this could be simplified by mapping *all* the X11
 *  KeySyms to KEY_* codes.
 */
void _xwin_get_keyboard_mapping(void)
{
   int i;
   int count;
   int missing = 0;

   memset(used, 0, sizeof used);
   memset(_xwin.keycode_to_scancode, 0, sizeof _xwin.keycode_to_scancode);

   XLOCK();

   XDisplayKeycodes(_xwin.display, &min_keycode, &max_keycode);
   count = 1 + max_keycode - min_keycode;

   if (keysyms) {
      XFree(keysyms);
   }
   keysyms = XGetKeyboardMapping(_xwin.display, min_keycode,
      count, &sym_per_key);

   TRACE (PREFIX_I "%i keys, %i symbols per key.\n", count, sym_per_key);

   missing = 0;

   for (i = min_keycode; i <= max_keycode; i++) {
      KeySym sym = keysyms[sym_per_key * (i - min_keycode)];
      KeySym sym2 =  keysyms[sym_per_key * (i - min_keycode) + 1];
      char *sym_str, *sym2_str;
      int allegro_key = 0;

      sym_str = XKeysymToString(sym);
      sym2_str = XKeysymToString(sym2);

      TRACE (PREFIX_I "key [%i: %s %s]", i, sym_str ? sym_str : "NULL", sym2_str ?
         sym2_str : "NULL");

      /* Hack for French keyboards, to correctly map KEY_0 to KEY_9. */
      if (sym2 >= XK_0 && sym2 <= XK_9) {
	 allegro_key = find_allegro_key(sym2);
      }

      if (!allegro_key) {
	 if (sym != NoSymbol) {
	    allegro_key = find_allegro_key(sym);

	    if (allegro_key == 0) {
	       missing++;
	       TRACE (" defering.\n");
	    }
	 }
	 else {
	    /* No KeySym for this key - ignore it. */
	    _xwin.keycode_to_scancode[i] = -1;
	    TRACE (" not assigned.\n");
	 }
      }

      if (allegro_key) {
	 if (used[allegro_key]) {
	    TRACE(" *double*");
	 }
	 _xwin.keycode_to_scancode[i] = allegro_key;
	 key_names[allegro_key] =
	    XKeysymToString(keysyms[sym_per_key * (i - min_keycode)]);
	 used[allegro_key] = 1;
	 TRACE(" assigned to %i.\n", allegro_key);
      }
   }

   if (missing) {
      /* The keys still not assigned are just assigned arbitrarily now. */
      for (i = min_keycode; i <= max_keycode; i++) {
	 if (_xwin.keycode_to_scancode[i] == 0) {
	    find_unknown_key_assignment(i);
	 }
      }
   }

   if (xmodmap)
      XFreeModifiermap(xmodmap);
   xmodmap = XGetModifierMapping(_xwin.display);
   for (i = 0; i < 8; i++) {
      int j;

      TRACE (PREFIX_I "Modifier %d:", i + 1);
      for (j = 0; j < xmodmap->max_keypermod; j++) {
	 KeySym sym = XKeycodeToKeysym(_xwin.display,
	    xmodmap->modifiermap[i * xmodmap->max_keypermod + j], 0);
         char *sym_str = XKeysymToString(sym);
         TRACE(" %s", sym_str ? sym_str : "NULL");
      }
      TRACE("\n");
   }

   /* The [xkeymap] section can be useful, e.g. if trying to play a
    * game which has X and Y hardcoded as KEY_X and KEY_Y to mean
    * left/right movement, but on the X11 keyboard X and Y are far apart.
    * For normal use, a user never should have to touch [xkeymap] anymore
    * though, and proper written programs will not hardcode such mappings.
    */
   {
      char *section, *option_format;
      char option[128], tmp1[128], tmp2[128];

      section = uconvert_ascii("xkeymap", tmp1);
      option_format = uconvert_ascii("keycode%d", tmp2);

      for (i = min_keycode; i <= max_keycode; i++) {
	 int scancode;

	 uszprintf(option, sizeof(option), option_format, i);
	 scancode = get_config_int(section, option, -1);
	 if (scancode > 0) {
	    _xwin.keycode_to_scancode[i] = scancode;
	    TRACE(PREFIX_I "User override: KeySym %i assigned to %i.\n", i, scancode);
	 }
      }
   }

   XUNLOCK();
}
Example #3
0
/* _al_xwin_keyboard_handler:
 *  Keyboard "interrupt" handler.
 */
void _al_xwin_keyboard_handler(XKeyEvent *event, ALLEGRO_DISPLAY *display)
{
    int keycode;

    if (!xkeyboard_installed)
        return;

    keycode = keycode_to_scancode[event->keycode];
    if (keycode == -1)
        keycode = find_unknown_key_assignment(event->keycode);

    update_shifts(event);

    /* Special case the pause key. */
    if (keycode == ALLEGRO_KEY_PAUSE) {
        /* Allegro ignore's releasing of the pause key. */
        if (event->type == KeyRelease)
            return;
        if (pause_key) {
            event->type = KeyRelease;
            pause_key = 0;
        }
        else {
            pause_key = 1;
        }
    }

    if (event->type == KeyPress) { /* Key pressed.  */
        int len;
        char buffer[16];
        int unicode = 0;
        int filtered = 0;

#if defined (ALLEGRO_XWINDOWS_WITH_XIM) && defined(X_HAVE_UTF8_STRING)
        if (xic) {
            len = Xutf8LookupString(xic, event, buffer, sizeof buffer, NULL, NULL);
        }
        else
#endif
        {
            /* XLookupString is supposed to only use ASCII. */
            len = XLookupString(event, buffer, sizeof buffer, NULL, NULL);
        }
        buffer[len] = '\0';
        ALLEGRO_USTR_INFO info;
        const ALLEGRO_USTR *ustr = al_ref_cstr(&info, buffer);
        unicode = al_ustr_get(ustr, 0);
        if (unicode < 0)
            unicode = 0;

#ifdef ALLEGRO_XWINDOWS_WITH_XIM
        ALLEGRO_DISPLAY_XGLX *glx = (void *)display;
        filtered = XFilterEvent((XEvent *)event, glx->window);
#endif
        if (keycode || unicode) {
            handle_key_press(keycode, unicode, filtered, _key_shifts, display);
        }
    }
    else { /* Key release. */
        /* HACK:
         * Detect key repeat by looking forward to see if this release is
         * followed by a press event, in which case we assume that this release
         * event was generated in response to that key press event. Events are
         * simultaneous if they are separated by less than 4 ms (a value that
         * worked well on one machine where this hack was needed).
         *
         * This is unnecessary on systems where XkbSetDetectableAutorepeat works.
         */
        if (XPending(event->display) > 0) {
            ALLEGRO_KEY_REPEAT_DATA d;
            XEvent dummy;
            d.event = event;
            d.found = false;
            XCheckIfEvent(event->display, &dummy, check_for_repeat, (XPointer)&d);
            if (d.found) {
                return;
            }
        }
        handle_key_release(keycode, display);
    }
}
Example #4
0
/* _xwin_keyboard_handler:
 *  Keyboard "interrupt" handler.
 */
void _xwin_keyboard_handler(XKeyEvent *event, int dga2_hack)
{
   int keycode;

   if (!xkeyboard_installed)
      return;

   if (_xwin_keyboard_callback)
      (*_xwin_keyboard_callback)(event->type == KeyPress ? 1 : 0, event->keycode);

   keycode = _xwin.keycode_to_scancode[event->keycode];
   if (keycode == -1)
      keycode = find_unknown_key_assignment(event->keycode);

   if (dga2_hack)
      dga2_update_shifts(event);
   else
      update_shifts(event);

   /* Special case the pause key. */
   if (keycode == KEY_PAUSE) {
      /* Allegro ignore's releasing of the pause key. */
      if (event->type == KeyRelease)
         return;
      if (pause_key) {
         event->type = KeyRelease;
         pause_key = 0;
      }
      else {
         pause_key = 1;
      }
   }

   if (event->type == KeyPress) { /* Key pressed.  */
      int len;
      char buffer[16];
      char buffer2[16];
      int unicode = 0, r = 0;

#if defined (ALLEGRO_XWINDOWS_WITH_XIM) && defined(X_HAVE_UTF8_STRING)
      if (xic) {
	 len = Xutf8LookupString(xic, event, buffer, sizeof buffer, NULL, NULL);
      }
      else
#endif
      {
         /* XLookupString is supposed to only use ASCII. */
	 len = XLookupString(event, buffer, sizeof buffer, NULL, NULL);
      }
      buffer[len] = '\0';
      uconvert(buffer, U_UTF8, buffer2, U_UNICODE, sizeof buffer2);
      unicode = *(unsigned short *)buffer2;

#ifdef ALLEGRO_XWINDOWS_WITH_XIM
      r = XFilterEvent((XEvent *)event, _xwin.window);
#endif
      if (keycode || unicode) {
	 /* If we have a keycode, we want it to go to Allegro immediately, so the
	  * key[] array is updated, and the user callbacks are called. OTOH, a key
	  * should not be added to the keyboard buffer (parameter -1) if it was
          * filtered out as a compose key, or if it is a modifier key.
	  */
	 if (r || keycode >= KEY_MODIFIERS)
	    unicode = -1;
	 else {
	    /* Historically, Allegro expects to get only the scancode when Alt is
	     * held down.
	     */
	    if (_key_shifts & KB_ALT_FLAG)
	       unicode = 0;
         }

	 _handle_key_press(unicode, keycode);

         /* Detect Ctrl-Alt-End. */
         if (keycode == KEY_END && (_key_shifts & KB_CTRL_FLAG) &&
            (_key_shifts & KB_ALT_FLAG) && (three_finger_flag))
         {
         #ifndef ALLEGRO_HAVE_LIBPTHREAD
            if (_unix_bg_man == &_bg_man_sigalrm) {
               _sigalrm_request_abort();
            }
            else
         #endif
            {
               TRACE(PREFIX_W "Three finger combo detected. SIGTERMing "
                     "pid %d\n", main_pid);
               kill(main_pid, SIGTERM);
            }
         }
      }
   }
   else { /* Key release. */
      _handle_key_release(keycode);
   }
}