# HG changeset patch # User Mads Kiilerich <m...@kiilerich.com> # Date 1300226300 -3600 # Node ID 2760f5e8d4b601f360ac76ac2e74be058be27873 # Parent d1714a5c82b3d77f8c3c979703cd32629448b0c7 wfreerdp: use LowLevelKeyboardProc hook for keyboard input
It seems like this is better for our purpose than processing ordinary events. This also makes it possible to intercept Alt+Tab and process it remotely. The low level events are not tied to a window or to having focus, so we have to keep a global telling us where we have focus. diff --git a/win/wfreerdp/wf_event.cpp b/win/wfreerdp/wf_event.cpp --- a/win/wfreerdp/wf_event.cpp +++ b/win/wfreerdp/wf_event.cpp @@ -23,12 +23,54 @@ #include "wf_event.h" extern HCURSOR g_default_cursor; +extern HWND g_hWnd; #define X_POS(lParam) (lParam & 0xffff) #define Y_POS(lParam) ((lParam >> 16) & 0xffff) #define SCANCODE(lParam) ((lParam >> 16) & 0xff) LRESULT CALLBACK +wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam) +{ + HWND hWnd = g_hWnd; + wfInfo * wfi; + DWORD scanCode, flags; + + DEBUG_KBD("hWnd %X nCode %X\n", hWnd, nCode); + if (hWnd && (nCode == HC_ACTION)) { + switch (wParam) { + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + wfi = (wfInfo *) GetWindowLongPtr(hWnd, GWLP_USERDATA); + PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) lParam; + scanCode = p->scanCode; + flags = p->flags; + DEBUG_KBD("wParam %04X scanCode %04X flags %02X vkCode %02X\n", + wParam, scanCode, flags, p->vkCode); + + if ((scanCode == 0x36) && (flags & 1)) + { + DEBUG_KBD("hack: sending extended right shift (x36) as plain left shift (0x2a)\n"); + scanCode = 0x2a; + flags &= ~1; + } + + wfi->inst->rdp_send_input(wfi->inst, RDP_INPUT_SCANCODE, + ((flags & 0x80) ? KBD_FLAG_UP : 0) | + ((flags & 1) ? KBD_FLAG_EXT : 0), + scanCode, 0); + if (p->vkCode == VK_CAPITAL) + DEBUG_KBD("caps lock is processed on client side too to toggle caps lock indicator\n"); + else + return 1; + } + } + return CallNextHookEx(NULL, nCode, wParam, lParam); +} + +LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { wfInfo * wfi; @@ -98,36 +140,6 @@ } break; - case WM_KEYDOWN: - if (wfi != NULL) - { -#ifdef WITH_DEBUG_KBD - printf("key down: lParam=0x%08X = %3d\n", lParam, SCANCODE(lParam)); -#endif - wfi->inst->rdp_send_input(wfi->inst, RDP_INPUT_SCANCODE, - RDP_KEYPRESS, SCANCODE(lParam), 0); - } - break; - - case WM_KEYUP: - if (wfi != NULL) - { -#ifdef WITH_DEBUG_KBD - printf("key up: lParam=0x%08X = %3d\n", lParam, SCANCODE(lParam)); -#endif - wfi->inst->rdp_send_input(wfi->inst, RDP_INPUT_SCANCODE, - RDP_KEYRELEASE, SCANCODE(lParam), 0); - if (SCANCODE(lParam) == 56) - { -#ifdef WITH_DEBUG_KBD - printf("faking key up for left ctrl = 29 for key up of AltGr = 56\n"); -#endif - wfi->inst->rdp_send_input(wfi->inst, RDP_INPUT_SCANCODE, - RDP_KEYRELEASE, 29, 0); - } - } - break; - case WM_SETCURSOR: if (wfi != NULL) { @@ -139,10 +151,19 @@ } break; + case WM_SETFOCUS: + DEBUG_KBD("getting focus %X\n", hWnd); + g_hWnd = hWnd; + break; + + case WM_KILLFOCUS: + DEBUG_KBD("loosing focus %X\n", hWnd); + if (g_hWnd == hWnd) + g_hWnd = NULL; // racy - but probably not in a fatal way + break; + default: - // Process the left-over messages return DefWindowProc(hWnd, Msg, wParam, lParam); } - // If something was not done, let it go return 0; } diff --git a/win/wfreerdp/wf_event.h b/win/wfreerdp/wf_event.h --- a/win/wfreerdp/wf_event.h +++ b/win/wfreerdp/wf_event.h @@ -23,6 +23,8 @@ #include <windows.h> LRESULT CALLBACK +wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); #endif diff --git a/win/wfreerdp/wf_win.cpp b/win/wfreerdp/wf_win.cpp --- a/win/wfreerdp/wf_win.cpp +++ b/win/wfreerdp/wf_win.cpp @@ -27,6 +27,7 @@ extern LPCTSTR g_wnd_class_name; extern HINSTANCE g_hInstance; extern HCURSOR g_default_cursor; +extern HWND g_hWnd; // See http://msdn.microsoft.com/en-us/library/dd145130(VS.85).aspx static const DWORD rop3_code_table[] = @@ -1189,6 +1190,7 @@ } wfi->drw = wfi->backstore; + g_hWnd = wfi->hwnd; ShowWindow(wfi->hwnd, SW_SHOWNORMAL); UpdateWindow(wfi->hwnd); diff --git a/win/wfreerdp/wfreerdp.cpp b/win/wfreerdp/wfreerdp.cpp --- a/win/wfreerdp/wfreerdp.cpp +++ b/win/wfreerdp/wfreerdp.cpp @@ -39,6 +39,7 @@ HCURSOR g_default_cursor; volatile int g_thread_count = 0; HANDLE g_done_event; +HWND g_hWnd; static int create_console(void) @@ -588,6 +589,40 @@ return NULL; } +static DWORD WINAPI +kbd_thread_func(LPVOID lpParam) +{ + HHOOK hook_handle; + MSG msg; + BOOL bRet; + + DEBUG("keyboard thread started\n"); + + hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, wf_ll_kbd_proc, NULL, 0); + if (hook_handle) + { + while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0) + { + if (bRet == -1) + { + printf("keyboard thread error getting message\n"); + break; + } + else + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + DEBUG("keyboard thread ended\n"); + UnhookWindowsHookEx(hook_handle); + } + else + printf("failed to install keyboard hook\n"); + + return NULL; +} + INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { @@ -627,11 +662,13 @@ wnd_cls.lpszClassName = g_wnd_class_name; wnd_cls.hInstance = hInstance; wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION); - RegisterClassEx(&wnd_cls); g_hInstance = hInstance; + if (!CreateThread(NULL, 0, kbd_thread_func, NULL, 0, NULL)) + printf("error creating keyboard handler thread"); + argv = CommandLineToArgvW(GetCommandLine(), &argc); while (1) ------------------------------------------------------------------------------ Colocation vs. Managed Hosting A question and answer guide to determining the best fit for your organization - today and in the future. http://p.sf.net/sfu/internap-sfd2d _______________________________________________ Freerdp-devel mailing list Freerdp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/freerdp-devel