Blame client/Windows/wf_event.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * Event Handling
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2009-2011 Jay Sorg
Packit 1fb8d4
 * Copyright 2010-2011 Vic Lee
Packit 1fb8d4
 * Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/freerdp.h>
Packit 1fb8d4
Packit 1fb8d4
#include "wf_client.h"
Packit 1fb8d4
Packit 1fb8d4
#include "wf_gdi.h"
Packit 1fb8d4
#include "wf_event.h"
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/event.h>
Packit 1fb8d4
Packit 1fb8d4
static HWND g_focus_hWnd;
Packit 1fb8d4
Packit Service 5a9772
#define X_POS(lParam) ((UINT16)(lParam & 0xFFFF))
Packit Service 5a9772
#define Y_POS(lParam) ((UINT16)((lParam >> 16) & 0xFFFF))
Packit 1fb8d4
Packit Service 5a9772
static BOOL wf_scale_blt(wfContext* wfc, HDC hdc, int x, int y, int w, int h, HDC hdcSrc, int x1,
Packit Service 5a9772
                         int y1, DWORD rop);
Packit Service 5a9772
static BOOL wf_scale_mouse_event(wfContext* wfc, rdpInput* input, UINT16 flags, UINT16 x, UINT16 y);
Packit 1fb8d4
#if (_WIN32_WINNT >= 0x0500)
Packit 1fb8d4
static BOOL wf_scale_mouse_event_ex(wfContext* wfc, rdpInput* input, UINT16 flags,
Packit 1fb8d4
                                    UINT16 buttonMask, UINT16 x, UINT16 y);
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
static BOOL g_flipping_in;
Packit 1fb8d4
static BOOL g_flipping_out;
Packit 1fb8d4
Packit 1fb8d4
static BOOL alt_ctrl_down()
Packit 1fb8d4
{
Packit Service 5a9772
	return ((GetAsyncKeyState(VK_CONTROL) & 0x8000) || (GetAsyncKeyState(VK_MENU) & 0x8000));
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
LRESULT CALLBACK wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam)
Packit 1fb8d4
{
Packit 1fb8d4
	wfContext* wfc;
Packit 1fb8d4
	DWORD rdp_scancode;
Packit 1fb8d4
	rdpInput* input;
Packit 1fb8d4
	PKBDLLHOOKSTRUCT p;
Packit Service 5a9772
	DEBUG_KBD("Low-level keyboard hook, hWnd %X nCode %X wParam %X", g_focus_hWnd, nCode, wParam);
Packit 1fb8d4
Packit 1fb8d4
	if (g_flipping_in)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!alt_ctrl_down())
Packit 1fb8d4
			g_flipping_in = FALSE;
Packit 1fb8d4
Packit 1fb8d4
		return CallNextHookEx(NULL, nCode, wParam, lParam);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (g_focus_hWnd && (nCode == HC_ACTION))
