diff --git a/host/Capture/DXGI.cpp b/host/Capture/DXGI.cpp index 5d01863e..1b117044 100644 --- a/host/Capture/DXGI.cpp +++ b/host/Capture/DXGI.cpp @@ -350,20 +350,20 @@ size_t DXGI::GetMaxFrameSize() return (m_width * m_height * 4); } -GrabStatus Capture::DXGI::Capture() +unsigned int Capture::DXGI::Capture() { if (!m_initialized) return GRAB_STATUS_ERROR; CursorInfo cursor = { 0 }; - bool cursorUpdated = false; DXGI_OUTDUPL_FRAME_INFO frameInfo; IDXGIResourcePtr res; + unsigned int ret; HRESULT status; for (int retryCount = 0; retryCount < 2; ++retryCount) { - GrabStatus ret = ReleaseFrame(); + ret = ReleaseFrame(); if (ret != GRAB_STATUS_OK) return ret; @@ -396,7 +396,7 @@ GrabStatus Capture::DXGI::Capture() m_lastCursorX != frameInfo.PointerPosition.Position.x || m_lastCursorY != frameInfo.PointerPosition.Position.y ) { - cursorUpdated = true; + ret |= GRAB_STATUS_CURSOR; cursor.hasPos = true; cursor.x = m_lastCursorX = frameInfo.PointerPosition.Position.x; cursor.y = m_lastCursorY = frameInfo.PointerPosition.Position.y; @@ -404,12 +404,24 @@ GrabStatus Capture::DXGI::Capture() if (m_lastMouseVis != frameInfo.PointerPosition.Visible) { - cursorUpdated = true; + ret |= GRAB_STATUS_CURSOR; m_lastMouseVis = frameInfo.PointerPosition.Visible; } cursor.visible = m_lastMouseVis == TRUE; } + else + { + // always report the mouse position to prevent the guest losing sync (ie: dragging windows) + POINT curPos; + if (GetCursorPos(&curPos) && (curPos.x != m_lastCursorX || curPos.y != m_lastCursorY)) + { + ret |= GRAB_STATUS_CURSOR; + cursor.hasPos = true; + cursor.x = m_lastCursorX = curPos.x; + cursor.y = m_lastCursorY = curPos.y; + } + } // if the pointer shape has changed if (frameInfo.PointerShapeBufferSize > 0) @@ -442,7 +454,7 @@ GrabStatus Capture::DXGI::Capture() buf->pointerSize = 0; cursor.shape = buf; - cursorUpdated = true; + ret |= GRAB_STATUS_CURSOR; DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo; status = m_dup->GetFramePointerShape(buf->bufferSize, buf->buffer, &buf->pointerSize, &shapeInfo); @@ -467,7 +479,7 @@ GrabStatus Capture::DXGI::Capture() cursor.pitch = shapeInfo.Pitch; } - if (cursorUpdated) + if (ret & GRAB_STATUS_CURSOR) { // push the cursor update into the queue EnterCriticalSection(&m_cursorCS); @@ -479,20 +491,23 @@ GrabStatus Capture::DXGI::Capture() if (frameInfo.LastPresentTime.QuadPart == 0) { // if there is nothing to update, just start again - if (!cursorUpdated) + if (!ret) { --retryCount; continue; } res = NULL; - return GRAB_STATUS_CURSOR; + ret |= GRAB_STATUS_OK; + return ret; } // success, break out of the retry loop break; } + ret |= GRAB_STATUS_FRAME; + // ensure we have a frame if (!m_releaseFrame) { @@ -508,7 +523,8 @@ GrabStatus Capture::DXGI::Capture() return GRAB_STATUS_ERROR; } - return GRAB_STATUS_OK; + ret |= GRAB_STATUS_OK; + return ret; } GrabStatus Capture::DXGI::ReleaseFrame() diff --git a/host/Capture/DXGI.h b/host/Capture/DXGI.h index 8fbd1c39..0fb769b1 100644 --- a/host/Capture/DXGI.h +++ b/host/Capture/DXGI.h @@ -58,7 +58,7 @@ namespace Capture enum FrameType GetFrameType(); size_t GetMaxFrameSize(); - GrabStatus Capture(); + unsigned int Capture(); GrabStatus GetFrame (struct FrameInfo & frame ); bool GetCursor(CursorInfo & cursor); void FreeCursor(CursorInfo & cursor); diff --git a/host/ICapture.h b/host/ICapture.h index bddd8caf..9c0f0f72 100644 --- a/host/ICapture.h +++ b/host/ICapture.h @@ -54,11 +54,12 @@ struct FrameInfo enum GrabStatus { - GRAB_STATUS_OK, - GRAB_STATUS_TIMEOUT, - GRAB_STATUS_REINIT, - GRAB_STATUS_CURSOR, - GRAB_STATUS_ERROR + GRAB_STATUS_OK = 1, + GRAB_STATUS_TIMEOUT = 2, + GRAB_STATUS_REINIT = 4, + GRAB_STATUS_CURSOR = 8, + GRAB_STATUS_FRAME = 16, + GRAB_STATUS_ERROR = 32 }; typedef std::vector CaptureOptions; @@ -74,7 +75,7 @@ public: virtual bool ReInitialize() = 0; virtual enum FrameType GetFrameType() = 0; virtual size_t GetMaxFrameSize() = 0; - virtual enum GrabStatus Capture() = 0; + virtual unsigned int Capture() = 0; virtual enum GrabStatus GetFrame(struct FrameInfo & frame) = 0; virtual bool GetCursor(CursorInfo & cursor) = 0; virtual void FreeCursor(CursorInfo & cursor) = 0; diff --git a/host/Service.cpp b/host/Service.cpp index 6dda0430..5c71dee0 100644 --- a/host/Service.cpp +++ b/host/Service.cpp @@ -193,87 +193,88 @@ bool Service::Process() INTERLOCKED_AND8(flags, ~(KVMFR_HEADER_FLAG_RESTART)); } - GrabStatus result; - + unsigned int status; bool ok = false; - bool cursorOnly = false; bool repeat = false; + for(int i = 0; i < 2; ++i) { - // capture a frame of data - switch (m_capture->Capture()) + status = m_capture->Capture(); + if (status & GRAB_STATUS_OK) { - case GRAB_STATUS_OK: - ok = true; - break; - - case GRAB_STATUS_TIMEOUT: - if (m_haveFrame) - { - ok = true; - repeat = true; - break; - } - - // capture timeouts are not errors - --i; - continue; - - case GRAB_STATUS_CURSOR: - ok = true; - cursorOnly = true; - break; - - case GRAB_STATUS_ERROR: - DEBUG_ERROR("Capture failed"); - return false; - - case GRAB_STATUS_REINIT: - DEBUG_INFO("ReInitialize Requested"); - - INTERLOCKED_OR8(flags, KVMFR_HEADER_FLAG_PAUSED); - if(WTSGetActiveConsoleSessionId() != m_consoleSessionID) - { - DEBUG_INFO("User switch detected, waiting to regain control"); - while (WTSGetActiveConsoleSessionId() != m_consoleSessionID) - Sleep(100); - } - - while (!m_capture->CanInitialize()) - Sleep(100); - - if (!m_capture->ReInitialize()) - { - DEBUG_ERROR("ReInitialize Failed"); - return false; - } - - if (m_capture->GetMaxFrameSize() > m_frameSize) - { - DEBUG_ERROR("Maximum frame size of %zd bytes excceds maximum space available", m_capture->GetMaxFrameSize()); - return false; - } - - INTERLOCKED_AND8(flags, ~KVMFR_HEADER_FLAG_PAUSED); - - // re-init request should not count towards a failure to capture - --i; - continue; + ok = true; + break; } - if (ok) - break; + if (status & GRAB_STATUS_TIMEOUT) + { + if (m_haveFrame) + { + ok = true; + repeat = true; + break; + } + + // timeouts should not count towards a failure to capture + --i; + continue; + } + + if (status & GRAB_STATUS_ERROR) + { + DEBUG_ERROR("Capture failed, retrying"); + continue; + } + + if (status & GRAB_STATUS_REINIT) + { + DEBUG_INFO("ReInitialize Requested"); + + INTERLOCKED_OR8(flags, KVMFR_HEADER_FLAG_PAUSED); + if (WTSGetActiveConsoleSessionId() != m_consoleSessionID) + { + DEBUG_INFO("User switch detected, waiting to regain control"); + while (WTSGetActiveConsoleSessionId() != m_consoleSessionID) + Sleep(100); + } + + while (!m_capture->CanInitialize()) + Sleep(100); + + if (!m_capture->ReInitialize()) + { + DEBUG_ERROR("ReInitialize Failed"); + return false; + } + + if (m_capture->GetMaxFrameSize() > m_frameSize) + { + DEBUG_ERROR("Maximum frame size of %zd bytes excceds maximum space available", m_capture->GetMaxFrameSize()); + return false; + } + + INTERLOCKED_AND8(flags, ~KVMFR_HEADER_FLAG_PAUSED); + + // re-init request should not count towards a failure to capture + --i; + continue; + } + + DEBUG_ERROR("Capture interface returned an unexpected result"); + return false; } + if (!ok) { DEBUG_ERROR("Capture retry count exceeded"); return false; } - SetEvent(m_cursorEvent); + if (status & GRAB_STATUS_CURSOR) + SetEvent(m_cursorEvent); - if (!cursorOnly) + if (status & GRAB_STATUS_FRAME) { volatile KVMFRFrame * fi = &(m_shmHeader->frame); @@ -284,7 +285,7 @@ bool Service::Process() frame.buffer = m_frame[m_frameIndex]; frame.bufferSize = m_frameSize; - result = m_capture->GetFrame(frame); + GrabStatus result = m_capture->GetFrame(frame); if (result != GRAB_STATUS_OK) { DEBUG_INFO("GetFrame failed");