Added new option, SendSysKeys, which controls if Alt-Tab, Alt-F4 and Alt-Space should be handled locally, or sent to the server


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@127 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/vncviewer/CViewOptions.cxx b/vncviewer/CViewOptions.cxx
index 13ad7cd..39a1a5c 100644
--- a/vncviewer/CViewOptions.cxx
+++ b/vncviewer/CViewOptions.cxx
@@ -66,6 +66,8 @@
                          "Send pointer (mouse) events to the server.", true);
 static BoolParameter sendKeyEvents("SendKeyEvents",
                          "Send key presses (and releases) to the server.", true);
+static BoolParameter sendSysKeys("SendSysKeys",
+                         "Send system keys (Alt combinations) to the server.", true);
 
 static BoolParameter clientCutText("ClientCutText",
                          "Send clipboard changes to the server.", true);
@@ -110,7 +112,7 @@
 CViewOptions::CViewOptions()
 : useLocalCursor(::useLocalCursor), useDesktopResize(::useDesktopResize),
 autoSelect(::autoSelect), fullColour(::fullColour), fullScreen(::fullScreen),
-shared(::sharedConnection), sendPtrEvents(::sendPtrEvents), sendKeyEvents(::sendKeyEvents),
+shared(::sharedConnection), sendPtrEvents(::sendPtrEvents), sendKeyEvents(::sendKeyEvents), sendSysKeys(::sendSysKeys),
 preferredEncoding(encodingZRLE), clientCutText(::clientCutText), serverCutText(::serverCutText),
 protocol3_3(::protocol3_3), acceptBell(::acceptBell), lowColourLevel(::lowColourLevel),
 pointerEventInterval(ptrEventInterval), emulate3(::emulate3), monitor(::monitor.getData()),
