All pastes #38842 Raw Edit

Someone

public text v1 · immutable
#38842 ·published 2006-01-27 21:11 UTC
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) */
};