Hi,

I'm currently looking into Caribou (an on-screen keyboard software)[1]
and found that its keysym replacement logic does not work reliably[2].

That code basically does the following:

(1) assign a keysym to some unused keycode (like keycode 246, which
    XF86WLAN is assigned here) with XkbSetMap
(2) send key press event using XTestFakeKeyEvent to get the keysym typed

Is this supposed to work?  After (1), I could type the new keysym with
physical keyboard, but couldn't with XTestFakeKeyEvent.  If I change the
mapping with XChangeKeyboardMapping instead of XkbSetMap, it seems to
work with both physical and virtual keyboard.

I'm attaching a test program which changes keysym mapping on 'a' key
(keycode 38) on US keyboard and then send key press.

The original code can be found at:

http://git.gnome.org/browse/caribou/tree/libcaribou/xadapter.vala#n148
http://git.gnome.org/browse/at-spi2-core/tree/registryd/deviceeventcontroller.c#n286

Footnotes: 
[1]  http://live.gnome.org/Caribou
[2]  https://bugzilla.gnome.org/show_bug.cgi?id=673547

Regards,
-- 
Daiki Ueno
/* This program does:
 *
 * (1) change keysym mapping 'a' -> 'b'
 * (2) wait a second to allow typing 'a' from physical keyboard
 * (3) emit key press/release event, with XTestFakeKeyEvent
 * (4) change keysym mapping 'b' -> 'a'
 */

#include <X11/extensions/XTest.h>
#include <X11/XKBlib.h>
#include <stdio.h>
#include <stdlib.h>

Display *display;
XkbDescRec *xkb;

static Bool
replace_keycode (unsigned int keycode, unsigned int *keysym)
{
  unsigned int offset;
  XkbMapChangesRec changes;
  XkbChangesRec _changes;
  unsigned int old_keysym;
  Bool retval;

  if (xkb->min_key_code > keycode ||
      keycode > xkb->max_key_code)
    return False;

  if (keysym == NULL)
    return False;

  offset = xkb->map->key_sym_map[keycode].offset;
  old_keysym = xkb->map->syms[offset];
  xkb->map->syms[offset] = *keysym;

#if USE_XKB
  changes.changed = XkbKeySymsMask;
  changes.first_key_sym = keycode;
  changes.num_key_syms = xkb->map->key_sym_map[keycode].width;

  XkbChangeMap (display, xkb, &changes);
  XSync (display, False);
#else
  XChangeKeyboardMapping (display,
                          keycode,
                          xkb->map->key_sym_map[keycode].width,
                          &xkb->map->syms[offset],
                          1);
  XSync (display, False);
#endif

  *keysym = old_keysym;

  return True;
}

int
main (void)
{
  int opcode, event_base, error_base, major_version, minor_version;
  unsigned int keycode;
  unsigned int keysym;

  display = XOpenDisplay (NULL);

  if (!XTestQueryExtension(display, &event_base, &error_base,
                           &major_version, &minor_version))
    {
      g_printerr ("XTest extension is not available\n");
      exit (1);
    }

  if (!XkbQueryExtension(display, &opcode, &event_base, &error_base,
                         &major_version, &minor_version))
    {
      g_printerr ("Xkb extension is not available\n");
      exit (1);
    }

  xkb = XkbGetMap (display, XkbAllComponentsMask, XkbUseCoreKbd);

  keycode = 38;                 /* keycode for 'a' key */
  keysym = 0x62;                /* keysym for 'b' */

  printf ("initial %X\n", XkbKeycodeToKeysym (display, keycode, 0, 0));
  replace_keycode (keycode, &keysym);
  printf ("replaced %X - type 'a'\n", XkbKeycodeToKeysym (display, keycode, 0, 
0));
  sleep (1);
  XTestFakeKeyEvent (display, keycode, True, 20);
  XSync (display, False);
  printf ("key pressed %X\n", XkbKeycodeToKeysym (display, keycode, 0, 0));
  XTestFakeKeyEvent (display, keycode, False, 20);
  XSync (display, False);
  printf ("key released %X\n", XkbKeycodeToKeysym (display, keycode, 0, 0));
  replace_keycode (keycode, &keysym);
  printf ("replaced %X\n", XkbKeycodeToKeysym (display, keycode, 0, 0));

  return 0;
}

/* Local Variables:  */
/* compile-command: "gcc -DUSE_XKB test-xkb-xtest.c -o test-xkb-xtest 
`pkg-config gobject-2.0 x11 xtst --cflags --libs`" */
/* End:              */
_______________________________________________
xorg@lists.x.org: X.Org support
Archives: http://lists.freedesktop.org/archives/xorg
Info: http://lists.x.org/mailman/listinfo/xorg
Your subscription address: arch...@mail-archive.com

Reply via email to