Discussion:
Forwarding key events while using XGrabKeyboard
(too old to reply)
KWhat4
2007-10-15 07:15:59 UTC
Permalink
I have the following disaster of a program. It is a very simple
global keyboard listener that works except that it does not forward
any of the keys grabbed. I have no idea how to get it todo this or if
its even possible. Also i need to have key up and down events so the
other method that i believe is commented out somewhere in the mess
doesn't work.

PLEASE NOTE IF YOU ARE GOING TO COMPILE OR TEST THIS PROGRAM USE THE
SCRIPT TO RUN IT BELOW! It hooks all keys so once its running you
wont be able to kill it. (See issue above)

Any help would be appreciated,
Thanks.

//***Test CPP.

#include <stdio.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/XKBlib.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xutil.h>
#include <X11/Shell.h>

char *TranslateKeyCode(XEvent *ev);
Display *disp;
XEvent xev;

int iKeyCode;
int iKeyState;
int iKeyTime;

void snoop_x() {
//AnyKey
//AnyModifier
//XGrabKey(disp, XKeysymToKeycode(disp, XStringToKeysym("b")), None,
DefaultRootWindow(disp), TRUE, GrabModeSync, GrabModeSync);
}

int main(int argc, char* argv[]) {
//fprintf(stderr, "Loading JNI Keyboard Driver\n");
disp = XOpenDisplay(NULL);
if (disp == NULL) {
fprintf(stderr, "Can't open display: %s\n", XDisplayName(NULL));
//TODO NEED TO KILL PROGRAM AT THIS POINT
//exit(10);
}

//This is suppose to handle our BadWindow Error
//but it doesnt work and apperently it slows the
//system... Bad Idea
//XSynchronize(disp, TRUE);

//XSetErrorHandler(XErrIgnore);
//XAutoRepeatOff(disp);

XkbSetDetectableAutoRepeat(disp, TRUE, NULL);
snoop_x();

while (TRUE) {
XGrabKeyboard(disp, DefaultRootWindow(disp), TRUE, GrabModeAsync,
GrabModeAsync, CurrentTime);
XNextEvent(disp, &xev);
iKeyCode = xev.xkey.keycode;
//iKeyCode = XLookupKeysym(&xev.xkey, xev.xkey.state);
iKeyState = xev.xkey.state;
iKeyTime = xev.xkey.time;
int iKeyType = xev.type;
Window tmp = xev.xkey.window;
XUngrabKeyboard(disp, CurrentTime);



XPutBackEvent(disp, &xev);
XSelectInput(disp, tmp, KeyPressMask | KeyReleaseMask);
XGrabKey(disp, iKeyCode, None, tmp, TRUE, GrabModeAsync,
GrabModeAsync);
XNextEvent(disp, &xev);

//XSendEvent(disp, InputFocus, FALSE, xev.type, &xev);
XAllowEvents(disp, ReplayKeyboard, iKeyTime);



switch (iKeyType) {
case KeyPress:
//bKeyDown = TRUE;
fprintf(stderr, "Press");
break;

case KeyRelease:
//bKeyDown = FALSE;
fprintf(stderr, "Release");
break;
}

fprintf(stderr, "Key: %i %i %i\n", iKeyCode, xev.type, iKeyTime);



//XSetInputFocus(disp, PointerRoot, RevertToParent, iKeyTime);
//XSendEvent(disp, xev.xkey.subwindow, FALSE, xev.type, &xev);

XSync(disp, FALSE);
XFlush(disp);


//XUngrabKey(disp, xev.xkey.keycode, None, DefaultRootWindow(disp));
}
}


//** test.sh
#!/bin/bash

g++ -m32 -o test.bin -march=i586 -lX11 ./test.cpp

./test.bin &
PID=$!
sleep 10;
kill -9 $PID
KWhat4
2007-10-17 04:58:28 UTC
Permalink
ok the simple answer to this issue is that its not possible to do a
global event driven keybaord hook that doesnt hijack the keyboard in
this fashion. The only method that can be used is the xevie libs.
http://freedesktop.org/wiki/Software/XEvIE

