21 #include <winpr/crt.h>
22 #include <winpr/synch.h>
23 #include <winpr/sysinfo.h>
25 #include <freerdp/log.h>
26 #include <freerdp/codec/color.h>
27 #include <freerdp/codec/region.h>
28 #include <freerdp/server/server-common.h>
30 #include "win_shadow.h"
32 #define TAG SERVER_TAG("shadow.win")
37 #ifndef MOUSEEVENTF_HWHEEL
38 #define MOUSEEVENTF_HWHEEL 0x1000
41 static BOOL win_shadow_input_synchronize_event(rdpShadowSubsystem* subsystem,
42 rdpShadowClient* client, UINT32 flags)
44 WLog_WARN(TAG,
"TODO: Implement!");
48 static BOOL win_shadow_input_keyboard_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
49 UINT16 flags, UINT8 code)
53 event.type = INPUT_KEYBOARD;
55 event.ki.wScan = code;
56 event.ki.dwFlags = KEYEVENTF_SCANCODE;
57 event.ki.dwExtraInfo = 0;
60 if (flags & KBD_FLAGS_RELEASE)
61 event.ki.dwFlags |= KEYEVENTF_KEYUP;
63 if (flags & KBD_FLAGS_EXTENDED)
64 event.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
66 rc = SendInput(1, &event,
sizeof(INPUT));
72 static BOOL win_shadow_input_unicode_keyboard_event(rdpShadowSubsystem* subsystem,
73 rdpShadowClient* client, UINT16 flags,
78 event.type = INPUT_KEYBOARD;
80 event.ki.wScan = code;
81 event.ki.dwFlags = KEYEVENTF_UNICODE;
82 event.ki.dwExtraInfo = 0;
85 if (flags & KBD_FLAGS_RELEASE)
86 event.ki.dwFlags |= KEYEVENTF_KEYUP;
88 rc = SendInput(1, &event,
sizeof(INPUT));
94 static BOOL win_shadow_input_mouse_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
95 UINT16 flags, UINT16 x, UINT16 y)
102 event.type = INPUT_MOUSE;
104 if (flags & (PTR_FLAGS_WHEEL | PTR_FLAGS_HWHEEL))
106 if (flags & PTR_FLAGS_WHEEL)
107 event.mi.dwFlags = MOUSEEVENTF_WHEEL;
109 event.mi.dwFlags = MOUSEEVENTF_HWHEEL;
110 event.mi.mouseData = flags & WheelRotationMask;
112 if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
113 event.mi.mouseData *= -1;
115 rc = SendInput(1, &event,
sizeof(INPUT));
121 #if (_WIN32_WINNT < 0x0600)
122 if (flags & PTR_FLAGS_HWHEEL)
128 width = (float)GetSystemMetrics(SM_CXSCREEN);
129 height = (float)GetSystemMetrics(SM_CYSCREEN);
130 event.mi.dx = (LONG)((
float)x * (65535.0f / width));
131 event.mi.dy = (LONG)((
float)y * (65535.0f / height));
132 event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE;
134 if (flags & PTR_FLAGS_MOVE)
136 event.mi.dwFlags |= MOUSEEVENTF_MOVE;
137 rc = SendInput(1, &event,
sizeof(INPUT));
142 event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE;
144 if (flags & PTR_FLAGS_BUTTON1)
146 if (flags & PTR_FLAGS_DOWN)
147 event.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
149 event.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
151 rc = SendInput(1, &event,
sizeof(INPUT));
153 else if (flags & PTR_FLAGS_BUTTON2)
155 if (flags & PTR_FLAGS_DOWN)
156 event.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
158 event.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
160 rc = SendInput(1, &event,
sizeof(INPUT));
162 else if (flags & PTR_FLAGS_BUTTON3)
164 if (flags & PTR_FLAGS_DOWN)
165 event.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
167 event.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
169 rc = SendInput(1, &event,
sizeof(INPUT));
178 static BOOL win_shadow_input_extended_mouse_event(rdpShadowSubsystem* subsystem,
179 rdpShadowClient* client, UINT16 flags, UINT16 x,
187 if ((flags & PTR_XFLAGS_BUTTON1) || (flags & PTR_XFLAGS_BUTTON2))
189 event.type = INPUT_MOUSE;
191 if (flags & PTR_FLAGS_MOVE)
193 width = (float)GetSystemMetrics(SM_CXSCREEN);
194 height = (float)GetSystemMetrics(SM_CYSCREEN);
195 event.mi.dx = (LONG)((
float)x * (65535.0f / width));
196 event.mi.dy = (LONG)((
float)y * (65535.0f / height));
197 event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
198 rc = SendInput(1, &event,
sizeof(INPUT));
203 event.mi.dx =
event.mi.dy =
event.mi.dwFlags = 0;
205 if (flags & PTR_XFLAGS_DOWN)
206 event.mi.dwFlags |= MOUSEEVENTF_XDOWN;
208 event.mi.dwFlags |= MOUSEEVENTF_XUP;
210 if (flags & PTR_XFLAGS_BUTTON1)
211 event.mi.mouseData = XBUTTON1;
212 else if (flags & PTR_XFLAGS_BUTTON2)
213 event.mi.mouseData = XBUTTON2;
215 rc = SendInput(1, &event,
sizeof(INPUT));
223 static int win_shadow_invalidate_region(winShadowSubsystem* subsystem,
int x,
int y,
int width,
226 rdpShadowServer* server;
227 rdpShadowSurface* surface;
229 server = subsystem->base.server;
230 surface = server->surface;
231 invalidRect.left = x;
233 invalidRect.right = x + width;
234 invalidRect.bottom = y + height;
235 EnterCriticalSection(&(surface->lock));
236 region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
237 LeaveCriticalSection(&(surface->lock));
241 static int win_shadow_surface_copy(winShadowSubsystem* subsystem)
250 BYTE* pDstData = NULL;
251 rdpShadowServer* server;
252 rdpShadowSurface* surface;
256 server = subsystem->base.server;
257 surface = server->surface;
259 if (ArrayList_Count(server->clients) < 1)
262 surfaceRect.left = surface->x;
263 surfaceRect.top = surface->y;
264 surfaceRect.right = surface->x + surface->width;
265 surfaceRect.bottom = surface->y + surface->height;
266 region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
268 if (region16_is_empty(&(surface->invalidRegion)))
271 extents = region16_extents(&(surface->invalidRegion));
272 CopyMemory(&invalidRect, extents,
sizeof(
RECTANGLE_16));
273 shadow_capture_align_clip_rect(&invalidRect, &surfaceRect);
274 x = invalidRect.left;
276 width = invalidRect.right - invalidRect.left;
277 height = invalidRect.bottom - invalidRect.top;
283 width = surface->width;
284 height = surface->height;
287 WLog_INFO(TAG,
"SurfaceCopy x: %d y: %d width: %d height: %d right: %d bottom: %d", x, y, width,
288 height, x + width, y + height);
289 #if defined(WITH_WDS_API)
295 WINPR_ASSERT(subsystem);
296 shw = subsystem->shw;
299 context = &shw->common.context;
300 WINPR_ASSERT(context);
305 pDstData = gdi->primary_buffer;
306 nDstStep = gdi->width * 4;
307 DstFormat = gdi->dstFormat;
309 #elif defined(WITH_DXGI_1_2)
310 DstFormat = PIXEL_FORMAT_BGRX32;
311 status = win_shadow_dxgi_fetch_frame_data(subsystem, &pDstData, &nDstStep, x, y, width, height);
317 if (!freerdp_image_copy_no_overlap(surface->data, surface->format, surface->scanline, x, y,
318 width, height, pDstData, DstFormat, nDstStep, x, y, NULL,
320 return ERROR_INTERNAL_ERROR;
322 ArrayList_Lock(server->clients);
323 count = ArrayList_Count(server->clients);
324 shadow_subsystem_frame_update(&subsystem->base);
325 ArrayList_Unlock(server->clients);
326 region16_clear(&(surface->invalidRegion));
330 #if defined(WITH_WDS_API)
332 static DWORD WINAPI win_shadow_subsystem_thread(LPVOID arg)
334 winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
339 StopEvent = subsystem->base.server->StopEvent;
341 events[nCount++] = StopEvent;
342 events[nCount++] = subsystem->RdpUpdateEnterEvent;
346 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
348 if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0)
353 if (WaitForSingleObject(subsystem->RdpUpdateEnterEvent, 0) == WAIT_OBJECT_0)
355 win_shadow_surface_copy(subsystem);
356 (void)ResetEvent(subsystem->RdpUpdateEnterEvent);
357 (void)SetEvent(subsystem->RdpUpdateLeaveEvent);
365 #elif defined(WITH_DXGI_1_2)
367 static DWORD WINAPI win_shadow_subsystem_thread(LPVOID arg)
369 winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
379 StopEvent = subsystem->server->StopEvent;
381 events[nCount++] = StopEvent;
383 dwInterval = 1000 / fps;
384 frameTime = GetTickCount64() + dwInterval;
388 dwTimeout = INFINITE;
389 cTime = GetTickCount64();
390 dwTimeout = (DWORD)((cTime > frameTime) ? 0 : frameTime - cTime);
391 status = WaitForMultipleObjects(nCount, events, FALSE, dwTimeout);
393 if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0)
398 if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime))
401 dxgi_status = win_shadow_dxgi_get_next_frame(subsystem);
404 dxgi_status = win_shadow_dxgi_get_invalid_region(subsystem);
407 win_shadow_surface_copy(subsystem);
409 dwInterval = 1000 / fps;
410 frameTime += dwInterval;
420 static UINT32 win_shadow_enum_monitors(
MONITOR_DEF* monitors, UINT32 maxMonitors)
429 DISPLAY_DEVICE displayDevice = { 0 };
431 displayDevice.cb =
sizeof(DISPLAY_DEVICE);
433 if (EnumDisplayDevices(NULL, iDevNum, &displayDevice, 0))
435 hdc = CreateDC(displayDevice.DeviceName, NULL, NULL, NULL);
436 desktopWidth = GetDeviceCaps(hdc, HORZRES);
437 desktopHeight = GetDeviceCaps(hdc, VERTRES);
440 monitor = &monitors[index];
443 monitor->right = desktopWidth;
444 monitor->bottom = desktopHeight;
452 static int win_shadow_subsystem_init(rdpShadowSubsystem* arg)
454 winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
457 subsystem->base.numMonitors = win_shadow_enum_monitors(subsystem->base.monitors, 16);
458 #if defined(WITH_WDS_API)
459 status = win_shadow_wds_init(subsystem);
460 #elif defined(WITH_DXGI_1_2)
461 status = win_shadow_dxgi_init(subsystem);
463 virtualScreen = &(subsystem->base.virtualScreen);
464 virtualScreen->left = 0;
465 virtualScreen->top = 0;
466 virtualScreen->right = subsystem->width;
467 virtualScreen->bottom = subsystem->height;
468 virtualScreen->flags = 1;
469 WLog_INFO(TAG,
"width: %d height: %d", subsystem->width, subsystem->height);
473 static int win_shadow_subsystem_uninit(rdpShadowSubsystem* arg)
475 winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
480 #if defined(WITH_WDS_API)
481 win_shadow_wds_uninit(subsystem);
482 #elif defined(WITH_DXGI_1_2)
483 win_shadow_dxgi_uninit(subsystem);
488 static int win_shadow_subsystem_start(rdpShadowSubsystem* arg)
490 winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
496 if (!(thread = CreateThread(NULL, 0, win_shadow_subsystem_thread, (
void*)subsystem, 0, NULL)))
498 WLog_ERR(TAG,
"Failed to create thread");
505 static int win_shadow_subsystem_stop(rdpShadowSubsystem* arg)
507 winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
515 static void win_shadow_subsystem_free(rdpShadowSubsystem* arg)
517 winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
522 win_shadow_subsystem_uninit(arg);
526 static rdpShadowSubsystem* win_shadow_subsystem_new(
void)
528 winShadowSubsystem* subsystem;
529 subsystem = (winShadowSubsystem*)calloc(1,
sizeof(winShadowSubsystem));
534 subsystem->base.SynchronizeEvent = win_shadow_input_synchronize_event;
535 subsystem->base.KeyboardEvent = win_shadow_input_keyboard_event;
536 subsystem->base.UnicodeKeyboardEvent = win_shadow_input_unicode_keyboard_event;
537 subsystem->base.MouseEvent = win_shadow_input_mouse_event;
538 subsystem->base.ExtendedMouseEvent = win_shadow_input_extended_mouse_event;
539 return &subsystem->base;
542 FREERDP_API
const char* ShadowSubsystemName(
void)
547 FREERDP_API
int ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints)
549 const char name[] =
"windows shadow subsystem";
550 const char* arg[] = { name };
552 freerdp_server_warn_unmaintained(ARRAYSIZE(arg), arg);
553 pEntryPoints->New = win_shadow_subsystem_new;
554 pEntryPoints->Free = win_shadow_subsystem_free;
555 pEntryPoints->Init = win_shadow_subsystem_init;
556 pEntryPoints->Uninit = win_shadow_subsystem_uninit;
557 pEntryPoints->Start = win_shadow_subsystem_start;
558 pEntryPoints->Stop = win_shadow_subsystem_stop;
559 pEntryPoints->EnumMonitors = win_shadow_enum_monitors;