/* sendkey - a simple tool to automate testing key shortcuts using XTEST Copyright 2003 Matthew Allum SPDX-License-Identifier: GPL-2.0-or-later */ #include #include #include #include #include #include #include #include #include #include #define KEYDOWN 1 #define KEYUP 2 #define KEYDOWNUP 3 Display* dpy; Window win_root; int screen; void send_key(KeyCode character, int keydirection) { switch (keydirection) { case KEYDOWN: XTestFakeKeyEvent(dpy, (unsigned int) character, True, 0); break; case KEYUP: XTestFakeKeyEvent(dpy, (unsigned int) character, False, 0); break; case KEYDOWNUP: XTestFakeKeyEvent(dpy, (unsigned int) character, True, 0); XTestFakeKeyEvent(dpy, (unsigned int) character, False, 0); break; } } void usage( char *appname ) { fprintf(stderr, "%s [-d ] [+alt] [+meta] [+shift] [+ctrl] unshifted key\n", appname ); exit(1); } int main(int argc, char **argv) { #define noModifierMapIndex (Mod5MapIndex + 1) #define numModifierIndexes (noModifierMapIndex + 1) int ShiftModifierIndex = 0; int AltModifierIndex = 0; int MetaModifierIndex = 0; KeyCode modifierTable[numModifierIndexes]; XModifierKeymap *modifiers; KeyCode *kp, kc; KeySym ks; int modifier_index; int modifier_key; int event, error; int major, minor; int i; Bool controlMode = False, metaMode = False, altMode = False, shiftMode = False; Bool ks_error = False; char *dpy_name = NULL; char *wanted_keysym = NULL; for (i = 1; i < argc; i++) { if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) { if (++i>=argc) usage (argv[0]); dpy_name = argv[i++]; continue; } if (!strcmp ("+alt", argv[i])) { altMode = True; continue; } if (!strcmp ("+ctrl", argv[i])) { controlMode = True; continue; } if (!strcmp ("+meta", argv[i])) { metaMode = True; continue; } if (!strcmp ("+shift", argv[i])) { shiftMode = True; continue; } wanted_keysym = argv[i]; } if (wanted_keysym == NULL) { fprintf(stderr, "No keysym supplied\n"); usage(argv[0]); } if ((dpy = XOpenDisplay(dpy_name)) == NULL) { fprintf(stderr, "Cannot connect to X server on display %s.", dpy_name); usage(argv[0]); } screen = DefaultScreen(dpy); win_root = DefaultRootWindow(dpy); if (!XTestQueryExtension(dpy, &event, &error, &major, &minor)) { fprintf(stderr, "XTest extension not supported on server \"%s\"\n.", DisplayString(dpy)); exit(1); } XSync(dpy, True); modifiers = XGetModifierMapping(dpy); kp = modifiers->modifiermap; for (modifier_index = 0; modifier_index < 8; modifier_index++) { modifierTable[modifier_index] = 0; for (modifier_key = 0; modifier_key < modifiers->max_keypermod; modifier_key++) { int kc = kp[modifier_index * modifiers->max_keypermod + modifier_key]; if (kc) { modifierTable[modifier_index] = kc; break; } } } modifierTable[noModifierMapIndex] = 0; for (modifier_index = Mod1MapIndex; modifier_index <= Mod5MapIndex; modifier_index++) { if (modifierTable[modifier_index]) { ks = XKeycodeToKeysym(dpy, modifierTable[modifier_index], 0); switch (ks) { case XK_Meta_R: case XK_Meta_L: MetaModifierIndex = modifier_index; break; case XK_Alt_R: case XK_Alt_L: AltModifierIndex = modifier_index; break; case XK_Shift_R: case XK_Shift_L: ShiftModifierIndex = modifier_index; break; } } } if (controlMode) send_key(modifierTable[ControlMapIndex], KEYDOWN); if (metaMode) send_key(modifierTable[MetaModifierIndex], KEYDOWN); if (altMode) send_key(modifierTable[AltModifierIndex], KEYDOWN); if (shiftMode) send_key(modifierTable[ShiftModifierIndex], KEYDOWN); ks = XStringToKeysym(wanted_keysym); if (ks==NoSymbol) { fprintf(stderr, "%s: Unable to lookup keysym for %s\n", argv[0], wanted_keysym); ks_error = True; } kc = XKeysymToKeycode(dpy, ks); send_key(kc, KEYDOWNUP); if (controlMode) send_key(modifierTable[ControlMapIndex], KEYUP); if (metaMode) send_key(modifierTable[MetaModifierIndex], KEYUP); if (altMode) send_key(modifierTable[AltModifierIndex], KEYUP); if (shiftMode) send_key(modifierTable[ShiftModifierIndex], KEYUP); XFlush(dpy); if (ks_error) return 1; return 0; }