Problems with keyboard grabbing under GNOME.



I'm writing an application - kind of virtual keyboard - and I'd like
it to be able to grab keys, i.e. to have keyboard events delivered
to it even when it does not have a focus.  The following code demonstrates
problems I have with three approaches I've tried.  All three work[1] under
my simplistic (mostly WindowMaker and XTerm) environment, but fail with
GNOME.  I didn't test it under KDE yet.

Can somebody advise me how to do this correctly?  Thanks :-)


[1]. Ok, there is minor glitch with XGrabKey - key release events seem
     get lost, but that seems to be Xorg issue.



/* Example code to demonstrate problems with keyboard grabbing. */
/* Edward Tomasz Napierala <trasz FreeBSD org>, January 2008 */

/* $XConsortium: xev.c,v 1.15 94/04/17 20:45:20 keith Exp $ */
/*

   Copyright (c) 1988  X Consortium

   Permission is hereby granted, free of charge, to any person obtaining
   a copy of this software and associated documentation files (the
   "Software"), to deal in the Software without restriction, including
   without limitation the rights to use, copy, modify, merge, publish,
   distribute, sublicense, and/or sell copies of the Software, and to
   permit persons to whom the Software is furnished to do so, subject to
   the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
   OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of the X Consortium shall
   not be used in advertising or otherwise to promote the sale, use or
   other dealings in this Software without prior written authorization
   from the X Consortium.

 */
/* $XFree86: xc/programs/xev/xev.c,v 1.13 2003/10/24 20:38:17 tsi Exp $ */

/*
 * Author:  Jim Fulton, MIT X Consortium
 */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xproto.h>

const char *Yes = "YES";
const char *No = "NO";
const char *Unknown = "unknown";

Display *dpy;
int screen;

static void
prologue (XEvent *eventp, char *event_name)
{
	XAnyEvent *e = (XAnyEvent *) eventp;

	printf ("\n%s event, serial %ld, synthetic %s, window 0x%lx,\n",
			event_name, e->serial, e->send_event ? Yes : No, e->window);
}

static void
dump (char *str, int len)
{
	printf("(");
	len--;
	while (len-- > 0)
		printf("%02x ", (unsigned char) *str++);
	printf("%02x)", (unsigned char) *str++);
}

static void
do_KeyPress (XEvent *eventp)
{
	XKeyEvent *e = (XKeyEvent *) eventp;
	KeySym ks;
	KeyCode kc = 0;
	Bool kc_set = False;
	char *ksname;
	int nbytes;
	char str[256+1];
	static char *buf = NULL;
	static int bsize = 8;

	if (buf == NULL)
		buf = malloc (bsize);

	nbytes = XLookupString (e, str, 256, &ks, NULL);

	if (ks == NoSymbol)
		ksname = "NoSymbol";
	else {
		if (!(ksname = XKeysymToString (ks)))
			ksname = "(no name)";
		kc = XKeysymToKeycode(dpy, ks);
		kc_set = True;
	}

	printf ("    root 0x%lx, subw 0x%lx, time %lu, (%d,%d), root:(%d,%d),\n",
			e->root, e->subwindow, e->time, e->x, e->y, e->x_root, e->y_root);
	printf ("    state 0x%x, keycode %u (keysym 0x%lx, %s), same_screen %s,\n",
			e->state, e->keycode, (unsigned long) ks, ksname,
			e->same_screen ? Yes : No);
	if (kc_set && e->keycode != kc)
		printf ("    XKeysymToKeycode returns keycode: %u\n",kc);
	if (nbytes < 0) nbytes = 0;
	if (nbytes > 256) nbytes = 256;
	str[nbytes] = '\0';
	printf ("    XLookupString gives %d bytes: ", nbytes);
	if (nbytes > 0) {
		dump (str, nbytes);
		printf (" \"%s\"\n", str);
	} else {
		printf ("\n");
	}

	printf ("    XFilterEvent returns: %s\n", 
			XFilterEvent (eventp, e->window) ? "True" : "False");
}

static void
do_KeyRelease (XEvent *eventp)
{
	do_KeyPress (eventp);		/* since it has the same info */
}

int
main (int argc, char **argv)
{
	int i;

	dpy = XOpenDisplay (NULL);
	if (!dpy) {
		fprintf (stderr, "Unable to open display.\n");
		exit (1);
	}

	screen = DefaultScreen (dpy);

#if defined(XGRABKEY)
	/*
	 * Problem #1: This won't work at all under GNOME; it will fail with the following:
	 *
	 * X Error of failed request:  BadAccess (attempt to access private resource denied)
	 *   Major opcode of failed request:  33 (X_GrabKey)
	 *   Serial number of failed request:  7
	 *   Current serial number in output stream:  7
	 */
	XGrabKey(dpy, AnyKey, AnyModifier, DefaultRootWindow(dpy), True, GrabModeAsync, GrabModeAsync);

#elif defined(XGRABKEY2)
	/*
	 * Problem #2: This won't grab anything under GNOME - no keyboard events will
	 * be delivered to this process.
	 */
	KeySym keys_to_grab[] = { XK_q, XK_w, XK_e, XK_r, XK_t, XK_y, XK_VoidSymbol };

	for (i = 0; keys_to_grab[i] != XK_VoidSymbol; i++) {
		KeyCode kc = XKeysymToKeycode(dpy, keys_to_grab[i]);
		XGrabKey(dpy, kc, 0, DefaultRootWindow(dpy), True, GrabModeAsync, GrabModeAsync);
	}

#elif defined(XGRABKEYBOARD)
	/*
	 * Problem #3: This will interfere with Metacity; moving windows will be impossible.
         * Also, pull down menus in windows or gnome-panel won't work - menu name ("File",
	 * "Edit" etc) will become highlighted, but actual menu won't show up.
	 */
	XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, GrabModeAsync, CurrentTime);

#else
#error Pass either -DXGRABKEY, -DXGRABKEY2 or -DXGRABKEYBOARD at the compiler command line.
#endif

	/* Terminate after twenty events, so the user won't have problems with ungrabbing. */
	for (i = 0; i < 20; i++) {
		XEvent event;

		XNextEvent (dpy, &event);

		switch (event.type) {
			case KeyPress:
				prologue (&event, "KeyPress");
				do_KeyPress (&event);
				break;
			case KeyRelease:
				prologue (&event, "KeyRelease");
				do_KeyRelease (&event);
				break;
			default:
				printf ("Unknown event type %d\n", event.type);
				break;
		}
	}

	XCloseDisplay (dpy);

	return 0; 
}

-- 
If you cut off my head, what would I say?  Me and my head, or me and my body?



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]