]> source.dussan.org Git - tigervnc.git/commitdiff
Add Windows keyboard handler
authorPierre Ossman <ossman@cendio.se>
Mon, 21 Jul 2014 14:46:22 +0000 (16:46 +0200)
committerPierre Ossman <ossman@cendio.se>
Fri, 22 Aug 2014 13:10:28 +0000 (15:10 +0200)
vncviewer/Viewport.cxx
vncviewer/win32.c
vncviewer/win32.h

index 0f627229b40c17ab31e5ebb58fb8b7de01bfe192..e183939dfbdb02780778924770a26a356410b566 100644 (file)
 #define NoSymbol 0
 #endif
 
+// Missing in at least some versions of MinGW
+#ifndef MAPVK_VK_TO_VSC
+#define MAPVK_VK_TO_VSC 0
+#endif
+
 #include "Viewport.h"
 #include "CConn.h"
 #include "OptionsDialog.h"
@@ -647,7 +652,63 @@ bool Viewport::handleXEvent(void *event, void *data)
 
   assert(event);
 
-#if !defined(WIN32) && !defined(__APPLE__)
+#if defined(WIN32)
+  MSG *msg = (MSG*)event;
+
+  if ((msg->message == WM_KEYDOWN) || (msg->message == WM_SYSKEYDOWN)) {
+    UINT vKey;
+    bool isExtended;
+    int keyCode;
+    rdr::U32 keySym;
+
+    vKey = msg->wParam;
+    isExtended = (msg->lParam & (1 << 24)) != 0;
+
+    keyCode = ((msg->lParam >> 16) & 0xff);
+
+    // Windows sets the scan code to 0x00 for multimedia keys, so we
+    // have to do a reverse lookup based on the vKey.
+    if (keyCode == 0x00) {
+      keyCode = MapVirtualKey(vKey, MAPVK_VK_TO_VSC);
+      if (keyCode == 0x00) {
+        vlog.error(_("No scan code for %svirtual key 0x%02x"),
+                   isExtended?"extended ":"", (int)vKey);
+        return true;
+      }
+    }
+
+    if (isExtended)
+      keyCode |= 0x100;
+
+    keySym = win32_vkey_to_keysym(vKey, isExtended);
+    if (keySym == NoSymbol) {
+      vlog.error(_("No symbol for %svirtual key 0x%02x"),
+                 isExtended?"extended ":"", (int)vKey);
+      return true;
+    }
+
+    self->handleKeyPress(keyCode, keySym);
+
+    return true;
+  } else if ((msg->message == WM_KEYUP) || (msg->message == WM_SYSKEYUP)) {
+    UINT vKey;
+    bool isExtended;
+    int keyCode;
+
+    vKey = msg->wParam;
+    isExtended = (msg->lParam & (1 << 24)) != 0;
+
+    keyCode = ((msg->lParam >> 16) & 0xff);
+    if (keyCode == 0x00)
+      keyCode = MapVirtualKey(vKey, MAPVK_VK_TO_VSC);
+    if (isExtended)
+      keyCode |= 0x100;
+
+    self->handleKeyRelease(keyCode);
+
+    return true;
+  }
+#elif !defined(__APPLE__)
   XEvent *xevent = (XEvent*)event;
 
   if (xevent->type == KeyPress) {
index d75cc578984b5811f6b5530e0caab1f29ef6f87c..cf4dc49a6878c6ef248becb630d402fccdf306a3 100644 (file)
 
 #include <windows.h>
 
+#define XK_MISCELLANY
+#define XK_XKB_KEYS
+#include <rfb/keysymdef.h>
+#include <rfb/XF86keysym.h>
+
+#include "keysym2ucs.h"
+
+#define NoSymbol 0
+
+// Missing in at least some versions of MinGW
+#ifndef MAPVK_VK_TO_CHAR
+#define MAPVK_VK_TO_CHAR 2
+#endif
+
 static HANDLE thread;
 static DWORD thread_id;
 
@@ -113,3 +127,175 @@ void win32_disable_lowlevel_keyboard(HWND hwnd)
   CloseHandle(thread);
   thread = NULL;
 }
