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