mirror of
https://github.com/apache/cloudstack.git
synced 2025-12-21 04:53:37 +01:00
276 lines
13 KiB
C++
276 lines
13 KiB
C++
// TODO: add Copyright?
|
|
//
|
|
// The VNC system is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
// USA.
|
|
//
|
|
// If the source code for the VNC system is not available from the place
|
|
// whence you received this file, check http://www.uk.research.att.com/vnc or contact
|
|
// the authors on vnc@uk.research.att.com for information on obtaining it.
|
|
|
|
// This is the source for the low-level keyboard hook, which allows intercepting and sending
|
|
// special keys (such as ALT,CTRL, ALT+TAB, etc) to the VNCServer side.
|
|
// written by Assaf Gordon (Assaf@mazleg.com), 10/9/2003
|
|
|
|
#define WINVER 0x0400
|
|
#define _WIN32_WINNT 0x0400
|
|
#include "LowLevelHook.h"
|
|
#include "res/resource.h"
|
|
|
|
HWND LowLevelHook::g_hwndVNCViewer=NULL;
|
|
DWORD LowLevelHook::g_VncProcessID=0;
|
|
BOOL LowLevelHook::g_fHookActive=FALSE;
|
|
HHOOK LowLevelHook::g_HookID=0;
|
|
BOOL LowLevelHook::g_fGlobalScrollLock=FALSE;
|
|
|
|
BOOL LowLevelHook::Initialize(HWND hwndMain)
|
|
{
|
|
HINSTANCE hInstance = NULL ;
|
|
|
|
g_hwndVNCViewer = NULL ;
|
|
g_fHookActive = GetScrollLockState() ;
|
|
g_VncProcessID = 0 ;
|
|
g_HookID = 0 ;
|
|
g_fGlobalScrollLock = FALSE ;
|
|
|
|
//Store our window's handle
|
|
g_hwndVNCViewer = hwndMain;
|
|
if (g_hwndVNCViewer==NULL)
|
|
return FALSE;
|
|
|
|
|
|
//Get the HInstacne of this window
|
|
//(required because LowLevel-Keyboard-Hook must be global,
|
|
// and need the HMODULE parameter in SetWindowsHookEx)
|
|
hInstance = (HINSTANCE)GetWindowLong(g_hwndVNCViewer,GWL_HINSTANCE);
|
|
if (hInstance==NULL)
|
|
return FALSE;
|
|
|
|
//
|
|
//Store the ProcessID of the VNC window.
|
|
//this will prevent the keyboard hook procedure to interfere
|
|
//with keypressed in other processes' windows
|
|
GetWindowThreadProcessId(g_hwndVNCViewer,&g_VncProcessID);
|
|
|
|
//Try to set the hook procedure
|
|
g_HookID = SetWindowsHookEx(WH_KEYBOARD_LL,VncLowLevelKbHookProc,hInstance,0);
|
|
if (g_HookID==0) {
|
|
|
|
DWORD dw = GetLastError();
|
|
|
|
//TODO:
|
|
//Analyze why the error occured (might be because we're under Win98/95/ME?)
|
|
return FALSE ;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL LowLevelHook::Release()
|
|
{
|
|
if (g_HookID!=0) {
|
|
return UnhookWindowsHookEx(g_HookID);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL LowLevelHook::GetScrollLockState()
|
|
{
|
|
BYTE keyState[256];
|
|
GetKeyboardState((LPBYTE)&keyState);
|
|
return (keyState[VK_SCROLL] & 1);
|
|
}
|
|
|
|
|
|
#include "Log.h"
|
|
#include <tchar.h>
|
|
extern Log vnclog;
|
|
|
|
LRESULT CALLBACK LowLevelHook::VncLowLevelKbHookProc(INT nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
vnclog.Print(1, _T("Begin LowLevelHook::VncLowLevelKbHookProc\n"));
|
|
|
|
//if set to TRUE, the key-pressed message will NOT be passed on to windows.
|
|
BOOL fHandled = FALSE;
|
|
|
|
BOOL fKeyDown = FALSE;
|
|
|
|
if (nCode == HC_ACTION) {
|
|
KBDLLHOOKSTRUCT *pkbdllhook = (KBDLLHOOKSTRUCT *)lParam;
|
|
|
|
DWORD ProcessID ;
|
|
|
|
//Get the process ID of the Active Window
|
|
//(The window with the input focus)
|
|
GetWindowThreadProcessId(GetFocus(),&ProcessID);
|
|
|
|
//only if this is "our" process (vncviewer's process)
|
|
//we should intecept the key-presses
|
|
if (ProcessID==g_VncProcessID) {
|
|
|
|
fKeyDown = ( (wParam==WM_KEYDOWN) || (wParam==WM_SYSKEYDOWN) );
|
|
|
|
switch (pkbdllhook->vkCode)
|
|
{
|
|
//Print Screen Key
|
|
// Request Full screen Update
|
|
// Simulate a "Request Refresh" from the System Menu
|
|
case VK_SNAPSHOT:
|
|
if (fKeyDown && g_fHookActive) {
|
|
PostMessage(g_hwndVNCViewer,WM_SYSCOMMAND,ID_REQUEST_REFRESH,0);
|
|
fHandled = TRUE;
|
|
}
|
|
break ;
|
|
|
|
//Pause Key
|
|
// Toggle FullScreen On/Off
|
|
// Simulate a "FullScreen" from the System Menu
|
|
case VK_PAUSE:
|
|
if (fKeyDown && g_fHookActive) {
|
|
PostMessage(g_hwndVNCViewer,WM_SYSCOMMAND,ID_FULLSCREEN,0);
|
|
fHandled = TRUE;
|
|
}
|
|
break ;
|
|
|
|
|
|
//Left or Right CONTROL keys
|
|
// Simulate a "Send CONTROL up/down" from the System Menu
|
|
case VK_LCONTROL:
|
|
case VK_RCONTROL:
|
|
if (g_fHookActive) {
|
|
if(fKeyDown)
|
|
PostMessage(g_hwndVNCViewer,WM_SYSCOMMAND,ID_CONN_CTLDOWN,0);
|
|
else
|
|
PostMessage(g_hwndVNCViewer,WM_SYSCOMMAND,ID_CONN_CTLUP,0);
|
|
fHandled = TRUE;
|
|
}
|
|
break;
|
|
|
|
//Either Left or Right ALT keys
|
|
// Simulate a "Send ALT up/down" from the System Menu
|
|
case VK_LMENU:
|
|
case VK_RMENU:
|
|
if (g_fHookActive) {
|
|
if(fKeyDown)
|
|
PostMessage(g_hwndVNCViewer,WM_SYSCOMMAND,ID_CONN_ALTDOWN,0);
|
|
else
|
|
PostMessage(g_hwndVNCViewer,WM_SYSCOMMAND,ID_CONN_ALTUP,0);
|
|
fHandled = TRUE;
|
|
}
|
|
break;
|
|
case VK_LWIN:
|
|
if (g_fHookActive) {
|
|
if(fKeyDown)
|
|
PostMessage(g_hwndVNCViewer,WM_SYSCOMMAND,ID_VK_LWINDOWN,0);
|
|
else
|
|
PostMessage(g_hwndVNCViewer,WM_SYSCOMMAND,ID_VK_LWINUP,0);
|
|
fHandled = TRUE;
|
|
}
|
|
break;
|
|
case VK_RWIN:
|
|
if (g_fHookActive) {
|
|
if(fKeyDown)
|
|
PostMessage(g_hwndVNCViewer,WM_SYSCOMMAND,ID_VK_RWINDOWN,0);
|
|
else
|
|
PostMessage(g_hwndVNCViewer,WM_SYSCOMMAND,ID_VK_RWINUP,0);
|
|
fHandled = TRUE;
|
|
}
|
|
break;
|
|
case VK_APPS:
|
|
if (g_fHookActive) {
|
|
if(fKeyDown)
|
|
PostMessage(g_hwndVNCViewer,WM_SYSCOMMAND,ID_VK_APPSDOWN,0);
|
|
else
|
|
PostMessage(g_hwndVNCViewer,WM_SYSCOMMAND,ID_VK_APPSUP,0);
|
|
fHandled = TRUE;
|
|
}
|
|
break;
|
|
|
|
|
|
|
|
|
|
//Scroll Lock = Turn the whole thing on or off
|
|
//This is a little tricky hack:
|
|
//Windows sets the scroll-lock LED on or off when the user PRESSes the scroll-lock key.
|
|
//We'll check the LED state when the user RELEASEs the key, so the LED is already set.
|
|
//If the LED/ScrollLock is ON, we'll activate the special key interception.
|
|
case VK_SCROLL:
|
|
if (!fKeyDown) {
|
|
g_fHookActive = GetScrollLockState();
|
|
}
|
|
break;
|
|
|
|
|
|
//SPACEBAR = When key interception is Active, no special handling is required for 'spacebar'.
|
|
//But when key interception is turned off, I want ALT+SPACE to open the VNCViewer's System Menu.
|
|
case VK_SPACE:
|
|
if (!g_fHookActive) {
|
|
if (pkbdllhook->flags & LLKHF_ALTDOWN) {
|
|
if(!fKeyDown)
|
|
PostMessage(g_hwndVNCViewer,WM_SYSCOMMAND,0xF100,0x20);
|
|
|
|
fHandled = TRUE;
|
|
}
|
|
}
|
|
break ;
|
|
|
|
|
|
|
|
//TAB = If the user presses ALT+TAB, we must block the TAB key (fHandled=TRUE),
|
|
//Otherwise windows (on the VNCViewer's side) will switch to another application.
|
|
//But because we block the TAB key, the 'ClientConnection' window won't know to send
|
|
//a TAB key to the VNCServer. so we simulate a TAB key pressed.
|
|
//(The ALT key down was already sent to the VNCServer when the user pressed ALT)
|
|
case VK_TAB:
|
|
if (g_fHookActive) {
|
|
if (pkbdllhook->flags & LLKHF_ALTDOWN) {
|
|
if(fKeyDown)
|
|
PostMessage(g_hwndVNCViewer,WM_KEYDOWN,VK_TAB,0);
|
|
|
|
/* Implementation Note:
|
|
Don't send the Key-UP event, it confuses Windows on the server side.
|
|
(It makes Windows switch TWO applications at a time).
|
|
|
|
This way it works OK on servers running Win98, Win2K, WinXP and Linux+IceWM.
|
|
Should test it with more servers to make sure it's OK.
|
|
*/
|
|
fHandled = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
//ESCAPE = ALT+ESC is also a way to switch application, so we block the ESCAPE key,
|
|
//Otherwise windows (on the VNCViewer's side) will switch to another application.
|
|
//Transmitting the ALT+ESCAPE combination to a VNCServer running Windows doesn't work
|
|
//very well, so for now, we'll just block the ALT+ESCAPE combination.
|
|
//(CTRL+ESC work OK, BTW)
|
|
case VK_ESCAPE:
|
|
if (g_fHookActive) {
|
|
if (pkbdllhook->flags & LLKHF_ALTDOWN) {
|
|
fHandled = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
} //switch(pkbdllhook->vkCode)
|
|
|
|
} // if (ProcessID == g_VncProcesID)
|
|
|
|
} // if (nCode==HT_ACTION)
|
|
|
|
//Call the next hook, if we didn't handle this message
|
|
vnclog.Print(1, _T("End LowLevelHook::VncLowLevelKbHookProc\n"));
|
|
return (fHandled ? TRUE : CallNextHookEx(g_HookID, nCode, wParam, lParam));
|
|
} |