rendered paste body/* $Id$ */
#include <assert.h>
#include <ctype.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XTest.h>
/*
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) */
};