# HG changeset patch
# User Mads Kiilerich <[email protected]>
# 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
[email protected]
https://lists.sourceforge.net/lists/listinfo/freerdp-devel