Packit 1fb8d4
	{
Packit 1fb8d4
		switch (wParam)
Packit 1fb8d4
		{
Packit 1fb8d4
			case WM_KEYDOWN:
Packit 1fb8d4
			case WM_SYSKEYDOWN:
Packit 1fb8d4
			case WM_KEYUP:
Packit 1fb8d4
			case WM_SYSKEYUP:
Packit Service 5a9772
				wfc = (wfContext*)GetWindowLongPtr(g_focus_hWnd, GWLP_USERDATA);
Packit Service 5a9772
				p = (PKBDLLHOOKSTRUCT)lParam;
Packit 1fb8d4
Packit 1fb8d4
				if (!wfc || !p)
Packit 1fb8d4
					return 1;
Packit 1fb8d4
Packit 1fb8d4
				input = wfc->context.input;
Packit Service 5a9772
				rdp_scancode = MAKE_RDP_SCANCODE((BYTE)p->scanCode, p->flags & LLKHF_EXTENDED);
Packit 1fb8d4
				DEBUG_KBD("keydown %d scanCode 0x%08lX flags 0x%08lX vkCode 0x%08lX",
Packit 1fb8d4
				          (wParam == WM_KEYDOWN), p->scanCode, p->flags, p->vkCode);
Packit 1fb8d4
Packit Service 5a9772
				if (wfc->fullscreen_toggle &&
Packit 1fb8d4
				    ((p->vkCode == VK_RETURN) || (p->vkCode == VK_CANCEL)) &&
Packit 1fb8d4
				    (GetAsyncKeyState(VK_CONTROL) & 0x8000) &&
Packit 1fb8d4
				    (GetAsyncKeyState(VK_MENU) & 0x8000)) /* could also use flags & LLKHF_ALTDOWN */
Packit 1fb8d4
				{
Packit 1fb8d4
					if (wParam == WM_KEYDOWN)
Packit 1fb8d4
					{
Packit 1fb8d4
						wf_toggle_fullscreen(wfc);
Packit 1fb8d4
						return 1;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (rdp_scancode == RDP_SCANCODE_NUMLOCK_EXTENDED)
Packit 1fb8d4
				{
Packit 1fb8d4
					/* Windows sends NumLock as extended - rdp doesn't */
Packit 1fb8d4
					DEBUG_KBD("hack: NumLock (x45) should not be extended");
Packit 1fb8d4
					rdp_scancode = RDP_SCANCODE_NUMLOCK;
Packit 1fb8d4
				}
Packit 1fb8d4
				else if (rdp_scancode == RDP_SCANCODE_NUMLOCK)
Packit 1fb8d4
				{
Packit 1fb8d4
					/* Windows sends Pause as if it was a RDP NumLock (handled above).
Packit Service 5a9772
					 * It must however be sent as a one-shot Ctrl+NumLock */
Packit 1fb8d4
					if (wParam == WM_KEYDOWN)
Packit 1fb8d4
					{
Packit 1fb8d4
						DEBUG_KBD("Pause, sent as Ctrl+NumLock");
Packit 1fb8d4
						freerdp_input_send_keyboard_event_ex(input, TRUE, RDP_SCANCODE_LCONTROL);
Packit 1fb8d4
						freerdp_input_send_keyboard_event_ex(input, TRUE, RDP_SCANCODE_NUMLOCK);
Packit 1fb8d4
						freerdp_input_send_keyboard_event_ex(input, FALSE, RDP_SCANCODE_LCONTROL);
Packit 1fb8d4
						freerdp_input_send_keyboard_event_ex(input, FALSE, RDP_SCANCODE_NUMLOCK);
Packit 1fb8d4
					}
Packit 1fb8d4
					else
Packit 1fb8d4
					{
Packit 1fb8d4
						DEBUG_KBD("Pause up");
Packit 1fb8d4
					}
Packit 1fb8d4
Packit 1fb8d4
					return 1;
Packit 1fb8d4
				}
Packit 1fb8d4
				else if (rdp_scancode == RDP_SCANCODE_RSHIFT_EXTENDED)
Packit 1fb8d4
				{
Packit 1fb8d4
					DEBUG_KBD("right shift (x36) should not be extended");
Packit 1fb8d4
					rdp_scancode = RDP_SCANCODE_RSHIFT;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit Service 5a9772
				freerdp_input_send_keyboard_event_ex(input, !(p->flags & LLKHF_UP), rdp_scancode);
Packit 1fb8d4
Packit Service 5a9772
				if (p->vkCode == VK_NUMLOCK || p->vkCode == VK_CAPITAL || p->vkCode == VK_SCROLL ||
Packit Service 5a9772
				    p->vkCode == VK_KANA)
Packit Service 5a9772
					DEBUG_KBD(
Packit Service 5a9772
					    "lock keys are processed on client side too to toggle their indicators");
Packit 1fb8d4
				else
Packit 1fb8d4
					return 1;
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (g_flipping_out)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!alt_ctrl_down())
Packit 1fb8d4
		{
Packit 1fb8d4
			g_flipping_out = FALSE;
Packit 1fb8d4
			g_focus_hWnd = NULL;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return CallNextHookEx(NULL, nCode, wParam, lParam);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void wf_event_focus_in(wfContext* wfc)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 syncFlags;
Packit 1fb8d4
	rdpInput* input;
Packit 1fb8d4
	POINT pt;
Packit 1fb8d4
	RECT rc;
Packit 1fb8d4
	input = wfc->context.input;
Packit 1fb8d4
	syncFlags = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (GetKeyState(VK_NUMLOCK))
Packit 1fb8d4
		syncFlags |= KBD_SYNC_NUM_LOCK;
Packit 1fb8d4
Packit 1fb8d4
	if (GetKeyState(VK_CAPITAL))
Packit 1fb8d4
		syncFlags |= KBD_SYNC_CAPS_LOCK;
Packit 1fb8d4
Packit 1fb8d4
	if (GetKeyState(VK_SCROLL))
Packit 1fb8d4
		syncFlags |= KBD_SYNC_SCROLL_LOCK;
Packit 1fb8d4
Packit 1fb8d4
	if (GetKeyState(VK_KANA))
Packit 1fb8d4
		syncFlags |= KBD_SYNC_KANA_LOCK;
Packit 1fb8d4
Packit 1fb8d4
	input->FocusInEvent(input, syncFlags);
Packit 1fb8d4
	/* send pointer position if the cursor is currently inside our client area */
Packit 1fb8d4
	GetCursorPos(&pt;;
Packit 1fb8d4
	ScreenToClient(wfc->hwnd, &pt;;
Packit 1fb8d4
	GetClientRect(wfc->hwnd, &rc);
Packit 1fb8d4
Packit 1fb8d4
	if (pt.x >= rc.left && pt.x < rc.right && pt.y >= rc.top && pt.y < rc.bottom)
Packit 1fb8d4
		input->MouseEvent(input, PTR_FLAGS_MOVE, (UINT16)pt.x, (UINT16)pt.y);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL wf_event_process_WM_MOUSEWHEEL(wfContext* wfc, HWND hWnd, UINT Msg, WPARAM wParam,
Packit Service 5a9772
                                           LPARAM lParam, BOOL horizontal, UINT16 x, UINT16 y)
Packit 1fb8d4
{
Packit 1fb8d4
	int delta;
Packit 1fb8d4
	UINT16 flags = 0;
Packit 1fb8d4
	rdpInput* input;
Packit 1fb8d4
	DefWindowProc(hWnd, Msg, wParam, lParam);
Packit 1fb8d4
	input = wfc->context.input;
Packit Service 5a9772
	delta = ((signed short)HIWORD(wParam)); /* GET_WHEEL_DELTA_WPARAM(wParam); */
Packit 1fb8d4
Packit 1fb8d4
	if (horizontal)
Packit 1fb8d4
		flags |= PTR_FLAGS_HWHEEL;
Packit 1fb8d4
	else
Packit 1fb8d4
		flags |= PTR_FLAGS_WHEEL;
Packit 1fb8d4
Packit 1fb8d4
	if (delta < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		flags |= PTR_FLAGS_WHEEL_NEGATIVE;
Packit 1fb8d4
		delta = -delta;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	flags |= delta;
Packit 1fb8d4
	return wf_scale_mouse_event(wfc, input, flags, x, y);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void wf_sizing(wfContext* wfc, WPARAM wParam, LPARAM lParam)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpSettings* settings = wfc->context.settings;
Packit 1fb8d4
	// Holding the CTRL key down while resizing the window will force the desktop aspect ratio.
Packit 1fb8d4
	LPRECT rect;
Packit 1fb8d4
Packit 1fb8d4
	if (settings->SmartSizing && (GetAsyncKeyState(VK_CONTROL) & 0x8000))
Packit 1fb8d4
	{
Packit Service 5a9772
		rect = (LPRECT)wParam;
Packit 1fb8d4
Packit 1fb8d4
		switch (lParam)
Packit 1fb8d4
		{
Packit 1fb8d4
			case WMSZ_LEFT:
Packit 1fb8d4
			case WMSZ_RIGHT:
Packit 1fb8d4
			case WMSZ_BOTTOMRIGHT:
Packit 1fb8d4
				// Adjust height
Packit Service 5a9772
				rect->bottom = rect->top + settings->DesktopHeight * (rect->right - rect->left) /
Packit Service 5a9772
				                               settings->DesktopWidth;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WMSZ_TOP:
Packit 1fb8d4
			case WMSZ_BOTTOM:
Packit 1fb8d4
			case WMSZ_TOPRIGHT:
Packit 1fb8d4
				// Adjust width
Packit 1fb8d4
				rect->right = rect->left + settings->DesktopWidth * (rect->bottom - rect->top) /
Packit Service 5a9772
				                               settings->DesktopHeight;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WMSZ_BOTTOMLEFT:
Packit 1fb8d4
			case WMSZ_TOPLEFT:
Packit 1fb8d4
				// adjust width
Packit Service 5a9772
				rect->left = rect->right - (settings->DesktopWidth * (rect->bottom - rect->top) /
Packit Service 5a9772
				                            settings->DesktopHeight);
Packit 1fb8d4
				break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
Packit 1fb8d4
{
Packit 1fb8d4
	HDC hdc;
Packit 1fb8d4
	LONG_PTR ptr;
Packit 1fb8d4
	wfContext* wfc;
Packit 1fb8d4
	int x, y, w, h;
Packit 1fb8d4
	PAINTSTRUCT ps;
Packit 1fb8d4
	BOOL processed;
Packit 1fb8d4
	RECT windowRect;
Packit 1fb8d4
	MINMAXINFO* minmax;
Packit 1fb8d4
	SCROLLINFO si;
Packit 1fb8d4
	processed = TRUE;
Packit 1fb8d4
	ptr = GetWindowLongPtr(hWnd, GWLP_USERDATA);
Packit Service 5a9772
	wfc = (wfContext*)ptr;
Packit 1fb8d4
Packit 1fb8d4
	if (wfc != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		rdpInput* input = wfc->context.input;
Packit 1fb8d4
		rdpSettings* settings = wfc->context.settings;
Packit 1fb8d4
Packit 1fb8d4
		switch (Msg)
Packit 1fb8d4
		{
Packit 1fb8d4
			case WM_MOVE:
Packit 1fb8d4
				if (!wfc->disablewindowtracking)
Packit 1fb8d4
				{
Packit Service 5a9772
					int x = (int)(short)LOWORD(lParam);
Packit Service 5a9772
					int y = (int)(short)HIWORD(lParam);
Packit 1fb8d4
					wfc->client_x = x;
Packit 1fb8d4
					wfc->client_y = y;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_GETMINMAXINFO:
Packit 1fb8d4
				if (wfc->context.settings->SmartSizing)
Packit 1fb8d4
				{
Packit 1fb8d4
					processed = FALSE;
Packit 1fb8d4
				}
Packit 1fb8d4
				else
Packit 1fb8d4
				{
Packit 1fb8d4
					// Set maximum window size for resizing
Packit Service 5a9772
					minmax = (MINMAXINFO*)lParam;
Packit 1fb8d4
Packit Service 5a9772
					// always use the last determined canvas diff, because it could be
Packit Service 5a9772
					// that the window is minimized when this gets called
Packit Service 5a9772
					// wf_update_canvas_diff(wfc);
Packit 1fb8d4
Packit 1fb8d4
					if (!wfc->fullscreen)
Packit 1fb8d4
					{
Packit 1fb8d4
						// add window decoration
Packit 1fb8d4
						minmax->ptMaxTrackSize.x = settings->DesktopWidth + wfc->diff.x;
Packit 1fb8d4
						minmax->ptMaxTrackSize.y = settings->DesktopHeight + wfc->diff.y;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_SIZING:
Packit 1fb8d4
				wf_sizing(wfc, lParam, wParam);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_SIZE:
Packit 1fb8d4
				GetWindowRect(wfc->hwnd, &windowRect);
Packit 1fb8d4
Packit 1fb8d4
				if (!wfc->fullscreen)
Packit 1fb8d4
				{
Packit 1fb8d4
					wfc->client_width = LOWORD(lParam);
Packit 1fb8d4
					wfc->client_height = HIWORD(lParam);
Packit 1fb8d4
					wfc->client_x = windowRect.left;
Packit 1fb8d4
					wfc->client_y = windowRect.top;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (wfc->client_width && wfc->client_height)
Packit 1fb8d4
				{
Packit 1fb8d4
					wf_size_scrollbars(wfc, LOWORD(lParam), HIWORD(lParam));
Packit 1fb8d4
Packit Service 5a9772
					// Workaround: when the window is maximized, the call to "ShowScrollBars"
Packit Service 5a9772
					// returns TRUE but has no effect.
Packit 1fb8d4
					if (wParam == SIZE_MAXIMIZED && !wfc->fullscreen)
Packit 1fb8d4
						SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, windowRect.right - windowRect.left,
Packit Service 5a9772
						             windowRect.bottom - windowRect.top,
Packit Service 5a9772
						             SWP_NOMOVE | SWP_FRAMECHANGED);
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_EXITSIZEMOVE:
Packit 1fb8d4
				wf_size_scrollbars(wfc, wfc->client_width, wfc->client_height);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_ERASEBKGND:
Packit 1fb8d4
				/* Say we handled it - prevents flickering */
Packit Service 5a9772
				return (LRESULT)1;
Packit 1fb8d4
Packit 1fb8d4
			case WM_PAINT:
Packit 1fb8d4
				hdc = BeginPaint(hWnd, &ps);
Packit 1fb8d4
				x = ps.rcPaint.left;
Packit 1fb8d4
				y = ps.rcPaint.top;
Packit 1fb8d4
				w = ps.rcPaint.right - ps.rcPaint.left + 1;
Packit 1fb8d4
				h = ps.rcPaint.bottom - ps.rcPaint.top + 1;
Packit 1fb8d4
				wf_scale_blt(wfc, hdc, x, y, w, h, wfc->primary->hdc,
Packit 1fb8d4
				             x - wfc->offset_x + wfc->xCurrentScroll,
Packit 1fb8d4
				             y - wfc->offset_y + wfc->yCurrentScroll, SRCCOPY);
Packit 1fb8d4
				EndPaint(hWnd, &ps);
Packit 1fb8d4
				break;
Packit 1fb8d4
#if (_WIN32_WINNT >= 0x0500)
Packit Service 5a9772
Packit 1fb8d4
			case WM_XBUTTONDOWN:
Packit 1fb8d4
				wf_scale_mouse_event_ex(wfc, input, PTR_XFLAGS_DOWN, GET_XBUTTON_WPARAM(wParam),
Packit Service 5a9772
				                        X_POS(lParam) - wfc->offset_x,
Packit Service 5a9772
				                        Y_POS(lParam) - wfc->offset_y);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_XBUTTONUP:
Packit 1fb8d4
				wf_scale_mouse_event_ex(wfc, input, 0, GET_XBUTTON_WPARAM(wParam),
Packit Service 5a9772
				                        X_POS(lParam) - wfc->offset_x,
Packit Service 5a9772
				                        Y_POS(lParam) - wfc->offset_y);
Packit 1fb8d4
				break;
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
			case WM_MBUTTONDOWN:
Packit 1fb8d4
				wf_scale_mouse_event(wfc, input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3,
Packit 1fb8d4
				                     X_POS(lParam) - wfc->offset_x, Y_POS(lParam) - wfc->offset_y);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_MBUTTONUP:
Packit Service 5a9772
				wf_scale_mouse_event(wfc, input, PTR_FLAGS_BUTTON3, X_POS(lParam) - wfc->offset_x,
Packit Service 5a9772
				                     Y_POS(lParam) - wfc->offset_y);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_LBUTTONDOWN:
Packit 1fb8d4
				wf_scale_mouse_event(wfc, input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1,
Packit 1fb8d4
				                     X_POS(lParam) - wfc->offset_x, Y_POS(lParam) - wfc->offset_y);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_LBUTTONUP:
Packit Service 5a9772
				wf_scale_mouse_event(wfc, input, PTR_FLAGS_BUTTON1, X_POS(lParam) - wfc->offset_x,
Packit Service 5a9772
				                     Y_POS(lParam) - wfc->offset_y);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_RBUTTONDOWN:
Packit 1fb8d4
				wf_scale_mouse_event(wfc, input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2,
Packit 1fb8d4
				                     X_POS(lParam) - wfc->offset_x, Y_POS(lParam) - wfc->offset_y);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_RBUTTONUP:
Packit Service 5a9772
				wf_scale_mouse_event(wfc, input, PTR_FLAGS_BUTTON2, X_POS(lParam) - wfc->offset_x,
Packit Service 5a9772
				                     Y_POS(lParam) - wfc->offset_y);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_MOUSEMOVE:
Packit 1fb8d4
				wf_scale_mouse_event(wfc, input, PTR_FLAGS_MOVE, X_POS(lParam) - wfc->offset_x,
Packit 1fb8d4
				                     Y_POS(lParam) - wfc->offset_y);
Packit 1fb8d4
				break;
Packit 1fb8d4
#if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
Packit Service 5a9772
Packit 1fb8d4
			case WM_MOUSEWHEEL:
Packit 1fb8d4
				wf_event_process_WM_MOUSEWHEEL(wfc, hWnd, Msg, wParam, lParam, FALSE,
Packit Service 5a9772
				                               X_POS(lParam) - wfc->offset_x,
Packit Service 5a9772
				                               Y_POS(lParam) - wfc->offset_y);
Packit 1fb8d4
				break;
Packit 1fb8d4
#endif
Packit 1fb8d4
#if (_WIN32_WINNT >= 0x0600)
Packit Service 5a9772
Packit 1fb8d4
			case WM_MOUSEHWHEEL:
Packit 1fb8d4
				wf_event_process_WM_MOUSEWHEEL(wfc, hWnd, Msg, wParam, lParam, TRUE,
Packit Service 5a9772
				                               X_POS(lParam) - wfc->offset_x,
Packit Service 5a9772
				                               Y_POS(lParam) - wfc->offset_y);
Packit 1fb8d4
				break;
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
			case WM_SETCURSOR:
Packit 1fb8d4
				if (LOWORD(lParam) == HTCLIENT)
Packit 1fb8d4
					SetCursor(wfc->cursor);
Packit 1fb8d4
				else
Packit 1fb8d4
					DefWindowProc(hWnd, Msg, wParam, lParam);
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_HSCROLL:
Packit Service 5a9772
			{
Packit Service 5a9772
				int xDelta;  // xDelta = new_pos - current_pos
Packit Service 5a9772
				int xNewPos; // new position
Packit Service 5a9772
				int yDelta = 0;
Packit Service 5a9772
Packit Service 5a9772
				switch (LOWORD(wParam))
Packit 1fb8d4
				{
Packit Service 5a9772
					// User clicked the scroll bar shaft left of the scroll box.
Packit Service 5a9772
					case SB_PAGEUP:
Packit Service 5a9772
						xNewPos = wfc->xCurrentScroll - 50;
Packit Service 5a9772
						break;
Packit 1fb8d4
Packit Service 5a9772
					// User clicked the scroll bar shaft right of the scroll box.
Packit Service 5a9772
					case SB_PAGEDOWN:
Packit Service 5a9772
						xNewPos = wfc->xCurrentScroll + 50;
Packit Service 5a9772
						break;
Packit Service 5a9772
Packit Service 5a9772
					// User clicked the left arrow.
Packit Service 5a9772
					case SB_LINEUP:
Packit Service 5a9772
						xNewPos = wfc->xCurrentScroll - 5;
Packit Service 5a9772
						break;
Packit Service 5a9772
Packit Service 5a9772
					// User clicked the right arrow.
Packit Service 5a9772
					case SB_LINEDOWN:
Packit Service 5a9772
						xNewPos = wfc->xCurrentScroll + 5;
Packit Service 5a9772
						break;
Packit 1fb8d4
Packit Service 5a9772
					// User dragged the scroll box.
Packit Service 5a9772
					case SB_THUMBPOSITION:
Packit Service 5a9772
						xNewPos = HIWORD(wParam);
Packit Service 5a9772
						break;
Packit 1fb8d4
Packit Service 5a9772
					// user is dragging the scrollbar
Packit Service 5a9772
					case SB_THUMBTRACK:
Packit Service 5a9772
						xNewPos = HIWORD(wParam);
Packit 1fb8d4
						break;
Packit 1fb8d4
Packit Service 5a9772
					default:
Packit Service 5a9772
						xNewPos = wfc->xCurrentScroll;
Packit 1fb8d4
				}
Packit Service 5a9772
Packit Service 5a9772
				// New position must be between 0 and the screen width.
Packit Service 5a9772
				xNewPos = MAX(0, xNewPos);
Packit Service 5a9772
				xNewPos = MIN(wfc->xMaxScroll, xNewPos);
Packit Service 5a9772
Packit Service 5a9772
				// If the current position does not change, do not scroll.
Packit Service 5a9772
				if (xNewPos == wfc->xCurrentScroll)
Packit Service 5a9772
					break;
Packit Service 5a9772
Packit Service 5a9772
				// Determine the amount scrolled (in pixels).
Packit Service 5a9772
				xDelta = xNewPos - wfc->xCurrentScroll;
Packit Service 5a9772
				// Reset the current scroll position.
Packit Service 5a9772
				wfc->xCurrentScroll = xNewPos;
Packit Service 5a9772
				// Scroll the window. (The system repaints most of the
Packit Service 5a9772
				// client area when ScrollWindowEx is called; however, it is
Packit Service 5a9772
				// necessary to call UpdateWindow in order to repaint the
Packit Service 5a9772
				// rectangle of pixels that were invalidated.)
Packit Service 5a9772
				ScrollWindowEx(wfc->hwnd, -xDelta, -yDelta, (CONST RECT*)NULL, (CONST RECT*)NULL,
Packit Service 5a9772
				               (HRGN)NULL, (PRECT)NULL, SW_INVALIDATE);
Packit Service 5a9772
				UpdateWindow(wfc->hwnd);
Packit Service 5a9772
				// Reset the scroll bar.
Packit Service 5a9772
				si.cbSize = sizeof(si);
Packit Service 5a9772
				si.fMask = SIF_POS;
Packit Service 5a9772
				si.nPos = wfc->xCurrentScroll;
Packit Service 5a9772
				SetScrollInfo(wfc->hwnd, SB_HORZ, &si, TRUE);
Packit Service 5a9772
			}
Packit Service 5a9772
			break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_VSCROLL:
Packit Service 5a9772
			{
Packit Service 5a9772
				int xDelta = 0;
Packit Service 5a9772
				int yDelta;  // yDelta = new_pos - current_pos
Packit Service 5a9772
				int yNewPos; // new position
Packit Service 5a9772
Packit Service 5a9772
				switch (LOWORD(wParam))
Packit 1fb8d4
				{
Packit Service 5a9772
					// User clicked the scroll bar shaft above the scroll box.
Packit Service 5a9772
					case SB_PAGEUP:
Packit Service 5a9772
						yNewPos = wfc->yCurrentScroll - 50;
Packit Service 5a9772
						break;
Packit 1fb8d4
Packit Service 5a9772
					// User clicked the scroll bar shaft below the scroll box.
Packit Service 5a9772
					case SB_PAGEDOWN:
Packit Service 5a9772
						yNewPos = wfc->yCurrentScroll + 50;
Packit Service 5a9772
						break;
Packit Service 5a9772
Packit Service 5a9772
					// User clicked the top arrow.
Packit Service 5a9772
					case SB_LINEUP:
Packit Service 5a9772
						yNewPos = wfc->yCurrentScroll - 5;
Packit Service 5a9772
						break;
Packit Service 5a9772
Packit Service 5a9772
					// User clicked the bottom arrow.
Packit Service 5a9772
					case SB_LINEDOWN:
Packit Service 5a9772
						yNewPos = wfc->yCurrentScroll + 5;
Packit Service 5a9772
						break;
Packit 1fb8d4
Packit Service 5a9772
					// User dragged the scroll box.
Packit Service 5a9772
					case SB_THUMBPOSITION:
Packit Service 5a9772
						yNewPos = HIWORD(wParam);
Packit Service 5a9772
						break;
Packit 1fb8d4
Packit Service 5a9772
					// user is dragging the scrollbar
Packit Service 5a9772
					case SB_THUMBTRACK:
Packit Service 5a9772
						yNewPos = HIWORD(wParam);
Packit 1fb8d4
						break;
Packit 1fb8d4
Packit Service 5a9772
					default:
Packit Service 5a9772
						yNewPos = wfc->yCurrentScroll;
Packit 1fb8d4
				}
Packit Service 5a9772
Packit Service 5a9772
				// New position must be between 0 and the screen height.
Packit Service 5a9772
				yNewPos = MAX(0, yNewPos);
Packit Service 5a9772
				yNewPos = MIN(wfc->yMaxScroll, yNewPos);
Packit Service 5a9772
Packit Service 5a9772
				// If the current position does not change, do not scroll.
Packit Service 5a9772
				if (yNewPos == wfc->yCurrentScroll)
Packit Service 5a9772
					break;
Packit Service 5a9772
Packit Service 5a9772
				// Determine the amount scrolled (in pixels).
Packit Service 5a9772
				yDelta = yNewPos - wfc->yCurrentScroll;
Packit Service 5a9772
				// Reset the current scroll position.
Packit Service 5a9772
				wfc->yCurrentScroll = yNewPos;
Packit Service 5a9772
				// Scroll the window. (The system repaints most of the
Packit Service 5a9772
				// client area when ScrollWindowEx is called; however, it is
Packit Service 5a9772
				// necessary to call UpdateWindow in order to repaint the
Packit Service 5a9772
				// rectangle of pixels that were invalidated.)
Packit Service 5a9772
				ScrollWindowEx(wfc->hwnd, -xDelta, -yDelta, (CONST RECT*)NULL, (CONST RECT*)NULL,
Packit Service 5a9772
				               (HRGN)NULL, (PRECT)NULL, SW_INVALIDATE);
Packit Service 5a9772
				UpdateWindow(wfc->hwnd);
Packit Service 5a9772
				// Reset the scroll bar.
Packit Service 5a9772
				si.cbSize = sizeof(si);
Packit Service 5a9772
				si.fMask = SIF_POS;
Packit Service 5a9772
				si.nPos = wfc->yCurrentScroll;
Packit Service 5a9772
				SetScrollInfo(wfc->hwnd, SB_VERT, &si, TRUE);
Packit Service 5a9772
			}
Packit Service 5a9772
			break;
Packit 1fb8d4
Packit 1fb8d4
			case WM_SYSCOMMAND:
Packit Service 5a9772
			{
Packit Service 5a9772
				if (wParam == SYSCOMMAND_ID_SMARTSIZING)
Packit 1fb8d4
				{
Packit Service 5a9772
					HMENU hMenu = GetSystemMenu(wfc->hwnd, FALSE);
Packit Service 5a9772
					freerdp_set_param_bool(wfc->context.settings, FreeRDP_SmartSizing,
Packit Service 5a9772
					                       !wfc->context.settings->SmartSizing);
Packit Service 5a9772
					CheckMenuItem(hMenu, SYSCOMMAND_ID_SMARTSIZING,
Packit Service 5a9772
					              wfc->context.settings->SmartSizing ? MF_CHECKED : MF_UNCHECKED);
Packit 1fb8d4
				}
Packit Service 5a9772
				else
Packit Service 5a9772
				{
Packit Service 5a9772
					processed = FALSE;
Packit Service 5a9772
				}
Packit Service 5a9772
			}
Packit Service 5a9772
			break;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit 1fb8d4
				processed = FALSE;
Packit 1fb8d4
				break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		processed = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (processed)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	switch (Msg)
Packit 1fb8d4
	{
Packit 1fb8d4
		case WM_DESTROY:
Packit 1fb8d4
			PostQuitMessage(WM_QUIT);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case WM_SETFOCUS:
Packit 1fb8d4
			DEBUG_KBD("getting focus %X", hWnd);
Packit 1fb8d4
Packit 1fb8d4
			if (alt_ctrl_down())
Packit 1fb8d4
				g_flipping_in = TRUE;
Packit 1fb8d4
Packit 1fb8d4
			g_focus_hWnd = hWnd;
Packit 1fb8d4
			freerdp_set_focus(wfc->context.instance);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case WM_KILLFOCUS:
Packit 1fb8d4
			if (g_focus_hWnd == hWnd && wfc && !wfc->fullscreen)
Packit 1fb8d4
			{
Packit 1fb8d4
				DEBUG_KBD("loosing focus %X", hWnd);
Packit 1fb8d4
Packit 1fb8d4
				if (alt_ctrl_down())
Packit 1fb8d4
					g_flipping_out = TRUE;
Packit 1fb8d4
				else
Packit 1fb8d4
					g_focus_hWnd = NULL;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case WM_ACTIVATE:
Packit Service 5a9772
		{
Packit Service 5a9772
			int activate = (int)(short)LOWORD(wParam);
Packit 1fb8d4
Packit Service 5a9772
			if (activate != WA_INACTIVE)
Packit Service 5a9772
			{
Packit Service 5a9772
				if (alt_ctrl_down())
Packit Service 5a9772
					g_flipping_in = TRUE;
Packit 1fb8d4
Packit Service 5a9772
				g_focus_hWnd = hWnd;
Packit Service 5a9772
			}
Packit Service 5a9772
			else
Packit Service 5a9772
			{
Packit Service 5a9772
				if (alt_ctrl_down())
Packit Service 5a9772
					g_flipping_out = TRUE;
Packit 1fb8d4
				else
Packit Service 5a9772
					g_focus_hWnd = NULL;
Packit 1fb8d4
			}
Packit Service 5a9772
		}
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			return DefWindowProc(hWnd, Msg, wParam, lParam);
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL wf_scale_blt(wfContext* wfc, HDC hdc, int x, int y, int w, int h, HDC hdcSrc, int x1, int y1,
Packit Service 5a9772
                  DWORD rop)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpSettings* settings;
Packit 1fb8d4
	UINT32 ww, wh, dw, dh;
Packit 1fb8d4
	settings = wfc->context.settings;
Packit 1fb8d4
Packit 1fb8d4
	if (!wfc->client_width)
Packit 1fb8d4
		wfc->client_width = settings->DesktopWidth;
Packit 1fb8d4
Packit 1fb8d4
	if (!wfc->client_height)
Packit 1fb8d4
		wfc->client_height = settings->DesktopHeight;
Packit 1fb8d4
Packit 1fb8d4
	ww = wfc->client_width;
Packit 1fb8d4
	wh = wfc->client_height;
Packit 1fb8d4
	dw = settings->DesktopWidth;
Packit 1fb8d4
	dh = settings->DesktopHeight;
Packit 1fb8d4
Packit 1fb8d4
	if (!ww)
Packit 1fb8d4
		ww = dw;
Packit 1fb8d4
Packit 1fb8d4
	if (!wh)
Packit 1fb8d4
		wh = dh;
Packit 1fb8d4
Packit Service 5a9772
	if (wfc->fullscreen || !wfc->context.settings->SmartSizing || (ww == dw && wh == dh))
Packit 1fb8d4
	{
Packit 1fb8d4
		return BitBlt(hdc, x, y, w, h, wfc->primary->hdc, x1, y1, SRCCOPY);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		SetStretchBltMode(hdc, HALFTONE);
Packit 1fb8d4
		SetBrushOrgEx(hdc, 0, 0, NULL);
Packit 1fb8d4
		return StretchBlt(hdc, 0, 0, ww, wh, wfc->primary->hdc, 0, 0, dw, dh, SRCCOPY);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL wf_scale_mouse_pos(wfContext* wfc, UINT16* x, UINT16* y)
Packit 1fb8d4
{
Packit 1fb8d4
	int ww, wh, dw, dh;
Packit 1fb8d4
	rdpContext* context;
Packit 1fb8d4
	rdpSettings* settings;
Packit Service 5a9772
Packit 1fb8d4
	if (!wfc || !x || !y)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	settings = wfc->context.settings;
Packit Service 5a9772
Packit 1fb8d4
	if (!settings)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!wfc->client_width)
Packit 1fb8d4
		wfc->client_width = settings->DesktopWidth;
Packit 1fb8d4
Packit 1fb8d4
	if (!wfc->client_height)
Packit 1fb8d4
		wfc->client_height = settings->DesktopHeight;
Packit 1fb8d4
Packit 1fb8d4
	ww = wfc->client_width;
Packit 1fb8d4
	wh = wfc->client_height;
Packit 1fb8d4
	dw = settings->DesktopWidth;
Packit 1fb8d4
	dh = settings->DesktopHeight;
Packit 1fb8d4
Packit 1fb8d4
	if (!settings->SmartSizing || ((ww == dw) && (wh == dh)))
Packit 1fb8d4
	{
Packit 1fb8d4
		*x += wfc->xCurrentScroll;
Packit 1fb8d4
		*y += wfc->yCurrentScroll;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		*x = *x * dw / ww + wfc->xCurrentScroll;
Packit 1fb8d4
		*y = *y * dh / wh + wfc->yCurrentScroll;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL wf_scale_mouse_event(wfContext* wfc, rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
Packit 1fb8d4
{
Packit 1fb8d4
	MouseEventEventArgs eventArgs;
Packit 1fb8d4
Packit 1fb8d4
	if (!wf_scale_mouse_pos(wfc, &x, &y))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (freerdp_input_send_mouse_event(input, flags, x, y))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	eventArgs.flags = flags;
Packit 1fb8d4
	eventArgs.x = x;
Packit 1fb8d4
	eventArgs.y = y;
Packit 1fb8d4
	PubSub_OnMouseEvent(wfc->context.pubSub, &wfc->context, &eventArgs);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
#if (_WIN32_WINNT >= 0x0500)
Packit Service 5a9772
static BOOL wf_scale_mouse_event_ex(wfContext* wfc, rdpInput* input, UINT16 flags,
Packit Service 5a9772
                                    UINT16 buttonMask, UINT16 x, UINT16 y)
Packit 1fb8d4
{
Packit 1fb8d4
	MouseEventExEventArgs eventArgs;
Packit 1fb8d4
Packit 1fb8d4
	if (buttonMask & XBUTTON1)
Packit 1fb8d4
		flags |= PTR_XFLAGS_BUTTON1;
Packit Service 5a9772
Packit 1fb8d4
	if (buttonMask & XBUTTON2)
Packit 1fb8d4
		flags |= PTR_XFLAGS_BUTTON2;
Packit 1fb8d4
Packit 1fb8d4
	if (!wf_scale_mouse_pos(wfc, &x, &y))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (freerdp_input_send_extended_mouse_event(input, flags, x, y))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	eventArgs.flags = flags;
Packit 1fb8d4
	eventArgs.x = x;
Packit 1fb8d4
	eventArgs.y = y;
Packit 1fb8d4
	PubSub_OnMouseEventEx(wfc->context.pubSub, &wfc->context, &eventArgs);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
#endif