Hopefully this will save others countless hours.
David L. Goldberg
2007-10-17 05:03:57 UTC
Permalink
Post by KWhat4
I have the following disaster of a program. It is a very simple
global keyboard listener that works except that it does not forward
any of the keys grabbed. I have no idea how to get it todo this or if
its even possible. Also i need to have key up and down events so the
other method that i believe is commented out somewhere in the mess
doesn't work.
PLEASE NOTE IF YOU ARE GOING TO COMPILE OR TEST THIS PROGRAM USE THE
SCRIPT TO RUN IT BELOW! It hooks all keys so once its running you
wont be able to kill it. (See issue above)
Any help would be appreciated,
Thanks.
//***Test CPP.
#include <stdio.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/XKBlib.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xutil.h>
#include <X11/Shell.h>
char *TranslateKeyCode(XEvent *ev);
Display *disp;
XEvent xev;
int iKeyCode;
int iKeyState;
int iKeyTime;
void snoop_x() {
//AnyKey
//AnyModifier
//XGrabKey(disp, XKeysymToKeycode(disp, XStringToKeysym("b")), None,
DefaultRootWindow(disp), TRUE, GrabModeSync, GrabModeSync);
}
int main(int argc, char* argv[]) {
//fprintf(stderr, "Loading JNI Keyboard Driver\n");
disp = XOpenDisplay(NULL);
if (disp == NULL) {
fprintf(stderr, "Can't open display: %s\n", XDisplayName(NULL));
//TODO NEED TO KILL PROGRAM AT THIS POINT
//exit(10);
}
//This is suppose to handle our BadWindow Error
//but it doesnt work and apperently it slows the
//system... Bad Idea
//XSynchronize(disp, TRUE);
//XSetErrorHandler(XErrIgnore);
//XAutoRepeatOff(disp);
XkbSetDetectableAutoRepeat(disp, TRUE, NULL);
snoop_x();
while (TRUE) {
XGrabKeyboard(disp, DefaultRootWindow(disp), TRUE, GrabModeAsync,
GrabModeAsync, CurrentTime);
XNextEvent(disp, &xev);
iKeyCode = xev.xkey.keycode;
//iKeyCode = XLookupKeysym(&xev.xkey, xev.xkey.state);
iKeyState = xev.xkey.state;
iKeyTime = xev.xkey.time;
int iKeyType = xev.type;
Window tmp = xev.xkey.window;
XUngrabKeyboard(disp, CurrentTime);
XPutBackEvent(disp, &xev);
XSelectInput(disp, tmp, KeyPressMask | KeyReleaseMask);
XGrabKey(disp, iKeyCode, None, tmp, TRUE, GrabModeAsync,
GrabModeAsync);
XNextEvent(disp, &xev);
//XSendEvent(disp, InputFocus, FALSE, xev.type, &xev);
XAllowEvents(disp, ReplayKeyboard, iKeyTime);
switch (iKeyType) {
//bKeyDown = TRUE;
fprintf(stderr, "Press");
break;
//bKeyDown = FALSE;
fprintf(stderr, "Release");
break;
}
fprintf(stderr, "Key: %i %i %i\n", iKeyCode, xev.type, iKeyTime);
//XSetInputFocus(disp, PointerRoot, RevertToParent, iKeyTime);
//XSendEvent(disp, xev.xkey.subwindow, FALSE, xev.type, &xev);
XSync(disp, FALSE);
XFlush(disp);
//XUngrabKey(disp, xev.xkey.keycode, None, DefaultRootWindow(disp));
}
}
//** test.sh
#!/bin/bash
g++ -m32 -o test.bin -march=i586 -lX11 ./test.cpp
./test.bin &
PID=$!
sleep 10;
kill -9 $PID
XSynchronize is just for debugging purposes I believe.

I have a project at http://uix.sourceforge.net in which I do some of
what you are trying to do (I think).
It's early development still but I last left off struggling with a
similar piece of code.
Be careful in the current version (works someone in kde if you turn
off numlock)
uploaded I have at least 2 bad errors. One was a processing error I
fixed by removing the XPending in UIX.cpp after the XGrabKey. The
next is a memory leak I still have to find.

There's still a LOT of broken code in there but hope its a little
helpful.

Loading...