]> source.dussan.org Git - tigervnc.git/commitdiff
x0vncserver: add support for led state notifications
authorPeter Korsgaard <peter.korsgaard@barco.com>
Wed, 12 Jul 2017 22:36:01 +0000 (00:36 +0200)
committerPierre Ossman <ossman@cendio.se>
Mon, 28 Aug 2017 11:54:30 +0000 (13:54 +0200)
Listen for XKb XkbIndicatorStateNotify events for scroll/num/caps lock and
map them to the RFB protocol.

Signed-off-by: Peter Korsgaard <peter.korsgaard@barco.com>
unix/x0vncserver/x0vncserver.cxx

index 8f73ac2ce749557680da94841ccdfa321f007427..9e5da4f9d1bfe963c83f300ab93ae39278558922 100644 (file)
@@ -39,6 +39,7 @@
 #include <X11/X.h>
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
+#include <X11/XKBlib.h>
 #ifdef HAVE_XTEST
 #include <X11/extensions/XTest.h>
 #endif
@@ -61,6 +62,14 @@ extern char buildtime[];
 using namespace rfb;
 using namespace network;
 
+// number of XKb indicator leds to handle
+static const int N_LEDS = 3;
+
+// order is important as it must match RFB extension
+static const char * ledNames[N_LEDS] = {
+  "Scroll Lock", "Num Lock", "Caps Lock"
+};
+
 static LogWriter vlog("Main");
 
 IntParameter pollingCycle("PollingCycle", "Milliseconds per one polling "
@@ -141,12 +150,42 @@ public:
   XDesktop(Display* dpy_, Geometry *geometry_)
     : dpy(dpy_), geometry(geometry_), pb(0), server(0),
       oldButtonMask(0), haveXtest(false), haveDamage(false),
-      maxButtons(0), running(false)
+      maxButtons(0), running(false), ledMasks(), ledState(0)
   {
+    int major, minor;
+
+    int xkbOpcode, xkbErrorBase;
+
+    major = XkbMajorVersion;
+    minor = XkbMinorVersion;
+    if (!XkbQueryExtension(dpy, &xkbOpcode, &xkbEventBase,
+                           &xkbErrorBase, &major, &minor)) {
+      vlog.error("XKEYBOARD extension not present");
+      throw Exception();
+    }
+
+    XkbSelectEvents(dpy, XkbUseCoreKbd, XkbIndicatorStateNotifyMask,
+                    XkbIndicatorStateNotifyMask);
+
+    // figure out bit masks for the indicators we are interested in
+    for (int i = 0; i < N_LEDS; i++) {
+      Atom a;
+      int shift;
+      Bool on;
+
+      a = XInternAtom(dpy, ledNames[i], True);
+      if (!a || !XkbGetNamedIndicator(dpy, a, &shift, &on, NULL, NULL))
+        continue;
+
+      ledMasks[i] = 1u << shift;
+      vlog.debug("Mask for '%s' is 0x%x", ledNames[i], ledMasks[i]);
+      if (on)
+        ledState |= 1u << i;
+    }
+
 #ifdef HAVE_XTEST
     int xtestEventBase;
     int xtestErrorBase;
-    int major, minor;
 
     if (XTestQueryExtension(dpy, &xtestEventBase,
                             &xtestErrorBase, &major, &minor)) {
@@ -165,7 +204,6 @@ public:
     int xdamageErrorBase;
 
     if (XDamageQueryExtension(dpy, &xdamageEventBase, &xdamageErrorBase)) {
-      TXWindow::setGlobalEventHandler(this);
       haveDamage = true;
     } else {
 #endif
@@ -174,6 +212,8 @@ public:
 #ifdef HAVE_XDAMAGE
     }
 #endif
+
+    TXWindow::setGlobalEventHandler(this);
   }
   virtual ~XDesktop() {
     stop();
@@ -212,6 +252,8 @@ public:
     }
 #endif
 
+    server->setLEDState(ledState);
+
     running = true;
   }
 
@@ -272,24 +314,41 @@ public:
   // -=- TXGlobalEventHandler interface
 
   virtual bool handleGlobalEvent(XEvent* ev) {
-#ifdef HAVE_XDAMAGE
-    XDamageNotifyEvent* dev;
-    Rect rect;
+    if (ev->type == xkbEventBase + XkbEventCode) {
+      XkbEvent *kb = (XkbEvent *)ev;
 
-    if (ev->type != xdamageEventBase)
-      return false;
+      if (kb->any.xkb_type != XkbIndicatorStateNotify)
+        return false;
+
+      vlog.debug("Got indicator update, mask is now 0x%x", kb->indicators.state);
+
+      ledState = 0;
+      for (int i = 0; i < N_LEDS; i++) {
+        if (kb->indicators.state & ledMasks[i])
+          ledState |= 1u << i;
+      }
+
+      if (running)
+        server->setLEDState(ledState);
 
-    if (!running)
       return true;
+#ifdef HAVE_XDAMAGE
+    } else if (ev->type == xdamageEventBase) {
+      XDamageNotifyEvent* dev;
+      Rect rect;
 
-    dev = (XDamageNotifyEvent*)ev;
-    rect.setXYWH(dev->area.x, dev->area.y, dev->area.width, dev->area.height);
-    server->add_changed(rect);
+      if (!running)
+        return true;
 
-    return true;
-#else
-  return false;
+      dev = (XDamageNotifyEvent*)ev;
+      rect.setXYWH(dev->area.x, dev->area.y, dev->area.width, dev->area.height);
+      server->add_changed(rect);
+
+      return true;
 #endif
+    }
+
+    return false;
   }
 
 protected:
@@ -306,6 +365,9 @@ protected:
   Damage damage;
   int xdamageEventBase;
 #endif
+  int xkbEventBase;
+  int ledMasks[N_LEDS];
+  unsigned ledState;
 };