]> source.dussan.org Git - tigervnc.git/commitdiff
Sync LED state when gaining focus
authorPierre Ossman <ossman@cendio.se>
Sat, 10 Dec 2016 16:13:40 +0000 (17:13 +0100)
committerPierre Ossman <ossman@cendio.se>
Thu, 24 Aug 2017 10:33:08 +0000 (12:33 +0200)
The state might have changed when we didn't have focus. Get
everything back in sync once we're back in control.

vncviewer/DesktopWindow.cxx
vncviewer/Viewport.cxx
vncviewer/Viewport.h
vncviewer/cocoa.h
vncviewer/cocoa.mm

index 3973cd66334844e92b8794658f4b6e17cb9a0e2d..897f9557382b3ef679d462563d9051404c0a43f5 100644 (file)
@@ -666,23 +666,31 @@ int DesktopWindow::fltkHandle(int event, Fl_Window *win)
 
   DesktopWindow *dw = dynamic_cast<DesktopWindow*>(win);
 
-  if (dw && fullscreenSystemKeys) {
+  if (dw) {
     switch (event) {
     case FL_FOCUS:
-      // FIXME: We reassert the keyboard grabbing on focus as FLTK there are
-      //        some issues we need to work around:
-      //        a) Fl::grab(0) on X11 will release the keyboard grab for us.
-      //        b) Gaining focus on the system level causes FLTK to switch
-      //           window level on OS X.
-      if (dw->fullscreen_active())
-        dw->grabKeyboard();
+      if (fullscreenSystemKeys) {
+        // FIXME: We reassert the keyboard grabbing on focus as FLTK there are
+        //        some issues we need to work around:
+        //        a) Fl::grab(0) on X11 will release the keyboard grab for us.
+        //        b) Gaining focus on the system level causes FLTK to switch
+        //           window level on OS X.
+        if (dw->fullscreen_active())
+          dw->grabKeyboard();
+      }
+
+      // We may have gotten our lock keys out of sync with the server
+      // whilst we didn't have focus. Try to sort this out.
+      dw->viewport->pushLEDState();
       break;
 
     case FL_UNFOCUS:
-      // FIXME: We need to relinquish control when the entire window loses
-      //        focus as it is very tied to this specific window on some
-      //        platforms and we want to be able to open subwindows.
-      dw->ungrabKeyboard();
+      if (fullscreenSystemKeys) {
+        // FIXME: We need to relinquish control when the entire window loses
+        //        focus as it is very tied to this specific window on some
+        //        platforms and we want to be able to open subwindows.
+        dw->ungrabKeyboard();
+      }
       break;
     }
   }
index c0bbd0dd2c22d0ea076de8e4359ae7c17925ca90..bfadd4c0ec7c25681f711f2de53b2c08258f1e50 100644 (file)
@@ -329,6 +329,87 @@ void Viewport::setLEDState(unsigned int state)
 #endif
 }
 
