FreeRDP
Loading...
Searching...
No Matches
wf_event.c
1
22#include <freerdp/config.h>
23
24#include <stdio.h>
25
26#include <winpr/assert.h>
27#include <winpr/sysinfo.h>
28#include <freerdp/freerdp.h>
29
30#include "wf_client.h"
31
32#include "wf_gdi.h"
33#include "wf_event.h"
34
35#include <freerdp/event.h>
36
37#include <windowsx.h>
38
39static HWND g_focus_hWnd = NULL;
40static HWND g_main_hWnd = NULL;
41static HWND g_parent_hWnd = NULL;
42
43#define RESIZE_MIN_DELAY 200 /* minimum delay in ms between two resizes */
44
45static BOOL wf_scale_blt(wfContext* wfc, HDC hdc, int x, int y, int w, int h, HDC hdcSrc, int x1,
46 int y1, DWORD rop);
47static BOOL wf_scale_mouse_event(wfContext* wfc, UINT16 flags, INT32 x, INT32 y);
48#if (_WIN32_WINNT >= 0x0500)
49static BOOL wf_scale_mouse_event_ex(wfContext* wfc, UINT16 flags, UINT16 buttonMask, INT32 x,
50 INT32 y);
51#endif
52
53static BOOL g_flipping_in = FALSE;
54static BOOL g_flipping_out = FALSE;
55
56static BOOL g_keystates[256] = { 0 };
57
58static BOOL ctrl_down(void)
59{
60 return g_keystates[VK_CONTROL] || g_keystates[VK_LCONTROL] || g_keystates[VK_RCONTROL];
61}
62
63static BOOL alt_ctrl_down(void)
64{
65 const BOOL altDown = g_keystates[VK_MENU] || g_keystates[VK_LMENU] || g_keystates[VK_RMENU];
66 return altDown && ctrl_down();
67}
68
69LRESULT CALLBACK wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam)
70{
71 DWORD ext_proc_id = 0;
72
73 wfContext* wfc = NULL;
74 DWORD rdp_scancode;
75 BOOL keystate;
76 rdpInput* input;
77 PKBDLLHOOKSTRUCT p;
78
79 DEBUG_KBD("Low-level keyboard hook, hWnd %X nCode %X wParam %X", g_focus_hWnd, nCode, wParam);
80
81 if (g_flipping_in)
82 {
83 if (!alt_ctrl_down())
84 g_flipping_in = FALSE;
85
86 return CallNextHookEx(NULL, nCode, wParam, lParam);
87 }
88
89 if (g_parent_hWnd && g_main_hWnd)
90 {
91 wfc = (wfContext*)GetWindowLongPtr(g_main_hWnd, GWLP_USERDATA);
92 GUITHREADINFO gui_thread_info;
93 gui_thread_info.cbSize = sizeof(GUITHREADINFO);
94 HWND fg_win_hwnd = GetForegroundWindow();
95 DWORD fg_win_thread_id = GetWindowThreadProcessId(fg_win_hwnd, &ext_proc_id);
96 BOOL result = GetGUIThreadInfo(fg_win_thread_id, &gui_thread_info);
97 if (gui_thread_info.hwndFocus != wfc->hWndParent)
98 {
99 g_focus_hWnd = NULL;
100 return CallNextHookEx(NULL, nCode, wParam, lParam);
101 }
102
103 g_focus_hWnd = g_main_hWnd;
104 }
105
106 if (g_focus_hWnd && (nCode == HC_ACTION))
107 {
108 switch (wParam)
109 {
110 case WM_KEYDOWN:
111 case WM_SYSKEYDOWN:
112 case WM_KEYUP:
113 case WM_SYSKEYUP:
114 if (!wfc)
115 wfc = (wfContext*)GetWindowLongPtr(g_focus_hWnd, GWLP_USERDATA);
116 p = (PKBDLLHOOKSTRUCT)lParam;
117
118 if (!wfc || !p)
119 return 1;
120
121 input = wfc->common.context.input;
122 rdp_scancode = MAKE_RDP_SCANCODE((BYTE)p->scanCode, p->flags & LLKHF_EXTENDED);
123 keystate = g_keystates[p->scanCode & 0xFF];
124
125 switch (wParam)
126 {
127 case WM_KEYDOWN:
128 case WM_SYSKEYDOWN:
129 g_keystates[p->scanCode & 0xFF] = TRUE;
130 break;
131 case WM_KEYUP:
132 case WM_SYSKEYUP:
133 default:
134 g_keystates[p->scanCode & 0xFF] = FALSE;
135 break;
136 }
137 DEBUG_KBD("keydown %d scanCode 0x%08lX flags 0x%08lX vkCode 0x%08lX",
138 (wParam == WM_KEYDOWN), p->scanCode, p->flags, p->vkCode);
139
140 if (wfc->fullscreen_toggle && (p->vkCode == VK_RETURN || p->vkCode == VK_CANCEL))
141 {
142 if (alt_ctrl_down())
143 {
144 if (wParam == WM_KEYDOWN)
145 {
146 wf_toggle_fullscreen(wfc);
147 return 1;
148 }
149 }
150 }
151
152 if (rdp_scancode == RDP_SCANCODE_NUMLOCK_EXTENDED)
153 {
154 /* Windows sends NumLock as extended - rdp doesn't */
155 DEBUG_KBD("hack: NumLock (x45) should not be extended");
156 rdp_scancode = RDP_SCANCODE_NUMLOCK;
157 }
158 else if (rdp_scancode == RDP_SCANCODE_NUMLOCK)
159 {
160 /* Windows sends Pause as if it was a RDP NumLock (handled above).
161 * It must however be sent as a one-shot Ctrl+NumLock */
162 if (wParam == WM_KEYDOWN)
163 {
164 DEBUG_KBD("Pause, sent as Ctrl+NumLock");
165 freerdp_input_send_keyboard_event_ex(input, TRUE, FALSE,
166 RDP_SCANCODE_LCONTROL);
167 freerdp_input_send_keyboard_event_ex(input, TRUE, FALSE,
168 RDP_SCANCODE_NUMLOCK);
169 freerdp_input_send_keyboard_event_ex(input, FALSE, FALSE,
170 RDP_SCANCODE_LCONTROL);
171 freerdp_input_send_keyboard_event_ex(input, FALSE, FALSE,
172 RDP_SCANCODE_NUMLOCK);
173 }
174 else
175 {
176 DEBUG_KBD("Pause up");
177 }
178
179 return 1;
180 }
181 else if (rdp_scancode == RDP_SCANCODE_RSHIFT_EXTENDED)
182 {
183 DEBUG_KBD("right shift (x36) should not be extended");
184 rdp_scancode = RDP_SCANCODE_RSHIFT;
185 }
186
187 freerdp_input_send_keyboard_event_ex(input, !(p->flags & LLKHF_UP), keystate,
188 rdp_scancode);
189
190 if (p->vkCode == VK_NUMLOCK || p->vkCode == VK_CAPITAL || p->vkCode == VK_SCROLL ||
191 p->vkCode == VK_KANA)
192 DEBUG_KBD(
193 "lock keys are processed on client side too to toggle their indicators");
194 else
195 return 1;
196
197 break;
198 default:
199 break;
200 }
201 }
202
203 if (g_flipping_out)
204 {
205 if (!alt_ctrl_down())
206 {
207 g_flipping_out = FALSE;
208 g_focus_hWnd = NULL;
209 }
210 }
211
212 return CallNextHookEx(NULL, nCode, wParam, lParam);
213}
214
215void wf_event_focus_in(wfContext* wfc)
216{
217 UINT16 syncFlags;
218 rdpInput* input;
219 POINT pt;
220 RECT rc;
221 input = wfc->common.context.input;
222 syncFlags = 0;
223
224 if (GetKeyState(VK_NUMLOCK))
225 syncFlags |= KBD_SYNC_NUM_LOCK;
226
227 if (GetKeyState(VK_CAPITAL))
228 syncFlags |= KBD_SYNC_CAPS_LOCK;
229
230 if (GetKeyState(VK_SCROLL))
231 syncFlags |= KBD_SYNC_SCROLL_LOCK;
232
233 if (GetKeyState(VK_KANA))
234 syncFlags |= KBD_SYNC_KANA_LOCK;
235
236 input->FocusInEvent(input, syncFlags);
237 /* send pointer position if the cursor is currently inside our client area */
238 GetCursorPos(&pt);
239 ScreenToClient(wfc->hwnd, &pt);
240 GetClientRect(wfc->hwnd, &rc);
241
242 if (pt.x >= rc.left && pt.x < rc.right && pt.y >= rc.top && pt.y < rc.bottom)
243 input->MouseEvent(input, PTR_FLAGS_MOVE, (UINT16)pt.x, (UINT16)pt.y);
244}
245
246static BOOL wf_event_process_WM_MOUSEWHEEL(wfContext* wfc, HWND hWnd, UINT Msg, WPARAM wParam,
247 LPARAM lParam, BOOL horizontal, INT32 x, INT32 y)
248{
249 int delta;
250 UINT16 flags = 0;
251 rdpInput* input;
252
253 WINPR_ASSERT(wfc);
254
255 input = wfc->common.context.input;
256 WINPR_ASSERT(input);
257
258 DefWindowProc(hWnd, Msg, wParam, lParam);
259 delta = ((signed short)HIWORD(wParam)); /* GET_WHEEL_DELTA_WPARAM(wParam); */
260
261 if (horizontal)
262 flags |= PTR_FLAGS_HWHEEL;
263 else
264 flags |= PTR_FLAGS_WHEEL;
265
266 if (delta < 0)
267 {
268 flags |= PTR_FLAGS_WHEEL_NEGATIVE;
269 /* 9bit twos complement, delta already negative */
270 delta = 0x100 + delta;
271 }
272
273 flags |= delta;
274 return wf_scale_mouse_event(wfc, flags, x, y);
275}
276
277static void wf_sizing(wfContext* wfc, WPARAM wParam, LPARAM lParam)
278{
279 rdpSettings* settings = wfc->common.context.settings;
280 // Holding the CTRL key down while resizing the window will force the desktop aspect ratio.
281 LPRECT rect;
282
283 if ((freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) ||
284 freerdp_settings_get_bool(settings, FreeRDP_DynamicResolutionUpdate)) &&
285 ctrl_down())
286 {
287 rect = (LPRECT)wParam;
288
289 switch (lParam)
290 {
291 case WMSZ_LEFT:
292 case WMSZ_RIGHT:
293 case WMSZ_BOTTOMRIGHT:
294 // Adjust height
295 rect->bottom =
296 rect->top + freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) *
297 (rect->right - rect->left) /
298 freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
299 break;
300
301 case WMSZ_TOP:
302 case WMSZ_BOTTOM:
303 case WMSZ_TOPRIGHT:
304 // Adjust width
305 rect->right =
306 rect->left + freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) *
307 (rect->bottom - rect->top) /
308 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
309 break;
310
311 case WMSZ_BOTTOMLEFT:
312 case WMSZ_TOPLEFT:
313 // adjust width
314 rect->left =
315 rect->right - (freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) *
316 (rect->bottom - rect->top) /
317 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
318 break;
319 }
320 }
321}
322
323static void wf_send_resize(wfContext* wfc)
324{
325 RECT windowRect;
326 int targetWidth = wfc->client_width;
327 int targetHeight = wfc->client_height;
328 rdpSettings* settings = wfc->common.context.settings;
329
330 if (freerdp_settings_get_bool(settings, FreeRDP_DynamicResolutionUpdate) && wfc->disp != NULL)
331 {
332 if (GetTickCount64() - wfc->lastSentDate > RESIZE_MIN_DELAY)
333 {
334 if (wfc->fullscreen)
335 {
336 GetWindowRect(wfc->hwnd, &windowRect);
337 targetWidth = windowRect.right - windowRect.left;
338 targetHeight = windowRect.bottom - windowRect.top;
339 }
340 if (freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingWidth) != targetWidth ||
341 freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingHeight) != targetHeight)
342 {
343 DISPLAY_CONTROL_MONITOR_LAYOUT layout = { 0 };
344
345 layout.Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
346 layout.Top = layout.Left = 0;
347 layout.Width = targetWidth;
348 layout.Height = targetHeight;
349 layout.Orientation =
350 freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation);
351 layout.DesktopScaleFactor =
352 freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
353 layout.DeviceScaleFactor =
354 freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
355 layout.PhysicalWidth = targetWidth;
356 layout.PhysicalHeight = targetHeight;
357
358 if (IFCALLRESULT(CHANNEL_RC_OK, wfc->disp->SendMonitorLayout, wfc->disp, 1,
359 &layout) != CHANNEL_RC_OK)
360 {
361 WLog_ERR("", "SendMonitorLayout failed.");
362 }
363 (void)freerdp_settings_set_uint32(settings, FreeRDP_SmartSizingWidth, targetWidth);
364 (void)freerdp_settings_set_uint32(settings, FreeRDP_SmartSizingHeight,
365 targetHeight);
366 }
367 wfc->lastSentDate = GetTickCount64();
368 }
369 }
370}
371
372LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
373{
374 HDC hdc = { 0 };
375 PAINTSTRUCT ps = { 0 };
376 BOOL processed = FALSE;
377 RECT windowRect = { 0 };
378 MINMAXINFO* minmax = NULL;
379 SCROLLINFO si = { 0 };
380 processed = TRUE;
381 LONG_PTR ptr = GetWindowLongPtr(hWnd, GWLP_USERDATA);
382 wfContext* wfc = (wfContext*)ptr;
383
384 if (wfc != NULL)
385 {
386 rdpInput* input = wfc->common.context.input;
387 rdpSettings* settings = wfc->common.context.settings;
388
389 if (!g_parent_hWnd && wfc->hWndParent)
390 g_parent_hWnd = wfc->hWndParent;
391
392 if (!g_main_hWnd)
393 g_main_hWnd = wfc->hwnd;
394
395 switch (Msg)
396 {
397 case WM_MOVE:
398 if (!wfc->disablewindowtracking)
399 {
400 int x = (int)(short)LOWORD(lParam);
401 int y = (int)(short)HIWORD(lParam);
402 wfc->client_x = x;
403 wfc->client_y = y;
404 }
405
406 break;
407
408 case WM_GETMINMAXINFO:
409 if (freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) ||
410 (freerdp_settings_get_bool(settings, FreeRDP_DynamicResolutionUpdate)))
411 {
412 processed = FALSE;
413 }
414 else
415 {
416 // Set maximum window size for resizing
417 minmax = (MINMAXINFO*)lParam;
418
419 // always use the last determined canvas diff, because it could be
420 // that the window is minimized when this gets called
421 // wf_update_canvas_diff(wfc);
422
423 if (!wfc->fullscreen)
424 {
425 // add window decoration
426 minmax->ptMaxTrackSize.x =
427 freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) +
428 wfc->diff.x;
429 minmax->ptMaxTrackSize.y =
430 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) +
431 wfc->diff.y;
432 }
433 }
434
435 break;
436
437 case WM_SIZING:
438 wf_sizing(wfc, lParam, wParam);
439 break;
440
441 case WM_SIZE:
442 GetWindowRect(wfc->hwnd, &windowRect);
443
444 if (!wfc->fullscreen)
445 {
446 wfc->client_width = LOWORD(lParam);
447 wfc->client_height = HIWORD(lParam);
448 wfc->client_x = windowRect.left;
449 wfc->client_y = windowRect.top;
450 }
451 else
452 {
453 wfc->wasMaximized = TRUE;
454 wf_send_resize(wfc);
455 }
456
457 if (wfc->client_width && wfc->client_height)
458 {
459 wf_size_scrollbars(wfc, LOWORD(lParam), HIWORD(lParam));
460
461 // Workaround: when the window is maximized, the call to "ShowScrollBars"
462 // returns TRUE but has no effect.
463 if (wParam == SIZE_MAXIMIZED && !wfc->fullscreen)
464 {
465 SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, windowRect.right - windowRect.left,
466 windowRect.bottom - windowRect.top,
467 SWP_NOMOVE | SWP_FRAMECHANGED);
468 wfc->wasMaximized = TRUE;
469 wf_send_resize(wfc);
470 }
471 else if (wParam == SIZE_RESTORED && !wfc->fullscreen && wfc->wasMaximized)
472 {
473 wfc->wasMaximized = FALSE;
474 wf_send_resize(wfc);
475 }
476 else if (wParam == SIZE_MINIMIZED)
477 {
478 g_focus_hWnd = NULL;
479 }
480 }
481
482 break;
483
484 case WM_EXITSIZEMOVE:
485 wf_size_scrollbars(wfc, wfc->client_width, wfc->client_height);
486 wf_send_resize(wfc);
487 break;
488
489 case WM_ERASEBKGND:
490 /* Say we handled it - prevents flickering */
491 return (LRESULT)1;
492
493 case WM_PAINT:
494 {
495 hdc = BeginPaint(hWnd, &ps);
496 const int x = ps.rcPaint.left;
497 const int y = ps.rcPaint.top;
498 const int w = ps.rcPaint.right - ps.rcPaint.left + 1;
499 const int h = ps.rcPaint.bottom - ps.rcPaint.top + 1;
500 wf_scale_blt(wfc, hdc, x, y, w, h, wfc->primary->hdc,
501 x - wfc->offset_x + wfc->xCurrentScroll,
502 y - wfc->offset_y + wfc->yCurrentScroll, SRCCOPY);
503 EndPaint(hWnd, &ps);
504 }
505 break;
506#if (_WIN32_WINNT >= 0x0500)
507
508 case WM_XBUTTONDOWN:
509 wf_scale_mouse_event_ex(wfc, PTR_XFLAGS_DOWN, GET_XBUTTON_WPARAM(wParam),
510 GET_X_LPARAM(lParam) - wfc->offset_x,
511 GET_Y_LPARAM(lParam) - wfc->offset_y);
512 break;
513
514 case WM_XBUTTONUP:
515 wf_scale_mouse_event_ex(wfc, 0, GET_XBUTTON_WPARAM(wParam),
516 GET_X_LPARAM(lParam) - wfc->offset_x,
517 GET_Y_LPARAM(lParam) - wfc->offset_y);
518 break;
519#endif
520
521 case WM_MBUTTONDOWN:
522 wf_scale_mouse_event(wfc, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3,
523 GET_X_LPARAM(lParam) - wfc->offset_x,
524 GET_Y_LPARAM(lParam) - wfc->offset_y);
525 break;
526
527 case WM_MBUTTONUP:
528 wf_scale_mouse_event(wfc, PTR_FLAGS_BUTTON3, GET_X_LPARAM(lParam) - wfc->offset_x,
529 GET_Y_LPARAM(lParam) - wfc->offset_y);
530 break;
531
532 case WM_LBUTTONDOWN:
533 wf_scale_mouse_event(wfc, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1,
534 GET_X_LPARAM(lParam) - wfc->offset_x,
535 GET_Y_LPARAM(lParam) - wfc->offset_y);
536 SetCapture(wfc->hwnd);
537 break;
538
539 case WM_LBUTTONUP:
540 wf_scale_mouse_event(wfc, PTR_FLAGS_BUTTON1, GET_X_LPARAM(lParam) - wfc->offset_x,
541 GET_Y_LPARAM(lParam) - wfc->offset_y);
542 ReleaseCapture();
543 break;
544
545 case WM_RBUTTONDOWN:
546 wf_scale_mouse_event(wfc, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2,
547 GET_X_LPARAM(lParam) - wfc->offset_x,
548 GET_Y_LPARAM(lParam) - wfc->offset_y);
549 break;
550
551 case WM_RBUTTONUP:
552 wf_scale_mouse_event(wfc, PTR_FLAGS_BUTTON2, GET_X_LPARAM(lParam) - wfc->offset_x,
553 GET_Y_LPARAM(lParam) - wfc->offset_y);
554 break;
555
556 case WM_MOUSEMOVE:
557 wf_scale_mouse_event(wfc, PTR_FLAGS_MOVE, GET_X_LPARAM(lParam) - wfc->offset_x,
558 GET_Y_LPARAM(lParam) - wfc->offset_y);
559 break;
560#if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
561
562 case WM_MOUSEWHEEL:
563 wf_event_process_WM_MOUSEWHEEL(wfc, hWnd, Msg, wParam, lParam, FALSE,
564 GET_X_LPARAM(lParam) - wfc->offset_x,
565 GET_Y_LPARAM(lParam) - wfc->offset_y);
566 break;
567#endif
568#if (_WIN32_WINNT >= 0x0600)
569
570 case WM_MOUSEHWHEEL:
571 wf_event_process_WM_MOUSEWHEEL(wfc, hWnd, Msg, wParam, lParam, TRUE,
572 GET_X_LPARAM(lParam) - wfc->offset_x,
573 GET_Y_LPARAM(lParam) - wfc->offset_y);
574 break;
575#endif
576
577 case WM_SETCURSOR:
578 if (LOWORD(lParam) == HTCLIENT)
579 SetCursor(wfc->cursor);
580 else
581 DefWindowProc(hWnd, Msg, wParam, lParam);
582
583 break;
584
585 case WM_HSCROLL:
586 {
587 int xDelta; // xDelta = new_pos - current_pos
588 int xNewPos; // new position
589 int yDelta = 0;
590
591 switch (LOWORD(wParam))
592 {
593 // User clicked the scroll bar shaft left of the scroll box.
594 case SB_PAGEUP:
595 xNewPos = wfc->xCurrentScroll - 50;
596 break;
597
598 // User clicked the scroll bar shaft right of the scroll box.
599 case SB_PAGEDOWN:
600 xNewPos = wfc->xCurrentScroll + 50;
601 break;
602
603 // User clicked the left arrow.
604 case SB_LINEUP:
605 xNewPos = wfc->xCurrentScroll - 5;
606 break;
607
608 // User clicked the right arrow.
609 case SB_LINEDOWN:
610 xNewPos = wfc->xCurrentScroll + 5;
611 break;
612
613 // User dragged the scroll box.
614 case SB_THUMBPOSITION:
615 xNewPos = HIWORD(wParam);
616 break;
617
618 // user is dragging the scrollbar
619 case SB_THUMBTRACK:
620 xNewPos = HIWORD(wParam);
621 break;
622
623 default:
624 xNewPos = wfc->xCurrentScroll;
625 }
626
627 // New position must be between 0 and the screen width.
628 xNewPos = MAX(0, xNewPos);
629 xNewPos = MIN(wfc->xMaxScroll, xNewPos);
630
631 // If the current position does not change, do not scroll.
632 if (xNewPos == wfc->xCurrentScroll)
633 break;
634
635 // Determine the amount scrolled (in pixels).
636 xDelta = xNewPos - wfc->xCurrentScroll;
637 // Reset the current scroll position.
638 wfc->xCurrentScroll = xNewPos;
639 // Scroll the window. (The system repaints most of the
640 // client area when ScrollWindowEx is called; however, it is
641 // necessary to call UpdateWindow in order to repaint the
642 // rectangle of pixels that were invalidated.)
643 ScrollWindowEx(wfc->hwnd, -xDelta, -yDelta, (CONST RECT*)NULL, (CONST RECT*)NULL,
644 (HRGN)NULL, (PRECT)NULL, SW_INVALIDATE);
645 UpdateWindow(wfc->hwnd);
646 // Reset the scroll bar.
647 si.cbSize = sizeof(si);
648 si.fMask = SIF_POS;
649 si.nPos = wfc->xCurrentScroll;
650 SetScrollInfo(wfc->hwnd, SB_HORZ, &si, TRUE);
651 }
652 break;
653
654 case WM_VSCROLL:
655 {
656 int xDelta = 0;
657 int yDelta; // yDelta = new_pos - current_pos
658 int yNewPos; // new position
659
660 switch (LOWORD(wParam))
661 {
662 // User clicked the scroll bar shaft above the scroll box.
663 case SB_PAGEUP:
664 yNewPos = wfc->yCurrentScroll - 50;
665 break;
666
667 // User clicked the scroll bar shaft below the scroll box.
668 case SB_PAGEDOWN:
669 yNewPos = wfc->yCurrentScroll + 50;
670 break;
671
672 // User clicked the top arrow.
673 case SB_LINEUP:
674 yNewPos = wfc->yCurrentScroll - 5;
675 break;
676
677 // User clicked the bottom arrow.
678 case SB_LINEDOWN:
679 yNewPos = wfc->yCurrentScroll + 5;
680 break;
681
682 // User dragged the scroll box.
683 case SB_THUMBPOSITION:
684 yNewPos = HIWORD(wParam);
685 break;
686
687 // user is dragging the scrollbar
688 case SB_THUMBTRACK:
689 yNewPos = HIWORD(wParam);
690 break;
691
692 default:
693 yNewPos = wfc->yCurrentScroll;
694 }
695
696 // New position must be between 0 and the screen height.
697 yNewPos = MAX(0, yNewPos);
698 yNewPos = MIN(wfc->yMaxScroll, yNewPos);
699
700 // If the current position does not change, do not scroll.
701 if (yNewPos == wfc->yCurrentScroll)
702 break;
703
704 // Determine the amount scrolled (in pixels).
705 yDelta = yNewPos - wfc->yCurrentScroll;
706 // Reset the current scroll position.
707 wfc->yCurrentScroll = yNewPos;
708 // Scroll the window. (The system repaints most of the
709 // client area when ScrollWindowEx is called; however, it is
710 // necessary to call UpdateWindow in order to repaint the
711 // rectangle of pixels that were invalidated.)
712 ScrollWindowEx(wfc->hwnd, -xDelta, -yDelta, (CONST RECT*)NULL, (CONST RECT*)NULL,
713 (HRGN)NULL, (PRECT)NULL, SW_INVALIDATE);
714 UpdateWindow(wfc->hwnd);
715 // Reset the scroll bar.
716 si.cbSize = sizeof(si);
717 si.fMask = SIF_POS;
718 si.nPos = wfc->yCurrentScroll;
719 SetScrollInfo(wfc->hwnd, SB_VERT, &si, TRUE);
720 }
721 break;
722
723 case WM_SYSCOMMAND:
724 {
725 if (wParam == SYSCOMMAND_ID_SMARTSIZING)
726 {
727 HMENU hMenu = GetSystemMenu(wfc->hwnd, FALSE);
728 const BOOL rc = freerdp_settings_get_bool(settings, FreeRDP_SmartSizing);
729 (void)freerdp_settings_set_bool(settings, FreeRDP_SmartSizing, !rc);
730 CheckMenuItem(hMenu, SYSCOMMAND_ID_SMARTSIZING,
731 freerdp_settings_get_bool(settings, FreeRDP_SmartSizing)
732 ? MF_CHECKED
733 : MF_UNCHECKED);
734 if (!freerdp_settings_get_bool(settings, FreeRDP_SmartSizing))
735 {
736 SetWindowPos(wfc->hwnd, HWND_TOP, -1, -1,
737 freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) +
738 wfc->diff.x,
739 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) +
740 wfc->diff.y,
741 SWP_NOMOVE);
742 }
743 else
744 {
745 wf_size_scrollbars(wfc, wfc->client_width, wfc->client_height);
746 wf_send_resize(wfc);
747 }
748 }
749 else if (wParam == SYSCOMMAND_ID_REQUEST_CONTROL)
750 {
751 freerdp_client_encomsp_set_control(wfc->common.encomsp, TRUE);
752 }
753 else
754 {
755 processed = FALSE;
756 }
757 }
758 break;
759
760 default:
761 processed = FALSE;
762 break;
763 }
764 }
765 else
766 {
767 processed = FALSE;
768 }
769
770 if (processed)
771 return 0;
772
773 switch (Msg)
774 {
775 case WM_DESTROY:
776 PostQuitMessage(WM_QUIT);
777 break;
778
779 case WM_SETFOCUS:
780 DEBUG_KBD("getting focus %X", hWnd);
781
782 (void)freerdp_settings_set_bool(wfc->common.context.settings, FreeRDP_SuspendInput,
783 FALSE);
784
785 if (alt_ctrl_down())
786 g_flipping_in = TRUE;
787
788 g_focus_hWnd = hWnd;
789 freerdp_set_focus(wfc->common.context.instance);
790 break;
791
792 case WM_KILLFOCUS:
793 (void)freerdp_settings_set_bool(wfc->common.context.settings, FreeRDP_SuspendInput,
794 TRUE);
795
796 if (g_focus_hWnd == hWnd && wfc && !wfc->fullscreen)
797 {
798 DEBUG_KBD("losing focus %X", hWnd);
799
800 if (alt_ctrl_down())
801 g_flipping_out = TRUE;
802 else
803 g_focus_hWnd = NULL;
804 }
805
806 break;
807
808 case WM_ACTIVATE:
809 {
810 int activate = (int)(short)LOWORD(wParam);
811 BOOL minimized_flag = (BOOL)HIWORD(wParam);
812
813 if (activate != WA_INACTIVE && !minimized_flag)
814 {
815 if (alt_ctrl_down())
816 g_flipping_in = TRUE;
817
818 g_focus_hWnd = hWnd;
819 }
820 else
821 {
822 if (alt_ctrl_down())
823 g_flipping_out = TRUE;
824 else
825 g_focus_hWnd = NULL;
826 }
827 }
828
829 default:
830 return DefWindowProc(hWnd, Msg, wParam, lParam);
831 break;
832 }
833
834 return 0;
835}
836
837BOOL wf_scale_blt(wfContext* wfc, HDC hdc, int x, int y, int w, int h, HDC hdcSrc, int x1, int y1,
838 DWORD rop)
839{
840 UINT32 ww, wh, dw, dh;
841 WINPR_ASSERT(wfc);
842
843 rdpSettings* settings = wfc->common.context.settings;
844 WINPR_ASSERT(settings);
845
846 if (!wfc->client_width)
847 wfc->client_width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
848
849 if (!wfc->client_height)
850 wfc->client_height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
851
852 ww = wfc->client_width;
853 wh = wfc->client_height;
854 dw = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
855 dh = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
856
857 if (!ww)
858 ww = dw;
859
860 if (!wh)
861 wh = dh;
862
863 if (wfc->fullscreen || !freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) ||
864 (ww == dw && wh == dh))
865 {
866 return BitBlt(hdc, x, y, w, h, wfc->primary->hdc, x1, y1, SRCCOPY);
867 }
868 else
869 {
870 SetStretchBltMode(hdc, HALFTONE);
871 SetBrushOrgEx(hdc, 0, 0, NULL);
872 return StretchBlt(hdc, 0, 0, ww, wh, wfc->primary->hdc, 0, 0, dw, dh, SRCCOPY);
873 }
874
875 return TRUE;
876}
877
878static BOOL wf_scale_mouse_pos(wfContext* wfc, INT32 x, INT32 y, UINT16* px, UINT16* py)
879{
880 int ww, wh, dw, dh;
881 rdpSettings* settings;
882
883 if (!wfc || !px || !py)
884 return FALSE;
885
886 settings = wfc->common.context.settings;
887
888 if (!settings)
889 return FALSE;
890
891 if (!wfc->client_width)
892 wfc->client_width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
893
894 if (!wfc->client_height)
895 wfc->client_height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
896
897 ww = wfc->client_width;
898 wh = wfc->client_height;
899 dw = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
900 dh = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
901
902 if (!freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) || ((ww == dw) && (wh == dh)))
903 {
904 x += wfc->xCurrentScroll;
905 y += wfc->yCurrentScroll;
906 }
907 else
908 {
909 x = x * dw / ww + wfc->xCurrentScroll;
910 y = y * dh / wh + wfc->yCurrentScroll;
911 }
912
913 *px = MIN(UINT16_MAX, MAX(0, x));
914 *py = MIN(UINT16_MAX, MAX(0, y));
915
916 return TRUE;
917}
918
919static BOOL wf_pub_mouse_event(wfContext* wfc, UINT16 flags, UINT16 x, UINT16 y)
920{
921 MouseEventEventArgs eventArgs = { 0 };
922
923 eventArgs.flags = flags;
924 eventArgs.x = x;
925 eventArgs.y = y;
926 PubSub_OnMouseEvent(wfc->common.context.pubSub, &wfc->common.context, &eventArgs);
927 return TRUE;
928}
929
930static BOOL wf_scale_mouse_event(wfContext* wfc, UINT16 flags, INT32 x, INT32 y)
931{
932 UINT16 px, py;
933
934 WINPR_ASSERT(wfc);
935
936 if (!wf_scale_mouse_pos(wfc, x, y, &px, &py))
937 return FALSE;
938
939 if (freerdp_client_send_button_event(&wfc->common, FALSE, flags, px, py))
940 return FALSE;
941
942 return wf_pub_mouse_event(wfc, flags, px, py);
943}
944
945#if (_WIN32_WINNT >= 0x0500)
946static BOOL wf_scale_mouse_event_ex(wfContext* wfc, UINT16 flags, UINT16 buttonMask, INT32 x,
947 INT32 y)
948{
949 UINT16 px, py;
950
951 WINPR_ASSERT(wfc);
952
953 if (buttonMask & XBUTTON1)
954 flags |= PTR_XFLAGS_BUTTON1;
955
956 if (buttonMask & XBUTTON2)
957 flags |= PTR_XFLAGS_BUTTON2;
958
959 if (!wf_scale_mouse_pos(wfc, x, y, &px, &py))
960 return FALSE;
961
962 if (freerdp_client_send_extended_button_event(&wfc->common, FALSE, flags, px, py))
963 return FALSE;
964
965 return wf_pub_mouse_event(wfc, flags, px, py);
966}
967#endif
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API UINT16 freerdp_settings_get_uint16(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt16 id)
Returns a UINT16 settings value.
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.