PDA

View Full Version : Grabbing a key in X11



victor.fernandez
11th August 2008, 08:17
I'm trying to grab a key to use it as a global shortcut in X11. I reduced my code to a simple test:


#include <QtGui>
#include <QX11Info>

#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>

#ifdef KeyPress
const int XKeyPress = KeyPress;
const int XKeyRelease = KeyRelease;
#undef KeyPress
#undef KeyRelease
#endif

class GrabWidget : public QTextBrowser
{
Q_OBJECT

public:
GrabWidget(QWidget *parent)
: QTextBrowser(parent)
{
qApp->installEventFilter(this);

m_keyCode = XKeysymToKeycode(QX11Info::display(), XK_F11);
XGrabKey(QX11Info::display(), m_keyCode, ControlMask|ShiftMask, QX11Info::appRootWindow(), False, GrabModeAsync, GrabModeAsync);
XFlush(QX11Info::display());
}

~GrabWidget()
{
XUngrabKey(QX11Info::display(), m_keyCode, ControlMask|ShiftMask, QX11Info::appRootWindow());
}

bool GrabWidget::eventFilter(QObject */*watched*/, QEvent *event)
{
if(event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
int qtKey = keyEvent->key();
if(keyEvent->modifiers() == (Qt::ControlModifier|Qt::ShiftModifier) && qtKey == Qt::Key_F11) {
insertPlainText("Ctrl+Shift+F11 pressed!\n");
return false;
}
}
return true;
}

private:
int m_keyCode;
};

Grabbing the key seems to be working since I don't get any error message from Xlib (whereas I get BadAccess if I try to grab a different key which is already grabbed by another application) but I don't get any key press events, nor even if I press that key combination when my own widget has focus. So, what's wrong? How should I receive KeyPress events when I grab a key? I also tried with x11Event() but I get events only when my widget has focus not when another has it.

Thanks.

PS: I know it's not portable but I already made an implementation for Windows using RegisterHotKey() and now I'm just trying to implement it for X11.

jpn
11th August 2008, 14:13
Try QxtGlobalShortcut (http://doc.libqxt.org/latest/classQxtGlobalShortcut.html).

victor.fernandez
18th August 2008, 08:08
I already tried subclassing QApplication to reimplement x11EventFilter(), which is what QxtGlobalShortcut does. In fact I've tried it and it doesn't work. It has the same problem: XGrabKey seems to work but no key press notifications are received when the application doesn't have focus. Even when the application has it, QxtGlobalShortcut doesn't emit the activated() signal!


int main(int argc, char **argv)
{
QxtApplication app(argc, argv);
TestWidget t;
t.show();
return app.exec();
}


class TestWidget : public QTextBrowser
{
Q_OBJECT

public:
TestWidget(QWidget *parent = 0) : QTextBrowser(parent)
{
m_globalShortcut.setShortcut(QKeySequence("Ctrl+Shift+F11"));
m_globalShortcut.setEnabled(true);
connect(&m_globalShortcut, SIGNAL(activated()),
this, SLOT(logActivation()));
}

public slots:
void logActivation()
{
insertPlainText("+ Ctrl+Shift+F11 pressed!\n");
}

private:
QxtGlobalShortcut m_globalShortcut;
};

jpn
18th August 2008, 08:25
What does setShortcut() return? "Ctrl+Shift+F11" is probably reserved, thus registering the shortcut fails.

victor.fernandez
18th August 2008, 13:50
It always returns true, no matter which key combination I use. I tried with other key combinations, such as Ctrl+Shift+J, Ctrl+Alt+J or Ctrl+Alt+R, for instance. The only difference is that with the last one the following message is printed in the console:


X Error: BadAccess (attempt to access private resource denied) 10
Major opcode: 33 (X_GrabKey)
Resource id: 0x5d

So Ctrl+Alt+R is already grabbed by another application but the former key combinations aren't and they still don't work. :-( I have openSUSE 10.3 with X.org 7.2 here but I've also tried in openSUSE 11.0 with X.org 7.3 and got the same results. Key grabbing works in my system, as I have Yakuake here and whenever I press F12 it opens as expected.

jpn
20th August 2008, 21:24
Sorry, I almost forgot this thread. Anyway, I can confirm that the test application above works as it is just fine on my system (Kubuntu 8.04.1, X.org 7.3, Qt 4.4.0, Qxt 0.4.0).