diff options
author | Thorvald Natvig <slicer@users.sourceforge.net> | 2011-02-26 11:37:49 +0300 |
---|---|---|
committer | Thorvald Natvig <slicer@users.sourceforge.net> | 2011-02-26 11:37:49 +0300 |
commit | ffbeaa25e0290fa0f974e4e1b4697003c4058187 (patch) | |
tree | 8ff659b43119b8fd3fbda3301e7a3610d09ecd7c /src | |
parent | fcc8c2b759791a82ffeb291c81de7a165a638f69 (diff) |
XInput 2.0 support
Diffstat (limited to 'src')
-rw-r--r-- | src/mumble/GlobalShortcut_unix.cpp | 200 | ||||
-rw-r--r-- | src/mumble/GlobalShortcut_unix.h | 8 |
2 files changed, 64 insertions, 144 deletions
diff --git a/src/mumble/GlobalShortcut_unix.cpp b/src/mumble/GlobalShortcut_unix.cpp index a191086b7..e40f5d9f8 100644 --- a/src/mumble/GlobalShortcut_unix.cpp +++ b/src/mumble/GlobalShortcut_unix.cpp @@ -36,7 +36,6 @@ GlobalShortcutEngine *GlobalShortcutEngine::platformInit() { GlobalShortcutX::GlobalShortcutX() { bRunning=false; - bXInput = false; display = NULL; @@ -67,131 +66,57 @@ GlobalShortcutX::GlobalShortcutX() { return; } - XExtensionVersion *version = XGetExtensionVersion(display, INAME); - if (version && (version != reinterpret_cast<XExtensionVersion *>(NoSuchExtension))) { - bool bReturn = false; - qWarning("GlobalShortcutX: Using XInput %d.%d", version->major_version, version->minor_version); - - bXInput = true; - XFree(version); - - qmXDevices.clear(); - - qmConnections = startScreensConnection(display); - foreach(QSocketNotifier *qsNotif, qmConnections.keys()) { - Display *dpy = qmConnections.value(qsNotif); - initXInput(dpy); - - QMap<XID, XDevice *> *qmDisplayXDevices = qmXDevices.value(dpy); - - qWarning("GlobalShortcutX: TOTAL %ld --- %ld ", qmDisplayXDevices->count(), qmXDevices.count()); - - if (qmDisplayXDevices->isEmpty()) { - qWarning("GlobalShortcutX: No XInput devices"); - } else { - connect(qsNotif, SIGNAL(activated(int)), this, SLOT(displayReadyRead(int))); - bReturn = true; - } - } - if (bReturn) + for(int i=0; i < ScreenCount(display); ++i) + qsRootWindows.insert(RootWindow(display, i)); + + int evt, error; + + if (XQueryExtension(display, "XInputExtension", &iXIopcode, &evt, &error)) { + int major = 2; + int minor = 0; + int rc = XIQueryVersion(display, &major, &minor); + if (rc != BadRequest) { + qWarning("GlobalShortcutX: Using XI2 %d.%d", major, minor); + + XIEventMask evmask; + unsigned char mask[(XI_LASTEVENT + 7)/8]; + + memset(&evmask, 0, sizeof(evmask)); + memset(mask, 0, sizeof(mask)); + + XISetMask(mask, XI_RawButtonPress); + XISetMask(mask, XI_RawButtonRelease); + XISetMask(mask, XI_RawKeyPress); + XISetMask(mask, XI_RawKeyRelease); + + evmask.deviceid = XIAllMasterDevices; + evmask.mask_len = sizeof(mask); + evmask.mask = mask; + + foreach(Window w, qsRootWindows) + XISelectEvents(display, w, &evmask, 1); + XFlush(display); + + connect(new QSocketNotifier(ConnectionNumber(display), QSocketNotifier::Read, this), SIGNAL(activated(int)), this, SLOT(displayReadyRead(int))); + return; - } else { - qWarning("GlobalShortcutX: No XInput support, falling back to polled input. This wastes a lot of CPU resources, so please enable one of the other methods."); - bRunning=true; - start(QThread::TimeCriticalPriority); + } } + + qWarning("GlobalShortcutX: No XInput support, falling back to polled input. This wastes a lot of CPU resources, so please enable one of the other methods."); + bRunning=true; + start(QThread::TimeCriticalPriority); } GlobalShortcutX::~GlobalShortcutX() { bRunning = false; wait(); - foreach(Display *dpy, qmXDevices.keys()) { - QMap<XID, XDevice *> *qmDisplayXDevices = qmXDevices.value(dpy); - foreach(XDevice *dev, *qmDisplayXDevices) { - XCloseDevice(dpy, dev); - } - - } - - if (display) XCloseDisplay(display); } -QMap<QSocketNotifier *, Display *>GlobalShortcutX::startScreensConnection(Display *dpy) { - int iScreens = ScreenCount(display); - QMap<QSocketNotifier *, Display *>connections; - QString sDisplayPrefix = QString::fromAscii(DisplayString(dpy)); - - // get the dpy prefix - int iDotPos = sDisplayPrefix.indexOf(QString::fromAscii(".")); - sDisplayPrefix = sDisplayPrefix.left(iDotPos + 1); - - connections.insert(new QSocketNotifier(ConnectionNumber(dpy), QSocketNotifier::Read, this), dpy); - - for (int i=0; i < iScreens; i++) { - QString sDpyTmp = sDisplayPrefix + QString::number(i); - - if (sDpyTmp != QString::fromAscii(DisplayString(dpy))) { - Display *dpyconn = XOpenDisplay(sDpyTmp.toAscii()); - connections.insert(new QSocketNotifier(ConnectionNumber(dpyconn), QSocketNotifier::Read, this), dpyconn); - } - } - - return connections; -} - - - -void GlobalShortcutX::initXInput(Display *dpy) { - - int numdev; - XDeviceInfo *infolist = XListInputDevices(dpy, &numdev); - if (! infolist) - return; - - QMap<XID, XDevice *> *qmDisplayXDevices = new QMap<XID, XDevice *>(); - qmXDevices.insert(dpy, qmDisplayXDevices); - for (int i=0;i<numdev;++i) { - XDeviceInfo *info = infolist + i; - XDevice *dev = XOpenDevice(dpy, info->id); - if (dev) { - bool key = false, button = false; - for (int j=0;j<dev->num_classes;++j) { - XInputClassInfo *ici = dev->classes + j; - key = key || (ici->input_class == KeyClass); - button = button || (ici->input_class == ButtonClass); - } - - XEventClass events[4]; - int nevents = 0; - if (key) { - DeviceKeyPress(dev, iKeyPress, events[nevents]); - ++nevents; - DeviceKeyRelease(dev, iKeyRelease, events[nevents]); - ++nevents; - } - if (button) { - DeviceButtonPress(dev, iButtonPress, events[nevents]); - ++nevents; - DeviceButtonRelease(dev, iButtonRelease, events[nevents]); - ++nevents; - } - - if ((nevents != 0) && ! XSelectExtensionEvent(dpy, XDefaultRootWindow(dpy), events, nevents)) { - qWarning("GlobalShortcutX: XInput %ld:%s", info->id, info->name); - qmDisplayXDevices->insert(info->id, dev); - } else { - XCloseDevice(dpy, dev); - } - } - } - - XFree(infolist); -} - - +// Tight loop polling void GlobalShortcutX::run() { Window root = XDefaultRootWindow(display); Window root_ret, child_ret; @@ -235,41 +160,37 @@ void GlobalShortcutX::run() { } } +// XInput2 event is ready on socketnotifier. void GlobalShortcutX::displayReadyRead(int) { XEvent evt; if (bNeedRemap) remap(); - QSocketNotifier *source = (QSocketNotifier *)this->sender(); - - Display *dpy = qmConnections.value(source); - - while (XPending(dpy)) { - XNextEvent(dpy, &evt); - if ((evt.type == iButtonPress) || (evt.type == iButtonRelease)) { - XDeviceButtonEvent *be = reinterpret_cast<XDeviceButtonEvent *>(&evt); - handleButton(be->button + 0x117, evt.type == iButtonPress); - } else if ((evt.type == iKeyPress) || (evt.type == iKeyRelease)) { - XDeviceKeyEvent *ke = reinterpret_cast<XDeviceKeyEvent *>(&evt); - - if ((evt.type == iKeyRelease) && XPending(dpy)) { - // Is it a silly key repeat? - XEvent nxt; - XPeekEvent(dpy, &nxt); - if (nxt.type == iKeyPress) { - XDeviceKeyEvent *ne = reinterpret_cast<XDeviceKeyEvent *>(&nxt); - if (ke->keycode == ne->keycode) { - XNextEvent(dpy, &nxt); - continue; - } - } - } - handleButton(ke->keycode, evt.type == iKeyPress); + while (XPending(display)) { + XNextEvent(display, &evt); + XGenericEventCookie *cookie = & evt.xcookie; + + if ((cookie->type != GenericEvent) || (cookie->extension != iXIopcode) || !XGetEventData(display, cookie)) + continue; + + XIDeviceEvent *xide = reinterpret_cast<XIDeviceEvent *>(cookie->data); + switch(cookie->evtype) { + case XI_RawKeyPress: + case XI_RawKeyRelease: + handleButton(xide->detail, cookie->evtype == XI_RawKeyPress); + break; + case XI_RawButtonPress: + case XI_RawButtonRelease: + handleButton(xide->detail + 0x117, cookie->evtype == XI_RawButtonPress); + break; } + + XFreeEventData(display, cookie); } } +// One of the raw /dev/input devices has ready input void GlobalShortcutX::inputReadyRead(int) { #ifdef Q_OS_LINUX struct input_event ev; @@ -317,6 +238,7 @@ void GlobalShortcutX::inputReadyRead(int) { #define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) +// The /dev/input directory changed void GlobalShortcutX::directoryChanged(const QString &dir) { #ifdef Q_OS_LINUX QDir d(dir, QLatin1String("event*"), 0, QDir::System); diff --git a/src/mumble/GlobalShortcut_unix.h b/src/mumble/GlobalShortcut_unix.h index 3a73b11d1..014567978 100644 --- a/src/mumble/GlobalShortcut_unix.h +++ b/src/mumble/GlobalShortcut_unix.h @@ -35,7 +35,7 @@ #include <QX11Info> #include <X11/X.h> #include <X11/Xlib.h> -#include <X11/extensions/XInput.h> +#include <X11/extensions/XInput2.h> #include <X11/Xutil.h> #ifdef Q_OS_LINUX #include <linux/input.h> @@ -48,15 +48,13 @@ class GlobalShortcutX : public GlobalShortcutEngine { private: Q_OBJECT Q_DISABLE_COPY(GlobalShortcutX) - QMap<QSocketNotifier *, Display *> startScreensConnection(Display *); public: Display *display; + QSet<Window> qsRootWindows; + int iXIopcode; volatile bool bRunning; - QMap<QSocketNotifier *, Display *> qmConnections; - bool bXInput; QSet<QString> qsKeyboards; QMap<QString, QFile *> qmInputDevices; - QMap<Display *, QMap<XID, XDevice *> *> qmXDevices; GlobalShortcutX(); ~GlobalShortcutX(); |