From 1ef61f6cd3957c93793d50f8a21401847c9f3863 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Fri, 11 Jan 2019 23:58:50 +1100 Subject: [PATCH] [host] use a global hook to obtain cursor move pos --- host/Capture/DXGI.cpp | 20 ------------ host/Capture/DXGI.h | 1 - host/Capture/NvFBC.cpp | 15 ++++++++- host/Capture/NvFBC.h | 1 + host/Service.cpp | 71 +++++++++++++++++++++--------------------- host/Service.h | 31 ++++++++++++++---- host/main.cpp | 65 ++++++++++++++++++++++++++++---------- 7 files changed, 124 insertions(+), 80 deletions(-) diff --git a/host/Capture/DXGI.cpp b/host/Capture/DXGI.cpp index 50de68bb..e3e364b5 100644 --- a/host/Capture/DXGI.cpp +++ b/host/Capture/DXGI.cpp @@ -539,8 +539,6 @@ unsigned int Capture::DXGI::Capture() cursor.w = shapeInfo.Width; cursor.h = shapeInfo.Height; cursor.pitch = shapeInfo.Pitch; - m_hotSpot.x = shapeInfo.HotSpot.x; - m_hotSpot.y = shapeInfo.HotSpot.y; } // if we have a mouse update @@ -556,24 +554,6 @@ unsigned int Capture::DXGI::Capture() cursor.y = m_lastCursorY = frameInfo.PointerPosition.Position.y; } } - else - { - // always report the mouse position to prevent the guest losing sync (ie: dragging windows) - POINT curPos; - if (GetCursorPos(&curPos)) - { - curPos.x -= m_hotSpot.x; - curPos.y -= m_hotSpot.y; - - if (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 (m_lastMouseVis != frameInfo.PointerPosition.Visible) m_lastMouseVis = frameInfo.PointerPosition.Visible; diff --git a/host/Capture/DXGI.h b/host/Capture/DXGI.h index 16de53ad..c1873869 100644 --- a/host/Capture/DXGI.h +++ b/host/Capture/DXGI.h @@ -102,6 +102,5 @@ namespace Capture int m_lastCursorX, m_lastCursorY; BOOL m_lastMouseVis; - POINT m_hotSpot; }; }; \ No newline at end of file diff --git a/host/Capture/NvFBC.cpp b/host/Capture/NvFBC.cpp index 3dc28652..394c3b83 100644 --- a/host/Capture/NvFBC.cpp +++ b/host/Capture/NvFBC.cpp @@ -41,6 +41,7 @@ NvFBC::NvFBC() : m_optNoCrop(false), m_optNoWait(false), m_initialized(false), + m_first(true), m_hDLL(NULL), m_nvFBC(NULL) { @@ -60,6 +61,7 @@ bool NvFBC::Initialize(CaptureOptions * options) if (m_initialized) DeInitialize(); + m_first = true; m_options = options; m_optNoCrop = false; @@ -345,7 +347,11 @@ unsigned int Capture::NvFBC::Capture() return GRAB_STATUS_REINIT; } - return GRAB_STATUS_OK | GRAB_STATUS_FRAME; + // turn off the cursor on the first frame as NvFBC is drawing it + if (m_first) + return GRAB_STATUS_OK | GRAB_STATUS_FRAME | GRAB_STATUS_CURSOR; + else + return GRAB_STATUS_OK | GRAB_STATUS_FRAME; } bool Capture::NvFBC::GetCursor(CursorInfo & cursor) @@ -353,6 +359,13 @@ bool Capture::NvFBC::GetCursor(CursorInfo & cursor) cursor.hasShape = false; cursor.hasPos = false; cursor.visible = false; + + if (m_first) + { + m_first = false; + return true; + } + return false; } diff --git a/host/Capture/NvFBC.h b/host/Capture/NvFBC.h index fa8ce3bc..efa71ea7 100644 --- a/host/Capture/NvFBC.h +++ b/host/Capture/NvFBC.h @@ -59,6 +59,7 @@ namespace Capture bool m_optNoWait; bool m_initialized; + bool m_first; HMODULE m_hDLL; NvFBC_CreateFunctionExType m_fnCreateEx; diff --git a/host/Service.cpp b/host/Service.cpp index df2d77db..0e6d7b09 100644 --- a/host/Service.cpp +++ b/host/Service.cpp @@ -27,8 +27,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "Util.h" #include "CaptureFactory.h" -Service * Service::m_instance = NULL; - Service::Service() : m_initialized(false), m_memory(NULL), @@ -41,10 +39,39 @@ Service::Service() : { m_consoleSessionID = WTSGetActiveConsoleSessionId(); m_ivshmem = IVSHMEM::Get(); + + if (!m_ivshmem->Initialize()) + throw "IVSHMEM failed to initalize"; + + if (m_ivshmem->GetSize() < sizeof(KVMFRHeader)) + throw "Shared memory is not large enough for the KVMFRHeader"; + + m_memory = static_cast(m_ivshmem->GetMemory()); + if (!m_memory) + throw "Failed to get IVSHMEM memory"; + + if (!InitPointers()) + throw "Failed to initialize the shared memory pointers"; } Service::~Service() { + DeInitialize(); +} + +LRESULT Service::LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + if (nCode == HC_ACTION && wParam == WM_MOUSEMOVE) + { + MSLLHOOKSTRUCT *msg = (MSLLHOOKSTRUCT *)lParam; + volatile KVMFRCursor * cursor = &(m_shmHeader->cursor); + volatile char * flags = (volatile char *)&(cursor->flags); + + cursor->x = msg->pt.x; + cursor->y = msg->pt.y; + INTERLOCKED_OR8(flags, KVMFR_CURSOR_FLAG_POS); + } + return CallNextHookEx(m_mouseHook, nCode, wParam, lParam); } bool Service::Initialize(ICapture * captureDevice) @@ -52,35 +79,8 @@ bool Service::Initialize(ICapture * captureDevice) if (m_initialized) DeInitialize(); - m_tryTarget = 0; - m_capture = captureDevice; - if (!m_ivshmem->Initialize()) - { - DEBUG_ERROR("IVSHMEM failed to initalize"); - DeInitialize(); - return false; - } - - if (m_ivshmem->GetSize() < sizeof(KVMFRHeader)) - { - DEBUG_ERROR("Shared memory is not large enough for the KVMFRHeader"); - DeInitialize(); - return false; - } - - m_memory = static_cast(m_ivshmem->GetMemory()); - if (!m_memory) - { - DEBUG_ERROR("Failed to get IVSHMEM memory"); - DeInitialize(); - return false; - } - - if (!InitPointers()) - { - DeInitialize(); - return false; - } + m_tryTarget = 0; + m_capture = captureDevice; if (m_capture->GetMaxFrameSize() > m_frameSize) { @@ -90,7 +90,7 @@ bool Service::Initialize(ICapture * captureDevice) } // Create the cursor thread - m_cursorThread = CreateThread(NULL, 0, _CursorThread, this, 0, NULL); + m_cursorThread = CreateThread(NULL, 0, _CursorThread, NULL, 0, NULL); m_cursorEvent = CreateEvent (NULL, FALSE, FALSE, L"CursorEvent"); InitializeCriticalSection(&m_cursorCS); @@ -340,21 +340,20 @@ DWORD Service::CursorThread() { volatile KVMFRCursor * cursor = &(m_shmHeader->cursor); // wait until the client is ready - while (cursor->flags != 0) + while ((cursor->flags & ~KVMFR_CURSOR_FLAG_POS) != 0) { Sleep(1); if (!m_capture) return 0; } - uint8_t flags = 0; + uint8_t flags = cursor->flags; if (ci.hasPos) { - // tell the client where the cursor is - flags |= KVMFR_CURSOR_FLAG_POS; cursor->x = ci.x; cursor->y = ci.y; + flags |= KVMFR_CURSOR_FLAG_POS; } if (ci.hasShape) diff --git a/host/Service.h b/host/Service.h index 18c1ee46..1e653586 100644 --- a/host/Service.h +++ b/host/Service.h @@ -25,6 +25,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "IVSHMEM.h" #include "ICapture.h" +#include "common/debug.h" #define MAX_FRAMES 2 @@ -38,11 +39,26 @@ enum ProcessStatus class Service { public: - static Service * Get() + static Service & Instance() { - if (!m_instance) - m_instance = new Service(); - return m_instance; + static Service service; + return service; + } + + static void InstallHook() + { + if (Instance().m_mouseHook) + RemoveHook(); + Instance().m_mouseHook = SetWindowsHookEx(WH_MOUSE_LL, _LowLevelMouseProc, NULL, 0); + } + + static void RemoveHook() + { + if (Instance().m_mouseHook) + { + UnhookWindowsHookEx(Instance().m_mouseHook); + Instance().m_mouseHook = NULL; + } } bool Initialize(ICapture * captureDevice); @@ -52,13 +68,16 @@ public: private: bool InitPointers(); - static Service * m_instance; int m_tryTarget; int m_lastTryCount; Service(); ~Service(); + HHOOK m_mouseHook; + LRESULT LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam); + static LRESULT WINAPI _LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) { return Service::Instance().LowLevelMouseProc(nCode, wParam, lParam); } + bool ReInit(volatile char * flags); bool m_initialized; @@ -77,7 +96,7 @@ private: uint64_t m_dataOffset[MAX_FRAMES]; int m_frameIndex; - static DWORD WINAPI _CursorThread(LPVOID lpParameter) { return ((Service *)lpParameter)->CursorThread(); } + static DWORD WINAPI _CursorThread(LPVOID lpParameter) { return Service::Instance().CursorThread(); } DWORD CursorThread(); HANDLE m_cursorThread; diff --git a/host/main.cpp b/host/main.cpp index 22e24055..419d43ce 100644 --- a/host/main.cpp +++ b/host/main.cpp @@ -34,11 +34,13 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include int parseArgs(struct StartupArgs & args); -int run(struct StartupArgs & args); +static DWORD WINAPI CaptureThread(LPVOID lpParameter); +int run(); void doHelp(); void doLicense(); +bool running = true; bool consoleActive = false; void setupConsole(); @@ -50,6 +52,7 @@ struct StartupArgs const char * captureDevice; CaptureOptions captureOptions; }; +struct StartupArgs args; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdParam, int iCmdShow) { @@ -57,21 +60,41 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdParam TraceUtil::Initialize(); CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); - struct StartupArgs args; args.foreground = false; args.captureDevice = NULL; - int ret = parseArgs(args); - if (ret == 0) + if (ret != 0) + fprintf(stderr, "Failed to parse command line arguments\n"); + else { - ret = run(args); - if (ret != 0) + if (args.foreground) + setupConsole(); + + Service::InstallHook(); + HANDLE captureThread = CreateThread(NULL, 0, CaptureThread, NULL, 0, NULL); + while (running) { - if (!args.foreground) + MSG msg; + BOOL bRet = GetMessage(&msg, NULL, 0, 0); + if (bRet == -1 || bRet == 0) { - setupConsole(); - fprintf(stderr, "An error occurred, re-run in forground mode (-f) for more information\n"); + ret = msg.wParam; + break; } + DispatchMessage(&msg); + } + Service::RemoveHook(); + running = false; + ret = WaitForSingleObject(captureThread, INFINITE); + CloseHandle(captureThread); + } + + if (ret != 0) + { + if (!args.foreground) + { + setupConsole(); + fprintf(stderr, "An error occurred, re-run in forground mode (-f) for more information\n"); } } @@ -85,11 +108,21 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdParam return ret; } -int run(struct StartupArgs & args) +static DWORD WINAPI CaptureThread(LPVOID lpParameter) { - if (args.foreground) - setupConsole(); + int ret = 0; + while (running) + { + ret = run(); + if (ret != 0) + break; + } + running = false; + return ret; +} +int run() +{ /* increase the system timer resolution */ ULONG currentRes; NtSetTimerResolution(0, TRUE, ¤tRes); @@ -124,15 +157,15 @@ int run(struct StartupArgs & args) return -1; } - Service *svc = svc->Get(); - if (!svc->Initialize(captureDevice)) + Service &svc = Service::Instance(); + if (!svc.Initialize(captureDevice)) return -1; int retry = 0; bool running = true; while (running) { - switch (svc->Process()) + switch (svc.Process()) { case PROCESS_STATUS_OK: retry = 0; @@ -152,7 +185,7 @@ int run(struct StartupArgs & args) } } - svc->DeInitialize(); + svc.DeInitialize(); if (task) AvRevertMmThreadCharacteristics(task);