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 
   41static BOOL win_shadow_input_synchronize_event(rdpShadowSubsystem* subsystem,
 
   42                                               rdpShadowClient* client, UINT32 flags)
 
   44  WLog_WARN(TAG, 
"TODO: Implement!");
 
   48static 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));
 
   72static 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));
 
   94static 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));
 
  178static 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));
 
  223static 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));
 
  241static 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) 
  332static 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) 
  367static 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;
 
  420static 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;
 
  452static 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);
 
  473static 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);
 
  488static 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");
 
  505static int win_shadow_subsystem_stop(rdpShadowSubsystem* arg)
 
  507  winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
 
  515static void win_shadow_subsystem_free(rdpShadowSubsystem* arg)
 
  517  winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
 
  522  win_shadow_subsystem_uninit(arg);
 
  526static 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;
 
  542FREERDP_API 
const char* ShadowSubsystemName(
void)
 
  547FREERDP_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;