+void Viewport::pushLEDState()
+{
+  unsigned int state;
+
+  // Server support?
+  if (cc->cp.ledState() == ledUnknown)
+    return;
+
+  state = 0;
+
+#if defined(WIN32)
+  if (GetKeyState(VK_CAPITAL) & 0x1)
+    state |= ledCapsLock;
+  if (GetKeyState(VK_NUMLOCK) & 0x1)
+    state |= ledNumLock;
+  if (GetKeyState(VK_SCROLL) & 0x1)
+    state |= ledScrollLock;
+#elif defined(__APPLE__)
+  int ret;
+  bool on;
+
+  ret = cocoa_get_caps_lock_state(&on);
+  if (ret != 0) {
+    vlog.error(_("Failed to get keyboard LED state: %d"), ret);
+    return;
+  }
+  if (on)
+    state |= ledCapsLock;
+
+  ret = cocoa_get_num_lock_state(&on);
+  if (ret != 0) {
+    vlog.error(_("Failed to get keyboard LED state: %d"), ret);
+    return;
+  }
+  if (on)
+    state |= ledNumLock;
+
+  // No support for Scroll Lock //
+  state |= (cc->cp.ledState() & ledScrollLock);
+
+#else
+  unsigned int mask;
+
+  Status status;
+  XkbStateRec xkbState;
+
+  status = XkbGetState(fl_display, XkbUseCoreKbd, &xkbState);
+  if (status != Success) {
+    vlog.error(_("Failed to get keyboard LED state: %d"), status);
+    return;
+  }
+
+  if (xkbState.locked_mods & LockMask)
+    state |= ledCapsLock;
+
+  mask = getModifierMask(XK_Num_Lock);
+  if (xkbState.locked_mods & mask)
+    state |= ledNumLock;
+
+  mask = getModifierMask(XK_Scroll_Lock);
+  if (xkbState.locked_mods & mask)
+    state |= ledScrollLock;
+#endif
+
+  if ((state & ledCapsLock) != (cc->cp.ledState() & ledCapsLock)) {
+    vlog.debug("Inserting fake CapsLock to get in sync with server");
+    handleKeyPress(fakeKeyBase + 100, XK_Caps_Lock);
+    handleKeyRelease(fakeKeyBase + 100);
+  }
+  if ((state & ledNumLock) != (cc->cp.ledState() & ledNumLock)) {
+    vlog.debug("Inserting fake NumLock to get in sync with server");
+    handleKeyPress(fakeKeyBase + 101, XK_Num_Lock);
+    handleKeyRelease(fakeKeyBase + 101);
+  }
+  if ((state & ledScrollLock) != (cc->cp.ledState() & ledScrollLock)) {
+    vlog.debug("Inserting fake ScrollLock to get in sync with server");
+    handleKeyPress(fakeKeyBase + 102, XK_Scroll_Lock);
+    handleKeyRelease(fakeKeyBase + 102);
+  }
+}
+
 
 void Viewport::draw(Surface* dst)
 {
index 652feb45a1181841c10a1c05f249ba5d65e1b754..31158c2d2a2f186e02abed5ea758f2e7e3c10efa 100644 (file)
@@ -49,6 +49,8 @@ public:
 
   // Change client LED state
   void setLEDState(unsigned int state);
+  // Change server LED state
+  void pushLEDState();
 
   void draw(Surface* dst);
 
index b5d5f763ce3e10b320aa8e253b59a5e81e2c8fb9..a713802685c7dd18b7da800046205914d2702166 100644 (file)
@@ -36,4 +36,7 @@ int cocoa_event_keysym(const void *event);
 int cocoa_set_caps_lock_state(bool on);
 int cocoa_set_num_lock_state(bool on);
 
+int cocoa_get_caps_lock_state(bool *on);
+int cocoa_get_num_lock_state(bool *on);
+
 #endif
index 6483291c6d3794c5ecc840478a55c82e60e807e0..e26851d6e79d8a333886b8b278ecabb6f1374485 100644 (file)
@@ -447,6 +447,23 @@ static int cocoa_set_modifier_lock_state(int modifier, bool on)
   return KERN_SUCCESS;
 }
 
+static int cocoa_get_modifier_lock_state(int modifier, bool *on)
+{
+  kern_return_t ret;
+  io_connect_t ioc;
+
+  ret = cocoa_open_hid(&ioc);
+  if (ret != KERN_SUCCESS)
+    return ret;
+
+  ret = IOHIDGetModifierLockState(ioc, modifier, on);
+  IOServiceClose(ioc);
+  if (ret != KERN_SUCCESS)
+    return ret;
+
+  return KERN_SUCCESS;
+}
+
 int cocoa_set_caps_lock_state(bool on)
 {
   return cocoa_set_modifier_lock_state(kIOHIDCapsLockState, on);
@@ -456,3 +473,13 @@ int cocoa_set_num_lock_state(bool on)
 {
   return cocoa_set_modifier_lock_state(kIOHIDNumLockState, on);
 }
+
+int cocoa_get_caps_lock_state(bool *on)
+{
+  return cocoa_get_modifier_lock_state(kIOHIDCapsLockState, on);
+}
+
+int cocoa_get_num_lock_state(bool *on)
+{
+  return cocoa_get_modifier_lock_state(kIOHIDNumLockState, on);
+}