/* $Id$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* Toggle for debugging. */ #if 1 #undef NDEBUG #endif int screen; Window root; Display *display; unsigned int depth; Bool is_XTEST_available = False; extern KeySym ascii_keysyms[256]; /* Function prototypes. */ void execute(unsigned int user_keycode, const XEvent *trigger_event); unsigned int find_modifier_mask (const char *); int grabkey_failed (Display *, XErrorEvent *); void usage (void); /* */ int main(int argc, char **argv) { int c; unsigned int user_keycode; /* Parse command-line options. */ while ( (c = getopt(argc, argv, "hv")) != -1) { switch (c) { case 'h': usage(); exit(EXIT_SUCCESS); break; case 'v': puts(PACKAGE " " VERSION); exit(EXIT_SUCCESS); break; case '?': default: usage(); exit(EXIT_FAILURE); break; } } argc -= optind; argv += optind; /* Open the connection with the X11 display. */ if ( (display = XOpenDisplay(NULL)) == NULL) { fprintf(stderr, "xascii: unable to open display \"%s\"\n", XDisplayName(NULL)); exit(EXIT_FAILURE); } /* Set global variables */ root = DefaultRootWindow(display); screen = DefaultScreen(display); depth = DefaultDepth(display, screen); { int major_opcode_return; int first_event_return; int first_error_return; #if 0 if (XQueryExtension(display, "XTEST", &major_opcode_return, &first_event_return, &first_error_return) == False) { puts("The extension XTEST is not available. " "It is likely that xascii will not work with most " "applications including xterm, GTK+, etc."); is_XTEST_available = False; } else { is_XTEST_available = True; } #endif } user_keycode = XKeysymToKeycode(display, XK_Alt_L); if (user_keycode == 0) { fputs("Failed to find your Alt key\n", stderr); exit(EXIT_FAILURE); } /* Grab the keys. */ { int (*temp)(Display *, XErrorEvent *); unsigned int numlock_mod = find_modifier_mask("Num_Lock"); #if 0 KeySym syms[] = { XK_KP_0, XK_KP_1, XK_KP_2, XK_KP_3, XK_KP_4, XK_KP_5, XK_KP_6, XK_KP_7, XK_KP_8, XK_KP_9 }; size_t i; #endif XSync(display, False); temp = XSetErrorHandler(grabkey_failed); { XGrabKey(display, user_keycode, 0, root, True, GrabModeAsync, GrabModeAsync); XGrabKey(display, user_keycode, LockMask, root, True, GrabModeAsync, GrabModeAsync); if (numlock_mod != 0) { XGrabKey(display, user_keycode, numlock_mod, root, True, GrabModeAsync, GrabModeAsync); XGrabKey(display, user_keycode, numlock_mod|LockMask, root, True, GrabModeAsync, GrabModeAsync); } } #if 0 for (i = 0; i < sizeof syms / sizeof syms[0]; ++i) { KeyCode keycode; keycode = XKeysymToKeycode(display, syms[i]); /* This shouldn't happen */ if (keycode == 0) { continue; } XGrabKey(display, keycode, user_mod, root, True, GrabModeAsync, GrabModeAsync); XGrabKey(display, keycode, user_mod|LockMask, root, True, GrabModeAsync, GrabModeAsync); if (numlock_mod != 0) { XGrabKey(display, keycode, user_mod|numlock_mod, root, True, GrabModeAsync, GrabModeAsync); XGrabKey(display, keycode, user_mod|numlock_mod|LockMask, root, True, GrabModeAsync, GrabModeAsync); } } #endif XSync(display, False); XSetErrorHandler(temp); } XSelectInput(display, root, KeyPressMask|KeyReleaseMask); /* Iterate waiting for the next occasion that the user press they key combination. */ for ( ; ; ) { XEvent event; XNextEvent(display, &event); switch (event.type) { case KeyPress: { #ifndef NDEBUG /*puts("Calling execute()");*/ #endif execute(user_keycode, &event); XUngrabKeyboard(display, CurrentTime); } break; } } XCloseDisplay(display); return 0; } /* Print program usage information to the user. */ void usage(void) { fputs("xascii [-hv]\n" "\t-h\tDisplay this help message\n" "\t-v\tPrint version number\n", stderr); } /* */ void execute(unsigned int user_keycode, const XEvent *trigger_event) { size_t len = 0; Bool cancel = False; char command[50] = ""; /* Really, we should only need 4 bytes */ int ascii; char dummy; KeyCode keycode; KeySym keysym; /* Read user input. */ for (; ; ) { XEvent xevent; KeySym keysym; char name[50]; int name_length; XWindowEvent(display, root, KeyReleaseMask|KeyPressMask, &xevent); if (xevent.type == KeyRelease) { if (xevent.xkey.keycode == user_keycode) { break; } else { continue; } } name_length = XLookupString(&xevent.xkey, name, sizeof name - 1, &keysym, NULL); name[name_length] = '\0'; if (name_length != 1 || isdigit(name[0]) == 0) { #ifndef NDEBUG puts("Invalid!"); #endif return; } /* Making sure we don't overflow the limit of `command'. */ if (len >= sizeof command - 1) { fputs("xascii: number too big/long\n", stderr); cancel = True; } command[len] = name[0]; command[++len] = '\0'; } #ifndef NDEBUG printf("Command \"%s\"\n", command); #endif if (strlen(command) == 0) { #ifndef NDEBUG puts("Empty!"); #endif return; } if (sscanf(command, "%d%c", &ascii, &dummy) != 1) { #ifndef NDEBUG puts("Impossible!"); #endif } #ifndef NDEBUG printf("Ascii %#x (%d) \"%s\"\n", ascii, ascii, XKeysymToString(ascii_keysyms[ascii]) == NULL ? "" : XKeysymToString(ascii_keysyms[ascii])); #endif if (ascii < 0 || ascii > 255) { #ifndef NDEBUG puts("Value out of range!"); #endif return; } if (ascii_keysyms[ascii] == 0) { #ifndef NDEBUG puts("Invalid character value"); #endif return; } keysym = ascii_keysyms[ascii]; keycode = XKeysymToKeycode(display, keysym); if (keycode == 0) { #ifndef NDEBUG puts("No matching keycode for keysym"); #endif return; } /* Send the keypress. */ if (is_XTEST_available == True) { /* Send KeyPress then KeyRelease. */ XTestFakeKeyEvent(display, keycode, True , CurrentTime); XTestFakeKeyEvent(display, keycode, False, CurrentTime); } else { XEvent xevent = *trigger_event; KeySym *syms; int keysyms_per_keycode_return; size_t i; #if 0 syms = XGetKeyboardMapping(display, keycode, 1, &keysyms_per_keycode_return); for (i = 0; i < keysyms_per_keycode_return; ++i) { if (syms[i] == keysym) { printf("Found at %d\n", i); /* Big guess / Kludge */ if (i == 1) { xevent.xkey.state |= ShiftMask; } } } printf("%d\n", keysyms_per_keycode_return); XFree(syms); #endif /*xevent.xkey.time = CurrentTime;*/ xevent.xkey.keycode = keycode; xevent.type = KeyPress; XSendEvent(display, InputFocus, True, KeyPressMask, &xevent); xevent.type = KeyRelease; XSendEvent(display, InputFocus, True, KeyReleaseMask, &xevent); } } /* Find the modifier mask for a symbolic key name (KeySym). */ unsigned int find_modifier_mask(const char *name) { int i; XModifierKeymap *map; unsigned int modmask = 0; if ( (map = XGetModifierMapping(display)) == NULL) { fprintf(stderr, "xascii: Failed to find your \"%s\" key\n", name); return 0; } for (i = 0; i < 8; ++i) { int j; for (j = 0; j < map->max_keypermod; ++j) { KeySym sym; char *s; int index = 0; int min_keycode, max_keycode, keysyms_per_keycode = 0; const KeyCode keycode = *(map->modifiermap + (i * map->max_keypermod) + j); if (keycode == 0) { continue; } XDisplayKeycodes(display, &min_keycode, &max_keycode); XGetKeyboardMapping(display, min_keycode, max_keycode - min_keycode + 1, &keysyms_per_keycode); do { sym = XKeycodeToKeysym(display, keycode, index); index++; } while (sym == NoSymbol && index < keysyms_per_keycode); s = XKeysymToString(sym); /* If this is the name we are looking for. */ if (s != NULL && strcmp(s, name) == 0) { #ifndef NDEBUG puts("Found Num_Lock modifier"); #endif switch (i) { case 0: modmask |= ShiftMask; break; case 1: modmask |= LockMask; break; case 2: modmask |= ControlMask; break; case 3: modmask |= Mod1Mask; break; case 4: modmask |= Mod2Mask; break; case 5: modmask |= Mod3Mask; break; case 6: modmask |= Mod4Mask; break; case 7: modmask |= Mod5Mask; break; default: assert(0); break; } } } } if (map != NULL) { XFreeModifiermap(map); } return modmask; } /* This is called if XGrabKey failed. Print a more friendly error message then the default Xlib error handler and exit gracefully. */ int grabkey_failed(Display *display, XErrorEvent *error) { fputs("xascii: Failed to grab numpad key bindings\n", stderr); puts("Maybe an other instance of the program is already running\n" "or an other program is already using these key bindings"); exit(EXIT_FAILURE); } /* This might have a few extra entries. */ KeySym ascii_keysyms[256] = { 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ XK_space, /* 0x20 ( 32) */ XK_exclam, /* 0x21 ( 33) */ XK_quotedbl, /* 0x22 ( 34) */ XK_numbersign, /* 0x23 ( 35) */ XK_dollar, /* 0x24 ( 36) */ XK_percent, /* 0x25 ( 37) */ XK_ampersand, /* 0x26 ( 38) */ XK_apostrophe, /* 0x27 ( 39) */ XK_parenleft, /* 0x28 ( 40) */ XK_parenright, /* 0x29 ( 41) */ XK_asterisk, /* 0x2a ( 42) */ XK_plus, /* 0x2b ( 43) */ XK_comma, /* 0x2c ( 44) */ XK_minus, /* 0x2d ( 45) */ XK_period, /* 0x2e ( 46) */ XK_slash, /* 0x2f ( 47) */ XK_0, /* 0x30 ( 48) */ XK_1, /* 0x31 ( 49) */ XK_2, /* 0x32 ( 50) */ XK_3, /* 0x33 ( 51) */ XK_4, /* 0x34 ( 52) */ XK_5, /* 0x35 ( 53) */ XK_6, /* 0x36 ( 54) */ XK_7, /* 0x37 ( 55) */ XK_8, /* 0x38 ( 56) */ XK_9, /* 0x39 ( 57) */ XK_colon, /* 0x3a ( 58) */ XK_semicolon, /* 0x3b ( 59) */ XK_less, /* 0x3c ( 60) */ XK_equal, /* 0x3d ( 61) */ XK_greater, /* 0x3e ( 62) */ XK_question, /* 0x3f ( 63) */ XK_at, /* 0x40 ( 64) */ 0, /* 0x00 ( 65) */ 0, /* 0x00 ( 66) */ 0, /* 0x00 ( 67) */ 0, /* 0x00 ( 68) */ 0, /* 0x00 ( 69) */ 0, /* 0x00 ( 70) */ 0, /* 0x00 ( 71) */ 0, /* 0x00 ( 72) */ 0, /* 0x00 ( 73) */ 0, /* 0x00 ( 74) */ 0, /* 0x00 ( 75) */ 0, /* 0x00 ( 76) */ 0, /* 0x00 ( 77) */ 0, /* 0x00 ( 78) */ 0, /* 0x00 ( 79) */ 0, /* 0x00 ( 80) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ 0, /* 0x00 ( 0) */ };