@@ -214,6 +216,8 @@
             sendPtrEvents = atoi(value.buf);
           } else if (stricmp(name.buf, "SendKeyEvents") == 0) {
             sendKeyEvents = atoi(value.buf);
+          } else if (stricmp(name.buf, "SendSysKeys") == 0) {
+            sendSysKeys = atoi(value.buf);
           } else if (stricmp(name.buf, "SendCutText") == 0) {
             clientCutText = atoi(value.buf);
           } else if (stricmp(name.buf, "AcceptCutText") == 0) {
@@ -310,6 +314,7 @@
     fprintf(f, "Shared=%d\n", (int)shared);
     fprintf(f, "SendPtrEvents=%d\n", (int)sendPtrEvents);
     fprintf(f, "SendKeyEvents=%d\n", (int)sendKeyEvents);
+    fprintf(f, "SendSysKeys=%d\n", (int)sendSysKeys);
     fprintf(f, "SendCutText=%d\n", (int)clientCutText);
     fprintf(f, "AcceptCutText=%d\n", (int)serverCutText);
     fprintf(f, "Emulate3=%d\n", (int)emulate3);
@@ -344,6 +349,7 @@
   key.setBool(_T("Shared"), shared);
   key.setBool(_T("SendPointerEvents"), sendPtrEvents);
   key.setBool(_T("SendKeyEvents"), sendKeyEvents);
+  key.setBool(_T("SendSysKeys"), sendSysKeys);
   key.setBool(_T("ClientCutText"), clientCutText);
   key.setBool(_T("ServerCutText"), serverCutText);
   key.setBool(_T("Protocol3.3"), protocol3_3);
@@ -399,6 +405,7 @@
   shared = o.shared;
   sendPtrEvents = o.sendPtrEvents;
   sendKeyEvents = o.sendKeyEvents;
+  sendSysKeys = o.sendSysKeys;
   clientCutText = o.clientCutText;
   serverCutText = o.serverCutText;
   emulate3 = o.emulate3;
diff --git a/vncviewer/CViewOptions.h b/vncviewer/CViewOptions.h
index d49cab1..b19c750 100644
--- a/vncviewer/CViewOptions.h
+++ b/vncviewer/CViewOptions.h
@@ -58,6 +58,7 @@
       bool shared;
       bool sendPtrEvents;
       bool sendKeyEvents;
+      bool sendSysKeys;
       bool clientCutText;
       bool serverCutText;
       bool emulate3;
diff --git a/vncviewer/OptionsDialog.cxx b/vncviewer/OptionsDialog.cxx
index 954631f..8655dc7 100644
--- a/vncviewer/OptionsDialog.cxx
+++ b/vncviewer/OptionsDialog.cxx
@@ -188,6 +188,7 @@
   virtual void initDialog() {
     setItemChecked(IDC_SEND_POINTER, dlg->options.sendPtrEvents);
     setItemChecked(IDC_SEND_KEYS, dlg->options.sendKeyEvents);
+    setItemChecked(IDC_SEND_SYSKEYS, dlg->options.sendSysKeys);
     setItemChecked(IDC_CLIENT_CUTTEXT, dlg->options.clientCutText);
     setItemChecked(IDC_SERVER_CUTTEXT, dlg->options.serverCutText);
     setItemChecked(IDC_EMULATE3, dlg->options.emulate3);
@@ -210,6 +211,7 @@
   virtual bool onOk() {
     dlg->options.sendPtrEvents = isItemChecked(IDC_SEND_POINTER);
     dlg->options.sendKeyEvents = isItemChecked(IDC_SEND_KEYS);
+    dlg->options.sendSysKeys = isItemChecked(IDC_SEND_SYSKEYS);
     dlg->options.clientCutText = isItemChecked(IDC_CLIENT_CUTTEXT);
     dlg->options.serverCutText = isItemChecked(IDC_SERVER_CUTTEXT);
     dlg->options.emulate3 = isItemChecked(IDC_EMULATE3);
diff --git a/vncviewer/cview.cxx b/vncviewer/cview.cxx
index 1765493..180119a 100644
--- a/vncviewer/cview.cxx
+++ b/vncviewer/cview.cxx
@@ -63,6 +63,8 @@
 const int TIMER_POINTER_INTERVAL = 2;
 const int TIMER_POINTER_3BUTTON = 3;
 
+const int HOTKEY_ALTTAB = 0;
+
 
 IntParameter debugDelay("DebugDelay","Milliseconds to display inverted "
                         "pixel data - a debugging feature", 0);
@@ -174,6 +176,9 @@
   bumpScrollTimer.setHWND(getHandle());
   bumpScrollTimer.setId(TIMER_BUMPSCROLL);
 
+  // Grab AltTab
+  setAltTabGrab(options.sendSysKeys);
+
   // Hook the clipboard
   clipboard.setNotifier(this);
 
@@ -290,6 +295,8 @@
   // - Inputs
   options.sendPtrEvents = opt.sendPtrEvents;
   options.sendKeyEvents = opt.sendKeyEvents;
+  options.sendSysKeys = opt.sendSysKeys;
+  setAltTabGrab(options.sendSysKeys);
   options.clientCutText = opt.clientCutText;
   options.serverCutText = opt.serverCutText;
   options.emulate3 = opt.emulate3;
@@ -692,10 +699,14 @@
 
   case WM_SETFOCUS:
     has_focus = true;
+    // Re-register AltTab hotkey
+    setAltTabGrab(options.sendSysKeys);
     break;
   case WM_KILLFOCUS:
     has_focus = false;
     cursorOutsideBuffer();
+    // Unregister AltTab hotkey
+    setAltTabGrab(false);
     // Restore the remote keys to consistent states
     try {
       kbd.releaseAllKeys(writer());
@@ -795,6 +806,35 @@
 
     // -=- Handle keyboard input
 
+  case WM_HOTKEY:
+    if (wParam == HOTKEY_ALTTAB) {
+      writeKeyEvent(VK_TAB, 0, true);
+      writeKeyEvent(VK_TAB, 0, false);
+      return 0;
+    }
+    break;
+
+  case WM_SYSKEYDOWN:
+    // Translate Alt-Space and Alt-F4 to WM_SYSCHAR and WM_CLOSE,
+    // since we are not using TranslateMessage(). 
+    if (!options.sendSysKeys) {
+      switch (wParam) {
+      case VK_SPACE:
+	writeKeyEvent(VK_MENU, 0, false);
+	SendMessage(getHandle(), WM_SYSCHAR, wParam, lParam);
+	return 0; 
+      case VK_F4:
+	SendMessage(getHandle(), WM_CLOSE, wParam, lParam);
+	return 0; 
+      }
+    }
+
+  case WM_SYSKEYUP:
+    // When we have registered for AltTab as a hotkey, SYSKEYUPs for
+    // Tabs are sent (but no SYSKEYDOWNs). AltTab is handled by
+    // WM_HOTKEY, though.
+    if (wParam == VK_TAB) return 0; 
+
   case WM_KEYUP:
   case WM_KEYDOWN:
     // Hook the MenuKey to pop-up the window menu
@@ -818,12 +858,11 @@
             TPM_CENTERALIGN | TPM_VCENTERALIGN, pt.x, pt.y, 0, getHandle(), 0);
         }
 
-        // Ignore the MenuKey keypress for both press & release events
-        return 0;
+	// Ignore the MenuKey keypress for both press & release events
+	return 0;
       }
     }
