diff options
author | Constantin Kaplinsky <const@tightvnc.com> | 2006-05-25 05:12:25 +0000 |
---|---|---|
committer | Constantin Kaplinsky <const@tightvnc.com> | 2006-05-25 05:12:25 +0000 |
commit | 729598cb00d791bbdfe23ebe0023d3a1c3962f83 (patch) | |
tree | ffe1b87705a0541998b8d7c44ea75dc4702dc515 /win/wm_hooks/wm_hooks.cxx | |
parent | b30ae7facbdf8273f34f5d67d3d2e9c81db75576 (diff) | |
download | tigervnc-729598cb00d791bbdfe23ebe0023d3a1c3962f83.tar.gz tigervnc-729598cb00d791bbdfe23ebe0023d3a1c3962f83.zip |
Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@591 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'win/wm_hooks/wm_hooks.cxx')
-rw-r--r-- | win/wm_hooks/wm_hooks.cxx | 465 |
1 files changed, 465 insertions, 0 deletions
diff --git a/win/wm_hooks/wm_hooks.cxx b/win/wm_hooks/wm_hooks.cxx new file mode 100644 index 00000000..fd01159c --- /dev/null +++ b/win/wm_hooks/wm_hooks.cxx @@ -0,0 +1,465 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This 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 software 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 software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// -=- wm_hooks.cxx +// +// Window Message Hooks Dynamic Link library + +#include <tchar.h> + +#include <wm_hooks/wm_hooks.h> + +UINT WM_HK_PingThread = RegisterWindowMessage(_T("RFB.WM_Hooks.PingThread")); + +UINT WM_HK_WindowChanged = RegisterWindowMessage(_T("RFB.WM_Hooks.WindowChanged")); +UINT WM_Hooks_WindowChanged() { + return WM_HK_WindowChanged; +} + +UINT WM_HK_WindowClientAreaChanged = RegisterWindowMessage(_T("RFB.WM_Hooks.WindowClientAreaChanged")); +UINT WM_Hooks_WindowClientAreaChanged() { + return WM_HK_WindowClientAreaChanged; +} + +UINT WM_HK_WindowBorderChanged = RegisterWindowMessage(_T("RFB.WM_Hooks.WindowBorderChanged")); +UINT WM_Hooks_WindowBorderChanged() { + return WM_HK_WindowBorderChanged; +} + +UINT WM_HK_RectangleChanged = RegisterWindowMessage(_T("RFB.WM_Hooks.RectangleChanged")); +UINT WM_Hooks_RectangleChanged() { + return WM_HK_RectangleChanged; +} + +UINT WM_HK_CursorChanged = RegisterWindowMessage(_T("RFB.WM_Hooks.CursorChanged")); +UINT WM_Hooks_CursorChanged() { + return WM_HK_CursorChanged; +} + +#ifdef _DEBUG +UINT WM_HK_Diagnostic = RegisterWindowMessage(_T("RFB.WM_Hooks.Diagnostic")); +UINT WM_Hooks_Diagnostic() { + return WM_HK_Diagnostic; +} +#endif + +ATOM ATOM_Popup_Selection = GlobalAddAtom(_T("RFB.WM_Hooks.PopupSelectionAtom")); + +// +// -=- DLL entry point +// + +HINSTANCE dll_instance = 0; + +BOOL WINAPI DllMain(HANDLE instance, ULONG reason, LPVOID reserved) { + switch (reason) { + case DLL_PROCESS_ATTACH: + dll_instance = (HINSTANCE)instance; + return TRUE; + case DLL_PROCESS_DETACH: + return TRUE; + case DLL_THREAD_DETACH: + WM_Hooks_Remove(GetCurrentThreadId()); + return TRUE; + default: + return TRUE; + }; +} + +// +// -=- Display update hooks +// + +#pragma data_seg(".WM_Hooks_Shared") +DWORD hook_owner = 0; +DWORD hook_target = 0; +HHOOK hook_CallWndProc = 0; +HHOOK hook_CallWndProcRet = 0; +HHOOK hook_GetMessage = 0; +HHOOK hook_DialogMessage = 0; +BOOL enable_cursor_shape = FALSE; +HCURSOR cursor = 0; +#ifdef _DEBUG +UINT diagnostic_min=1; +UINT diagnostic_max=0; +#endif +#pragma data_seg() + +#ifdef _DEBUG +DLLEXPORT void WM_Hooks_SetDiagnosticRange(UINT min, UINT max) { + diagnostic_min = min; diagnostic_max=max; +} +#endif + +bool NotifyHookOwner(UINT event, WPARAM wParam, LPARAM lParam) { + if (hook_owner) { + return PostThreadMessage(hook_owner, event, wParam, lParam)!=0; + /* + if (last_event) + return PostThreadMessage(hook_owner, last_event, last_wParam, last_lParam); + last_event = event; + last_wParam = wParam; + last_lParam = lParam; + return true; + */ + } + return false; +} + +bool NotifyWindow(HWND hwnd, UINT msg) { + return NotifyHookOwner(WM_HK_WindowChanged, msg, (LPARAM)hwnd); +} +bool NotifyWindowBorder(HWND hwnd, UINT msg) { + return NotifyHookOwner(WM_HK_WindowBorderChanged, msg, (LPARAM)hwnd); +} +bool NotifyWindowClientArea(HWND hwnd, UINT msg) { + return NotifyHookOwner(WM_HK_WindowClientAreaChanged, msg, (LPARAM)hwnd); +} +bool NotifyRectangle(RECT* rect) { + WPARAM w = MAKELONG((SHORT)rect->left, (SHORT)rect->top); + LPARAM l = MAKELONG((SHORT)rect->right, (SHORT)rect->bottom); + return NotifyHookOwner(WM_HK_RectangleChanged, w, l); +} +bool NotifyCursor(HCURSOR cursor) { + return NotifyHookOwner(WM_HK_CursorChanged, 0, (LPARAM)cursor); +} + +void ProcessWindowMessage(UINT msg, HWND wnd, WPARAM wParam, LPARAM lParam) { +#ifdef _DEBUG + if ((msg >= diagnostic_min) && (msg <= diagnostic_max)) + PostThreadMessage(hook_owner, WM_HK_Diagnostic, msg, (LPARAM)wnd); +#endif + if (!IsWindowVisible(wnd)) return; + switch (msg) { + + // -=- Border update events + case WM_NCPAINT: + case WM_NCACTIVATE: + NotifyWindowBorder(wnd, msg); + break; + + // -=- Client area update events + case BM_SETCHECK: + case BM_SETSTATE: + case EM_SETSEL: + case WM_CHAR: + case WM_ENABLE: + case WM_KEYUP: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_PALETTECHANGED: + case WM_RBUTTONUP: + case WM_SYSCOLORCHANGE: + case WM_SETTEXT: + case WM_SETFOCUS: + //case WM_TIMER: + NotifyWindowClientArea(wnd, msg); + break; + case WM_HSCROLL: + case WM_VSCROLL: + if (((int) LOWORD(wParam) == SB_THUMBTRACK) || ((int) LOWORD(wParam) == SB_ENDSCROLL)) + NotifyWindow(wnd, msg); + break; + + case WM_WINDOWPOSCHANGING: + case WM_DESTROY: + { + RECT wrect; + if (GetWindowRect(wnd, &wrect)) { + NotifyRectangle(&wrect); + } + } + break; + + case WM_WINDOWPOSCHANGED: + NotifyWindow(wnd, msg); + break; + + case WM_PAINT: + // *** could improve this + NotifyWindowClientArea(wnd, msg); + break; + + // Handle pop-up menus appearing + case 482: + NotifyWindow(wnd, 482); + break; + + // Handle pop-up menus having items selected + case 485: + { + HANDLE prop = GetProp(wnd, (LPCTSTR) MAKELONG(ATOM_Popup_Selection, 0)); + if (prop != (HANDLE) wParam) { + NotifyWindow(wnd, 485); + SetProp(wnd, + (LPCTSTR) MAKELONG(ATOM_Popup_Selection, 0), + (HANDLE) wParam); + } + } + break; + + case WM_NCMOUSEMOVE: + case WM_MOUSEMOVE: + if (enable_cursor_shape) { + HCURSOR new_cursor = GetCursor(); + if (new_cursor != cursor) { + cursor = new_cursor; + NotifyCursor(cursor); + } + } + break; + + /* *** + if (prf_use_GetUpdateRect) + { + HRGN region; + region = CreateRectRgn(0, 0, 0, 0); + + // Get the affected region + if (GetUpdateRgn(hWnd, region, FALSE) != ERROR) + { + int buffsize; + UINT x; + RGNDATA *buff; + POINT TopLeft; + + // Get the top-left point of the client area + TopLeft.x = 0; + TopLeft.y = 0; + if (!ClientToScreen(hWnd, &TopLeft)) + break; + + // Get the size of buffer required + buffsize = GetRegionData(region, 0, 0); + if (buffsize != 0) + { + buff = (RGNDATA *) new BYTE [buffsize]; + if (buff == NULL) + break; + + // Now get the region data + if(GetRegionData(region, buffsize, buff)) + { + for (x=0; x<(buff->rdh.nCount); x++) + { + // Obtain the rectangles from the list + RECT *urect = (RECT *) (((BYTE *) buff) + sizeof(RGNDATAHEADER) + (x * sizeof(RECT))); + SendDeferredUpdateRect( + hWnd, + (SHORT) (TopLeft.x + urect->left), + (SHORT) (TopLeft.y + urect->top), + (SHORT) (TopLeft.x + urect->right), + (SHORT) (TopLeft.y + urect->bottom) + ); + } + } + + delete [] buff; + } + } + + // Now free the region + if (region != NULL) + DeleteObject(region); + } + */ + }; +} + +LRESULT CALLBACK HookCallWndProc(int nCode, WPARAM wParam, LPARAM lParam) { + if (nCode == HC_ACTION) { + CWPSTRUCT* info = (CWPSTRUCT*) lParam; + ProcessWindowMessage(info->message, info->hwnd, info->wParam, info->lParam); + } + return CallNextHookEx(hook_CallWndProc, nCode, wParam, lParam); +} + +LRESULT CALLBACK HookCallWndProcRet(int nCode, WPARAM wParam, LPARAM lParam) { + if (nCode == HC_ACTION) { + CWPRETSTRUCT* info = (CWPRETSTRUCT*) lParam; + ProcessWindowMessage(info->message, info->hwnd, info->wParam, info->lParam); + } + return CallNextHookEx(hook_CallWndProcRet, nCode, wParam, lParam); +} + +LRESULT CALLBACK HookGetMessage(int nCode, WPARAM wParam, LPARAM lParam) { + if (nCode == HC_ACTION) { + if (wParam & PM_REMOVE) { + MSG* msg = (MSG*) lParam; + ProcessWindowMessage(msg->message, msg->hwnd, msg->wParam, msg->lParam); + } + } + return CallNextHookEx(hook_GetMessage, nCode, wParam, lParam); +} + +LRESULT CALLBACK HookDialogMessage(int nCode, WPARAM wParam, LPARAM lParam) { + if (nCode == HC_ACTION) { + MSG* msg = (MSG*) lParam; + ProcessWindowMessage(msg->message, msg->hwnd, msg->wParam, msg->lParam); + } + return CallNextHookEx(hook_DialogMessage, nCode, wParam, lParam); +} + +// - WM_Hooks_Install + +BOOL WM_Hooks_Install(DWORD owner, DWORD thread) { + // - Are there already hooks set? + if (hook_owner) { + if (!PostThreadMessage(hook_owner, WM_HK_PingThread, 0, 0)) { + WM_Hooks_Remove(hook_owner); + } else { + return FALSE; + } + } + + // - Initialise the hooks + hook_owner = owner; + hook_target = thread; + + hook_CallWndProc = SetWindowsHookEx(WH_CALLWNDPROC, HookCallWndProc, dll_instance, thread); + hook_CallWndProcRet = SetWindowsHookEx(WH_CALLWNDPROCRET, HookCallWndProcRet, dll_instance, thread); + hook_GetMessage = SetWindowsHookEx(WH_GETMESSAGE, HookGetMessage, dll_instance, thread); + hook_DialogMessage = SetWindowsHookEx(WH_SYSMSGFILTER, HookDialogMessage, dll_instance, thread); + + if (!hook_CallWndProc /*|| !hook_CallWndProcRet*/ || !hook_GetMessage || !hook_DialogMessage) { + WM_Hooks_Remove(owner); + return FALSE; + } + + return TRUE; +} + +// - WM_Hooks_Remove + +BOOL WM_Hooks_Remove(DWORD owner) { + if (owner != hook_owner) return FALSE; + if (hook_CallWndProc) { + UnhookWindowsHookEx(hook_CallWndProc); + hook_CallWndProc = 0; + } + if (hook_CallWndProcRet) { + UnhookWindowsHookEx(hook_CallWndProcRet); + hook_CallWndProcRet = 0; + } + if (hook_GetMessage) { + UnhookWindowsHookEx(hook_GetMessage); + hook_GetMessage = 0; + } + if (hook_DialogMessage) { + UnhookWindowsHookEx(hook_DialogMessage); + hook_DialogMessage = 0; + } + hook_owner = 0; + hook_target = 0; + return TRUE; +} + +// +// -=- User input hooks +// + +#pragma data_seg(".WM_Hooks_Shared") +HHOOK hook_keyboard = 0; +HHOOK hook_pointer = 0; +bool enable_real_ptr = true; +bool enable_synth_ptr = true; +bool enable_real_kbd = true; +bool enable_synth_kbd = true; +#pragma data_seg() + +#ifdef WH_KEYBOARD_LL +LRESULT CALLBACK HookKeyboardHook(int nCode, WPARAM wParam, LPARAM lParam) { + if (nCode >= 0) { + KBDLLHOOKSTRUCT* info = (KBDLLHOOKSTRUCT*) lParam; + bool real_event = (info->flags & LLKHF_INJECTED) == 0; + if ((real_event && !enable_real_kbd) || + (!real_event && !enable_synth_kbd)) { + return 1; + } + } + return CallNextHookEx(hook_keyboard, nCode, wParam, lParam); +} + +LRESULT CALLBACK HookPointerHook(int nCode, WPARAM wParam, LPARAM lParam) { + if (nCode >= 0) { + MSLLHOOKSTRUCT* info = (MSLLHOOKSTRUCT*) lParam; + bool real_event = (info->flags & LLMHF_INJECTED) == 0; + if ((real_event && !enable_real_ptr) || + (!real_event && !enable_synth_ptr)) { + return 1; + } + } + return CallNextHookEx(hook_keyboard, nCode, wParam, lParam); +} + +bool RefreshInputHooks() { + bool success = true; + bool set_ptr_hook = !enable_real_ptr || !enable_synth_ptr; + bool set_kbd_hook = !enable_real_kbd || !enable_synth_kbd; + if (hook_keyboard && !set_kbd_hook) { + UnhookWindowsHookEx(hook_keyboard); + hook_keyboard = 0; + } + if (hook_pointer && !set_ptr_hook) { + UnhookWindowsHookEx(hook_pointer); + hook_pointer = 0; + } + if (!hook_keyboard && set_kbd_hook) { + hook_keyboard = SetWindowsHookEx(WH_KEYBOARD_LL, HookKeyboardHook, dll_instance, 0); + if (!hook_keyboard) success = false; + } + if (!hook_pointer && set_ptr_hook) { + hook_pointer = SetWindowsHookEx(WH_MOUSE_LL, HookPointerHook, dll_instance, 0); + if (!hook_pointer) success = false; + } + return success; +} +#else +#pragma message(" NOTE: low-level mouse and keyboard hooks not supported") +#endif + +// - WM_Hooks_EnableRealInputs + +BOOL WM_Hooks_EnableRealInputs(BOOL pointer, BOOL keyboard) { +#ifdef WH_KEYBOARD_LL + enable_real_ptr = pointer!=0; + enable_real_kbd = keyboard!=0; + return RefreshInputHooks(); +#else + return FALSE; +#endif +} + +// - WM_Hooks_EnableSynthInputs + +BOOL WM_Hooks_EnableSynthInputs(BOOL pointer, BOOL keyboard) { +#ifdef WH_KEYBOARD_LL + enable_synth_ptr = pointer!=0; + enable_synth_kbd = keyboard!=0; + return RefreshInputHooks(); +#else + return FALSE; +#endif +} + +// - WM_Hooks_EnableCursorShape + +BOOL WM_Hooks_EnableCursorShape(BOOL enable) { + enable_cursor_shape = enable; + return TRUE; +} |