+
+static const int vkey_map[][3] = {
+  { VK_BACK,                XK_BackSpace,   NoSymbol },
+  { VK_TAB,                 XK_Tab,         NoSymbol },
+  { VK_CLEAR,               XK_Clear,       NoSymbol },
+  { VK_RETURN,              XK_Return,      XK_KP_Enter },
+  { VK_SHIFT,               XK_Shift_L,     NoSymbol },
+  { VK_CONTROL,             XK_Control_L,   XK_Control_R },
+  { VK_MENU,                XK_Alt_L,       XK_Alt_R },
+  { VK_PAUSE,               XK_Pause,       NoSymbol },
+  { VK_CAPITAL,             XK_Caps_Lock,   NoSymbol },
+  /* FIXME: IME keys */
+  { VK_ESCAPE,              XK_Escape,      NoSymbol },
+  { VK_PRIOR,               XK_KP_Prior,    XK_Prior },
+  { VK_NEXT,                XK_KP_Next,     XK_Next },
+  { VK_END,                 XK_KP_End,      XK_End },
+  { VK_HOME,                XK_KP_Home,     XK_Home },
+  { VK_LEFT,                XK_KP_Left,     XK_Left },
+  { VK_UP,                  XK_KP_Up,       XK_Up },
+  { VK_RIGHT,               XK_KP_Right,    XK_Right },
+  { VK_DOWN,                XK_KP_Down,     XK_Down },
+  { VK_SNAPSHOT,            XK_Print,       NoSymbol },
+  { VK_INSERT,              XK_KP_Insert,   XK_Insert },
+  { VK_DELETE,              XK_KP_Delete,   XK_Delete },
+  { VK_LWIN,                NoSymbol,       XK_Super_L },
+  { VK_RWIN,                NoSymbol,       XK_Super_R },
+  { VK_APPS,                NoSymbol,       XK_Menu },
+  { VK_SLEEP,               NoSymbol,       XF86XK_Sleep },
+  { VK_NUMPAD0,             XK_KP_0,        NoSymbol },
+  { VK_NUMPAD1,             XK_KP_1,        NoSymbol },
+  { VK_NUMPAD2,             XK_KP_2,        NoSymbol },
+  { VK_NUMPAD3,             XK_KP_3,        NoSymbol },
+  { VK_NUMPAD4,             XK_KP_4,        NoSymbol },
+  { VK_NUMPAD5,             XK_KP_5,        NoSymbol },
+  { VK_NUMPAD6,             XK_KP_6,        NoSymbol },
+  { VK_NUMPAD7,             XK_KP_7,        NoSymbol },
+  { VK_NUMPAD8,             XK_KP_8,        NoSymbol },
+  { VK_NUMPAD9,             XK_KP_9,        NoSymbol },
+  { VK_MULTIPLY,            XK_KP_Multiply, NoSymbol },
+  { VK_ADD,                 XK_KP_Add,      NoSymbol },
+  { VK_SUBTRACT,            XK_KP_Subtract, NoSymbol },
+  { VK_DIVIDE,              NoSymbol,       XK_KP_Divide },
+  /* VK_SEPARATOR and VK_DECIMAL left out on purpose. See further down. */
+  { VK_F1,                  XK_F1,          NoSymbol },
+  { VK_F2,                  XK_F2,          NoSymbol },
+  { VK_F3,                  XK_F3,          NoSymbol },
+  { VK_F4,                  XK_F4,          NoSymbol },
+  { VK_F5,                  XK_F5,          NoSymbol },
+  { VK_F6,                  XK_F6,          NoSymbol },
+  { VK_F7,                  XK_F7,          NoSymbol },
+  { VK_F8,                  XK_F8,          NoSymbol },
+  { VK_F9,                  XK_F9,          NoSymbol },
+  { VK_F10,                 XK_F10,         NoSymbol },
+  { VK_F11,                 XK_F11,         NoSymbol },
+  { VK_F12,                 XK_F12,         NoSymbol },
+  { VK_F13,                 XK_F13,         NoSymbol },
+  { VK_F14,                 XK_F14,         NoSymbol },
+  { VK_F15,                 XK_F15,         NoSymbol },
+  { VK_F16,                 XK_F16,         NoSymbol },
+  { VK_F17,                 XK_F17,         NoSymbol },
+  { VK_F18,                 XK_F18,         NoSymbol },
+  { VK_F19,                 XK_F19,         NoSymbol },
+  { VK_F20,                 XK_F20,         NoSymbol },
+  { VK_F21,                 XK_F21,         NoSymbol },
+  { VK_F22,                 XK_F22,         NoSymbol },
+  { VK_F23,                 XK_F23,         NoSymbol },
+  { VK_F24,                 XK_F24,         NoSymbol },
+  { VK_NUMLOCK,             NoSymbol,       XK_Num_Lock },
+  { VK_SCROLL,              XK_Scroll_Lock, NoSymbol },
+  { VK_BROWSER_BACK,        NoSymbol,       XF86XK_Back },
+  { VK_BROWSER_FORWARD,     NoSymbol,       XF86XK_Forward },
+  { VK_BROWSER_REFRESH,     NoSymbol,       XF86XK_Refresh },
+  { VK_BROWSER_STOP,        NoSymbol,       XF86XK_Stop },
+  { VK_BROWSER_SEARCH,      NoSymbol,       XF86XK_Search },
+  { VK_BROWSER_FAVORITES,   NoSymbol,       XF86XK_Favorites },
+  { VK_BROWSER_HOME,        NoSymbol,       XF86XK_HomePage },
+  { VK_VOLUME_MUTE,         NoSymbol,       XF86XK_AudioMute },
+  { VK_VOLUME_DOWN,         NoSymbol,       XF86XK_AudioLowerVolume },
+  { VK_VOLUME_UP,           NoSymbol,       XF86XK_AudioRaiseVolume },
+  { VK_MEDIA_NEXT_TRACK,    NoSymbol,       XF86XK_AudioNext },
+  { VK_MEDIA_PREV_TRACK,    NoSymbol,       XF86XK_AudioPrev },
+  { VK_MEDIA_STOP,          NoSymbol,       XF86XK_AudioStop },
+  { VK_MEDIA_PLAY_PAUSE,    NoSymbol,       XF86XK_AudioPlay },
+  { VK_LAUNCH_MAIL,         NoSymbol,       XF86XK_Mail },
+  { VK_LAUNCH_APP2,         NoSymbol,       XF86XK_Calculator },
+};
+
+int win32_vkey_to_keysym(UINT vkey, int extended)
+{
+  int i;
+
+  BYTE state[256];
+  int ret;
+  WCHAR wstr[10];
+
+  // Start with keys that either don't generate a symbol, or
+  // generate the same symbol as some other key.
+  for (i = 0;i < sizeof(vkey_map)/sizeof(vkey_map[0]);i++) {
+    if (vkey == vkey_map[i][0]) {
+      if (extended)
+        return vkey_map[i][2];
+      else
+        return vkey_map[i][1];
+    }
+  }
+
+  // Windows is not consistent in which virtual key it uses for
+  // the numpad decimal key, and this is not likely to be fixed:
+  // http://blogs.msdn.com/michkap/archive/2006/09/13/752377.aspx
+  //
+  // To get X11 behaviour, we instead look at the text generated
+  // by they key.
+  if ((vkey == VK_DECIMAL) || (vkey == VK_SEPARATOR)) {
+    UINT ch;
+
+    ch = MapVirtualKey(vkey, MAPVK_VK_TO_CHAR);
+    switch (ch) {
+    case ',':
+      return XK_KP_Separator;
+    case '.':
+      return XK_KP_Decimal;
+    default:
+      return NoSymbol;
+    }
+  }
+
+  // MapVirtualKey() doesn't look at modifiers, so it is
+  // insufficient for mapping most keys to a symbol. ToUnicode()
+  // does what we want though. Unfortunately it keeps state, so
+  // we have to be careful around dead characters.
+
+  GetKeyboardState(state);
+
+  // Pressing Ctrl wreaks havoc with the symbol lookup, so turn
+  // that off. But AltGr shows up as Ctrl+Alt in Windows, so keep
+  // Ctrl if Alt is active.
+  if (!(state[VK_LCONTROL] & 0x80) || !(state[VK_RMENU] & 0x80))
+    state[VK_CONTROL] = state[VK_LCONTROL] = state[VK_RCONTROL] = 0;
+
+  // FIXME: Multi character results, like U+0644 U+0627
+  //        on Arabic layout
+  ret = ToUnicode(vkey, 0, state, wstr, sizeof(wstr)/sizeof(wstr[0]), 0);
+
+  if (ret == 0) {
+    // Most Ctrl+Alt combinations will fail to produce a symbol, so
+    // try it again with Ctrl unconditionally disabled.
+    state[VK_CONTROL] = state[VK_LCONTROL] = state[VK_RCONTROL] = 0;
+    ret = ToUnicode(vkey, 0, state, wstr, sizeof(wstr)/sizeof(wstr[0]), 0);
+  }
+
+  if (ret == 1)
+    return ucs2keysym(wstr[0]);
+
+  if (ret == -1) {
+    WCHAR dead_char;
+
+    dead_char = wstr[0];
+
+    // Need to clear out the state that the dead key has caused.
+    // This is the recommended method by Microsoft's engineers:
+    // http://blogs.msdn.com/b/michkap/archive/2007/10/27/5717859.aspx
+    do {
+      ret = ToUnicode(vkey, 0, state, wstr, sizeof(wstr)/sizeof(wstr[0]), 0);
+    } while (ret < 0);
+
+    // Dead keys are represented by their spacing equivalent
+    // (or something similar depending on the layout)
+    return ucs2keysym(ucs2combining(dead_char));
+  }
+
+  return NoSymbol;
+}
index 35be77b5d18dddfd1f53fdd057722644212ac6e6..014870859f9e9a4225a7027ea8904813fe9cd99a 100644 (file)
@@ -30,6 +30,8 @@ extern "C" {
 int win32_enable_lowlevel_keyboard(HWND hwnd);
 void win32_disable_lowlevel_keyboard(HWND hwnd);
 
+int win32_vkey_to_keysym(UINT vkey, int extended);
+
 };
 
 #endif