-	case WM_SYSKEYDOWN:
-	case WM_SYSKEYUP:
+
     writeKeyEvent(wParam, lParam, (msg == WM_KEYDOWN) || (msg == WM_SYSKEYDOWN));
     return 0;
 
@@ -949,6 +988,26 @@
   }
 }
 
+void
+CView::setAltTabGrab(bool grab) {
+  BOOL hotKeyResult;
+  static bool grabstate = false;
+
+  // Do not call RegisterHotKey/UnregisterHotKey if not necessary
+  if (grabstate == grab)
+    return;
+
+  grabstate = grab;
+    
+  // Only works for NT/2k/XP
+  if (grab) {
+    hotKeyResult = RegisterHotKey(hwnd, HOTKEY_ALTTAB, MOD_ALT, VK_TAB);
+    if (!hotKeyResult)
+      vlog.debug("RegisterHotkey failed with error %d", GetLastError());
+  } else {
+    hotKeyResult = UnregisterHotKey(hwnd, HOTKEY_ALTTAB);
+  }
+}
 
 bool
 CView::invalidateBufferRect(const Rect& crect) {
diff --git a/vncviewer/cview.h b/vncviewer/cview.h
index 2bee1c4..ca97cdc 100644
--- a/vncviewer/cview.h
+++ b/vncviewer/cview.h
@@ -183,6 +183,9 @@
       void hideSystemCursor();
       void showSystemCursor();
 
+      // Grab AltTab?
+      void setAltTabGrab(bool grab);
+
       // cursorOutsideBuffer() is called whenever we detect that the mouse has
       // moved outside the desktop.  It restores the system arrow cursor.
       void cursorOutsideBuffer();
diff --git a/vncviewer/resource.h b/vncviewer/resource.h
index 3a08e57..0dde195 100644
--- a/vncviewer/resource.h
+++ b/vncviewer/resource.h
@@ -68,6 +68,7 @@
 #define IDC_COMPRESSLEVEL               1056
 #define IDC_ALLOW_JPEG                  1057
 #define IDC_QUALITYLEVEL                1058
+#define IDC_SEND_SYSKEYS                1059
 #define ID_CLOSE                        40002
 #define ID_OPTIONS                      40003
 #define ID_NEW_CONNECTION               40004
diff --git a/vncviewer/vncviewer.rc b/vncviewer/vncviewer.rc
index ad25574..3545bc2 100644
--- a/vncviewer/vncviewer.rc
+++ b/vncviewer/vncviewer.rc
@@ -232,17 +232,19 @@
                     BS_AUTOCHECKBOX | WS_TABSTOP,7,10,172,15
     CONTROL         "Send keyboard events to server",IDC_SEND_KEYS,"Button",
                     BS_AUTOCHECKBOX | WS_TABSTOP,7,25,172,15
-    CONTROL         "Send clipboard changes to server",IDC_CLIENT_CUTTEXT,
+    CONTROL         "Send system keys (Alt combinations) to server",IDC_SEND_SYSKEYS,
                     "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,40,172,15
+    CONTROL         "Send clipboard changes to server",IDC_CLIENT_CUTTEXT,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,55,172,15
     CONTROL         "Accept clipboard changes from server",
                     IDC_SERVER_CUTTEXT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
-                    7,55,172,15
+                    7,70,172,15
     CONTROL         "Enable 3-button mouse emulation",IDC_EMULATE3,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,7,70,172,15
+                    BS_AUTOCHECKBOX | WS_TABSTOP,7,85,172,15
     CONTROL         "Rate-limit mouse move events",IDC_POINTER_INTERVAL,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,86,172,14
-    LTEXT           "Menu key",IDC_STATIC,7,100,98,15,SS_CENTERIMAGE
-    COMBOBOX        IDC_MENU_KEY,105,100,74,105,CBS_DROPDOWNLIST | CBS_SORT | 
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,100,172,14
+    LTEXT           "Menu key",IDC_STATIC,7,115,98,15,SS_CENTERIMAGE
+    COMBOBOX        IDC_MENU_KEY,105,115,74,105,CBS_DROPDOWNLIST | CBS_SORT | 
                     WS_VSCROLL | WS_TABSTOP
 END