/* This program does: * * (1) change keysym mapping 'a' -> 'b' * (2) emit key press/release event, with XTestFakeKeyEvent * (3) change keysym mapping 'b' -> 'a' */ #include #include #include #include #include #include Display *display; XkbDescRec *xkb; static unsigned int get_xtest_device () { Atom xtest_prop = XInternAtom(display, "XTEST Device", True); XIDeviceInfo *info; int ndevices, i; info = XIQueryDevice(display, XIAllDevices, &ndevices); for (i = 0; i < ndevices; i++) { XIDeviceInfo *device = &info[i]; if (device->use == XISlaveKeyboard) { Atom type; int format; unsigned long num_items; unsigned long bytes_after; unsigned char data[4]; XIGetProperty (display, device->deviceid, xtest_prop, 0, 1, False, XA_INTEGER, &type, &format, &num_items, &bytes_after, (unsigned char **) &data); if (data[3] != 0) return device->deviceid; } } return 0; } static Bool replace_keycode (unsigned int keycode, unsigned int *keysym) { unsigned int offset; XkbMapChangesRec changes; XkbChangesRec _changes; XkbKeyTypeRec *type; 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]; type = &xkb->map->types[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) { XkbDeviceInfoRec *device; int opcode, event_base, error_base, major_version, minor_version; unsigned int keycode; unsigned int keysym; unsigned int xtest_device; display = XOpenDisplay (NULL); if (!XTestQueryExtension(display, &event_base, &error_base, &major_version, &minor_version)) { fprintf (stderr, "XTest extension is not available\n"); exit (1); } if (!XkbQueryExtension(display, &opcode, &event_base, &error_base, &major_version, &minor_version)) { fprintf (stderr, "Xkb extension is not available\n"); exit (1); } if (!XQueryExtension(display, "XInputExtension", &opcode, &event_base, &error_base)) { fprintf (stderr, "X Input extension not available.\n"); exit (1); } #if defined(USE_XKB) && defined(USE_CORE) xtest_device = XkbUseCoreKbd; #else xtest_device = get_xtest_device (); if (xtest_device == 0) { fprintf (stderr, "Can't get XTEST device\n"); exit (1); } #endif xkb = XkbGetMap (display, XkbAllComponentsMask, xtest_device); xkb->device_spec = xtest_device; 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)); XTestFakeKeyEvent (display, keycode, True, 0); XSync (display, False); printf ("key pressed %X\n", XkbKeycodeToKeysym (display, keycode, 0, 0)); XTestFakeKeyEvent (display, keycode, False, 0); 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 x11 xtst xi --cflags --libs`" */ /* End: */