]> source.dussan.org Git - tigervnc.git/commitdiff
Handle Ctrl+AltGr on Windows
authorPierre Ossman <ossman@cendio.se>
Thu, 8 Mar 2018 16:24:54 +0000 (17:24 +0100)
committerPierre Ossman <ossman@cendio.se>
Thu, 8 Mar 2018 16:24:54 +0000 (17:24 +0100)
Improve AltGr detection even further on Windows so we can detect the
case when Ctrl and AltGr are pressed together.

doc/keyboard-test.txt
vncviewer/Viewport.cxx
vncviewer/win32.c
vncviewer/win32.h

index 6375a9e5bb0a9e835b31bf557978040c65b2624f..d66e85337048bb6b85c1d0f008ea615075778d84 100644 (file)
@@ -66,7 +66,8 @@ Client (classic, non-raw, mode)
 
   - CapsLock, NumLock
   - Shift, Ctrl
-  - Alt, AltGr, Super [Win, X11] (FIXME: Ctrl+AltGr broken on Win)
+  - Alt, AltGr, Super [Win, X11]
+  - Ctrl+AltGr [Win]
   - Meta [X11]
   - Left/right identification (FIXME: broken for Shift on Win)
   - CmdL => AltL, CmdR => SuperL, AltL => ModeSwitch, AltR => Level3Shift [OS X]
@@ -75,7 +76,6 @@ Client (classic, non-raw, mode)
   - CapsLock, Shift and AltGr affect symbol lookup
   - Ctrl does not affect symbol lookup
   - Ctrl+Alt+<ANY> sends the same symbol as <ANY>
-  - Ctrl+AltGr+<ANY> sends the same symbol as AltGr+<ANY> (FIXME: broken on Win)
   - "Shift press, A press, Shift release, A release" should not send "a release"
 
 - Numpad:
index ba0b0e9346ad8fd1ceaae0e7519bda35f1e398ef..1c0503c529f559d85484dcbdd9f8ded4a7002adf 100644 (file)
@@ -838,24 +838,18 @@ int Viewport::handleSystemEvent(void *event, void *data)
     // Ctrl+Alt. However the remote end might not be Windows, so we need
     // to merge those in to a single AltGr event. We detect this case
     // by seeing the two key events directly after each other with a very
-    // short time between them (<50ms).
+    // short time between them (<50ms) and supress the Ctrl event.
     if (self->altGrArmed) {
       self->altGrArmed = false;
       Fl::remove_timeout(handleAltGrTimeout);
 
       if (isExtended && (keyCode == 0x38) && (vKey == VK_MENU) &&
           ((msg->time - self->altGrCtrlTime) < 50)) {
-        // FIXME: We fail to detect this if either Ctrl key is
-        //        first manually pressed as Windows then no longer
-        //        sends the fake Ctrl down event. It does however
-        //        happily send real Ctrl events even when AltGr
-        //        is already down.
-        vlog.debug("Detected AltGr combination");
-        self->handleKeyPress(0xb8, XK_ISO_Level3_Shift);
-        return 1;
+        // Alt seen, so this is an AltGr sequence
+      } else {
+        // Not Alt, so fire the queued up Ctrl event
+        self->handleKeyPress(0x1d, XK_Control_L);
       }
-
-      self->handleKeyPress(0x1d, XK_Control_L);
     }
 
     if (keyCode == SCAN_FAKE) {
@@ -917,12 +911,18 @@ int Viewport::handleSystemEvent(void *event, void *data)
     if ((keySym == XK_Shift_L) && (keyCode == 0x36))
       keySym = XK_Shift_R;
 
-    // Possible start of AltGr sequence? (see above)
-    if ((keyCode == 0x1d) && (keySym == XK_Control_L)) {
-      self->altGrArmed = true;
-      self->altGrCtrlTime = msg->time;
-      Fl::add_timeout(0.1, handleAltGrTimeout, self);
-      return 1;
+    // AltGr handling (see above)
+    if (win32_has_altgr()) {
+      if ((keyCode == 0xb8) && (keySym == XK_Alt_R))
+        keySym = XK_ISO_Level3_Shift;
+
+      // Possible start of AltGr sequence?
+      if ((keyCode == 0x1d) && (keySym == XK_Control_L)) {
+        self->altGrArmed = true;
+        self->altGrCtrlTime = msg->time;
+        Fl::add_timeout(0.1, handleAltGrTimeout, self);
+        return 1;
+      }
     }
 
     self->handleKeyPress(keyCode, keySym);
index 30c87f18cf0f661a3cc94dde38e5d7129b1c10a8..537ff43574990741356543a6f02335886c611287 100644 (file)
@@ -33,6 +33,9 @@
 #define MAPVK_VK_TO_CHAR 2
 #endif
 
+int has_altgr;
+HKL current_layout = 0;
+
 static HANDLE thread;
 static DWORD thread_id;
 
@@ -300,3 +303,58 @@ int win32_vkey_to_keysym(UINT vkey, int extended)
 
   return NoSymbol;
 }
+
+int win32_has_altgr(void)
+{
+  BYTE orig_state[256];
+  BYTE altgr_state[256];
+
+  if (current_layout == GetKeyboardLayout(0))
+    return has_altgr;
+
+  // Save current keyboard state so we can get things sane again after
+  // we're done
+  if (!GetKeyboardState(orig_state))
+    return 0;
+
+  // We press Ctrl+Alt (Windows fake AltGr) and then test every key
+  // to see if it produces a printable character. If so then we assume
+  // AltGr is used in the current layout.
+
+  has_altgr = 0;
+
+  memset(altgr_state, 0, sizeof(altgr_state));
+  altgr_state[VK_CONTROL] = 0x80;
+  altgr_state[VK_MENU] = 0x80;
+
+  for (UINT vkey = 0;vkey <= 0xff;vkey++) {
+    int ret;
+    WCHAR wstr[10];
+
+    // Need to skip this one as it is a bit magical and will trigger
+    // a false positive
+    if (vkey == VK_PACKET)
+      continue;
+
+    ret = ToUnicode(vkey, 0, altgr_state, wstr,
+                    sizeof(wstr)/sizeof(wstr[0]), 0);
+    if (ret == 1) {
+      has_altgr = 1;
+      break;
+    }
+
+    if (ret == -1) {
+      // Dead key, need to clear out state before we proceed
+      do {
+        ret = ToUnicode(vkey, 0, altgr_state, wstr,
+                        sizeof(wstr)/sizeof(wstr[0]), 0);
+      } while (ret < 0);
+    }
+  }
+
+  SetKeyboardState(orig_state);
+
+  current_layout = GetKeyboardLayout(0);
+
+  return has_altgr;
+}
index 014870859f9e9a4225a7027ea8904813fe9cd99a..9d4704bcf8f310a1a91449e1eef182738ebbbaa8 100644 (file)
@@ -32,6 +32,8 @@ void win32_disable_lowlevel_keyboard(HWND hwnd);
 
 int win32_vkey_to_keysym(UINT vkey, int extended);
 
+int win32_has_altgr(void);
+
 };
 
 #endif