From 0cac3e1c40ff6e03a11d2f5ac7f4353e96497c18 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Wed, 10 Apr 2019 21:07:56 +1000 Subject: [PATCH] [c-host] tons of windows specific fixes --- VERSION | 2 +- c-host/include/interface/capture.h | 1 + c-host/include/interface/platform.h | 1 + c-host/looking-glass-host | Bin 74712 -> 0 bytes c-host/platform/Windows/CMakeLists.txt | 11 +- c-host/platform/Windows/app.manifest | 12 +++ .../platform/Windows/capture/DXGI/src/dxgi.c | 39 +++---- .../Windows/capture/NVFBC/CMakeLists.txt | 4 + .../Windows/capture/NVFBC/src/nvfbc.c | 83 +++++++++------ .../Windows/include/windows/mousehook.h | 23 ++++ .../Windows/include/windows/platform.h | 23 ++++ c-host/platform/Windows/resource.rc | 3 + c-host/platform/Windows/src/mousehook.c | 98 ++++++++++++++++++ c-host/platform/Windows/src/platform.c | 72 +++++++++++++ c-host/platform/Windows/src/platform.h | 32 ++++++ c-host/src/app.c | 1 + 16 files changed, 346 insertions(+), 59 deletions(-) delete mode 100755 c-host/looking-glass-host create mode 100644 c-host/platform/Windows/app.manifest create mode 100644 c-host/platform/Windows/include/windows/mousehook.h create mode 100644 c-host/platform/Windows/include/windows/platform.h create mode 100644 c-host/platform/Windows/resource.rc create mode 100644 c-host/platform/Windows/src/mousehook.c create mode 100644 c-host/platform/Windows/src/platform.h diff --git a/VERSION b/VERSION index 5f4d0e5a..e28124f0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -a12-135-gd6805cfa0f+1 \ No newline at end of file +a12-142-g3f13485ced+1 \ No newline at end of file diff --git a/c-host/include/interface/capture.h b/c-host/include/interface/capture.h index 69bc9768..9a48892e 100644 --- a/c-host/include/interface/capture.h +++ b/c-host/include/interface/capture.h @@ -76,6 +76,7 @@ typedef struct CaptureInterface const char * (*getName )(); bool (*create )(); bool (*init )(void * pointerShape, const unsigned int pointerSize); + void (*stop )(); bool (*deinit )(); void (*free )(); unsigned int (*getMaxFrameSize)(); diff --git a/c-host/include/interface/platform.h b/c-host/include/interface/platform.h index 6064f344..ec65349c 100644 --- a/c-host/include/interface/platform.h +++ b/c-host/include/interface/platform.h @@ -47,5 +47,6 @@ typedef struct osEventHandle osEventHandle; osEventHandle * os_createEvent(bool autoReset); void os_freeEvent (osEventHandle * handle); bool os_waitEvent (osEventHandle * handle, unsigned int timeout); +bool os_waitEvents (osEventHandle * handles[], int count, bool waitAll, unsigned int timeout); bool os_signalEvent(osEventHandle * handle); bool os_resetEvent (osEventHandle * handle); \ No newline at end of file diff --git a/c-host/looking-glass-host b/c-host/looking-glass-host deleted file mode 100755 index e71e951fe92cb470ef7f10118a584200d67da55b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74712 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 + + + Hello World + + + + + + + + diff --git a/c-host/platform/Windows/capture/DXGI/src/dxgi.c b/c-host/platform/Windows/capture/DXGI/src/dxgi.c index 11d5a1f3..32be656f 100644 --- a/c-host/platform/Windows/capture/DXGI/src/dxgi.c +++ b/c-host/platform/Windows/capture/DXGI/src/dxgi.c @@ -55,7 +55,7 @@ Pointer; struct iface { bool initialized; - bool reinit; + bool stop; IDXGIFactory1 * factory; IDXGIAdapter1 * adapter; IDXGIOutput * output; @@ -158,7 +158,7 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize) this->pointerSize = pointerSize; this->pointerUsed = 0; - this->reinit = false; + this->stop = false; this->texRIndex = 0; this->texWIndex = 0; os_resetEvent(this->frameEvent); @@ -402,6 +402,13 @@ fail: return false; } +static void dxgi_stop() +{ + this->stop = true; + os_signalEvent(this->frameEvent ); + os_signalEvent(this->pointerEvent); +} + static bool dxgi_deinit() { assert(this); @@ -497,7 +504,7 @@ static unsigned int dxgi_getMaxFrameSize() return this->height * this->pitch; } -inline static CaptureResult dxgi_capture_int() +static CaptureResult dxgi_capture() { assert(this); assert(this->initialized); @@ -641,36 +648,18 @@ inline static CaptureResult dxgi_capture_int() return CAPTURE_RESULT_OK; } -static CaptureResult dxgi_capture(bool * hasFrameUpdate, bool * hasPointerUpdate) -{ - CaptureResult result = dxgi_capture_int(hasFrameUpdate, hasPointerUpdate); - - // signal pending events if the result was any form of failure or reinit - if (result != CAPTURE_RESULT_OK && result != CAPTURE_RESULT_TIMEOUT) - { - this->reinit = true; - os_signalEvent(this->frameEvent ); - os_signalEvent(this->pointerEvent); - } - - return result; -} - static CaptureResult dxgi_getFrame(CaptureFrame * frame) { assert(this); assert(this->initialized); - if (this->reinit) - return CAPTURE_RESULT_REINIT; - if (!os_waitEvent(this->frameEvent, TIMEOUT_INFINITE)) { DEBUG_ERROR("Failed to wait on the frame event"); return CAPTURE_RESULT_ERROR; } - if (this->reinit) + if (this->stop) return CAPTURE_RESULT_REINIT; Texture * tex = &this->texture[this->texRIndex]; @@ -695,16 +684,13 @@ static CaptureResult dxgi_getPointer(CapturePointer * pointer) assert(this); assert(this->initialized); - if (this->reinit) - return CAPTURE_RESULT_REINIT; - if (!os_waitEvent(this->pointerEvent, TIMEOUT_INFINITE)) { DEBUG_ERROR("Failed to wait on the pointer event"); return CAPTURE_RESULT_ERROR; } - if (this->reinit) + if (this->stop) return CAPTURE_RESULT_REINIT; Pointer p; @@ -761,6 +747,7 @@ struct CaptureInterface Capture_DXGI = .getName = dxgi_getName, .create = dxgi_create, .init = dxgi_init, + .stop = dxgi_stop, .deinit = dxgi_deinit, .free = dxgi_free, .getMaxFrameSize = dxgi_getMaxFrameSize, diff --git a/c-host/platform/Windows/capture/NVFBC/CMakeLists.txt b/c-host/platform/Windows/capture/NVFBC/CMakeLists.txt index e3d0e607..7977ac60 100644 --- a/c-host/platform/Windows/capture/NVFBC/CMakeLists.txt +++ b/c-host/platform/Windows/capture/NVFBC/CMakeLists.txt @@ -12,3 +12,7 @@ target_include_directories(capture_NVFBC PRIVATE src ) + +target_link_libraries(capture_NVFBC + platform_Windows +) diff --git a/c-host/platform/Windows/capture/NVFBC/src/nvfbc.c b/c-host/platform/Windows/capture/NVFBC/src/nvfbc.c index c4c0a356..2921699b 100644 --- a/c-host/platform/Windows/capture/NVFBC/src/nvfbc.c +++ b/c-host/platform/Windows/capture/NVFBC/src/nvfbc.c @@ -19,8 +19,9 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "interface/capture.h" #include "interface/platform.h" -#include "debug.h" +#include "windows/platform.h" #include "windows/windebug.h" +#include "windows/mousehook.h" #include #include #include @@ -30,7 +31,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA struct iface { - bool reinit; + bool stop; NvFBCHandle nvfbc; void * pointerShape; @@ -43,7 +44,10 @@ struct iface NvFBCFrameGrabInfo grabInfo; osEventHandle * frameEvent; - HANDLE cursorEvent; + osEventHandle * cursorEvents[2]; + + int mouseX, mouseY, mouseHotX, mouseHotY; + bool mouseVisible; }; static struct iface * this = NULL; @@ -64,6 +68,13 @@ static void getDesktopSize(unsigned int * width, unsigned int * height) *height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top; } +static void on_mouseMove(int x, int y) +{ + this->mouseX = x; + this->mouseY = y; + os_signalEvent(this->cursorEvents[1]); +} + static const char * nvfbc_getName() { return "NVFBC (NVidia Frame Buffer Capture)"; @@ -95,13 +106,14 @@ static bool nvfbc_create() static bool nvfbc_init(void * pointerShape, const unsigned int pointerSize) { - this->reinit = false; + this->stop = false; this->pointerShape = pointerShape; this->pointerSize = pointerSize; getDesktopSize(&this->width, &this->height); os_resetEvent(this->frameEvent); + HANDLE event; if (!NvFBCToSysSetup( this->nvfbc, BUFFER_FMT_ARGB10, @@ -111,18 +123,30 @@ static bool nvfbc_init(void * pointerShape, const unsigned int pointerSize) 0, (void **)&this->frameBuffer, NULL, - &this->cursorEvent + &event )) { return false; } + this->cursorEvents[0] = os_wrapEvent(event); + this->cursorEvents[1] = os_createEvent(true); + mouseHook_install(on_mouseMove); + Sleep(100); return true; } +static void nvfbc_stop() +{ + this->stop = true; + os_signalEvent(this->cursorEvents[1]); + os_signalEvent(this->frameEvent); +} + static bool nvfbc_deinit() { + mouseHook_remove(); return true; } @@ -172,7 +196,7 @@ static CaptureResult nvfbc_getFrame(CaptureFrame * frame) return CAPTURE_RESULT_ERROR; } - if (this->reinit) + if (this->stop) return CAPTURE_RESULT_REINIT; frame->width = this->grabInfo.dwWidth; @@ -195,37 +219,33 @@ static CaptureResult nvfbc_getFrame(CaptureFrame * frame) static CaptureResult nvfbc_getPointer(CapturePointer * pointer) { - while(true) + osEventHandle * events[2]; + memcpy(&events, &this->cursorEvents, sizeof(osEventHandle *) * 2); + if (!os_waitEvents(events, 2, false, TIMEOUT_INFINITE)) { - bool sig = false; - switch(WaitForSingleObject((HANDLE)this->cursorEvent, INFINITE)) - { - case WAIT_OBJECT_0: - sig = true; - break; - - case WAIT_ABANDONED: - continue; - - case WAIT_TIMEOUT: - continue; - - case WAIT_FAILED: - DEBUG_WINERROR("Wait for cursor event failed", GetLastError()); - return CAPTURE_RESULT_ERROR; - } - - if (sig) - break; - - DEBUG_ERROR("Unknown wait event return code"); + DEBUG_ERROR("Failed to wait on the cursor events"); return CAPTURE_RESULT_ERROR; } - if (this->reinit) + if (this->stop) return CAPTURE_RESULT_REINIT; - return NvFBCToSysGetCursor(this->nvfbc, pointer, this->pointerShape, this->pointerSize); + CaptureResult result; + pointer->shapeUpdate = false; + if (events[0]) + { + result = NvFBCToSysGetCursor(this->nvfbc, pointer, this->pointerShape, this->pointerSize); + this->mouseVisible = pointer->visible; + this->mouseHotX = pointer->x; + this->mouseHotY = pointer->y; + if (result != CAPTURE_RESULT_OK) + return result; + } + + pointer->visible = this->mouseVisible; + pointer->x = this->mouseX - this->mouseHotX; + pointer->y = this->mouseY - this->mouseHotY; + return CAPTURE_RESULT_OK; } struct CaptureInterface Capture_NVFBC = @@ -233,6 +253,7 @@ struct CaptureInterface Capture_NVFBC = .getName = nvfbc_getName, .create = nvfbc_create, .init = nvfbc_init, + .stop = nvfbc_stop, .deinit = nvfbc_deinit, .free = nvfbc_free, .getMaxFrameSize = nvfbc_getMaxFrameSize, diff --git a/c-host/platform/Windows/include/windows/mousehook.h b/c-host/platform/Windows/include/windows/mousehook.h new file mode 100644 index 00000000..ef71a3e1 --- /dev/null +++ b/c-host/platform/Windows/include/windows/mousehook.h @@ -0,0 +1,23 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017-2019 Geoffrey McRae +https://looking-glass.hostfission.com + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +typedef void (*MouseHookFn)(int x, int y); + +void mouseHook_install(MouseHookFn callback); +void mouseHook_remove(); \ No newline at end of file diff --git a/c-host/platform/Windows/include/windows/platform.h b/c-host/platform/Windows/include/windows/platform.h new file mode 100644 index 00000000..1a098324 --- /dev/null +++ b/c-host/platform/Windows/include/windows/platform.h @@ -0,0 +1,23 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017-2019 Geoffrey McRae +https://looking-glass.hostfission.com + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "interface/platform.h" +#include + +osEventHandle * os_wrapEvent(HANDLE event); \ No newline at end of file diff --git a/c-host/platform/Windows/resource.rc b/c-host/platform/Windows/resource.rc new file mode 100644 index 00000000..8af0ed12 --- /dev/null +++ b/c-host/platform/Windows/resource.rc @@ -0,0 +1,3 @@ +#include "winuser.h" + +CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "app.manifest" diff --git a/c-host/platform/Windows/src/mousehook.c b/c-host/platform/Windows/src/mousehook.c new file mode 100644 index 00000000..a3da302a --- /dev/null +++ b/c-host/platform/Windows/src/mousehook.c @@ -0,0 +1,98 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017-2019 Geoffrey McRae +https://looking-glass.hostfission.com + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "windows/mousehook.h" +#include "windows/windebug.h" +#include "platform.h" + +#include +#include + +struct mouseHook +{ + bool installed; + HHOOK hook; + MouseHookFn callback; +}; + +static struct mouseHook mouseHook = { 0 }; + +// forwards +static LRESULT WINAPI mouseHook_hook(int nCode, WPARAM wParam, LPARAM lParam); +static LRESULT msg_callback(WPARAM wParam, LPARAM lParam); + +void mouseHook_install(MouseHookFn callback) +{ + struct MSG_CALL_FUNCTION cf; + cf.fn = msg_callback; + cf.wParam = 1; + cf.lParam = (LPARAM)callback; + sendAppMessage(WM_CALL_FUNCTION, 0, (LPARAM)&cf); +} + +void mouseHook_remove() +{ + struct MSG_CALL_FUNCTION cf; + cf.fn = msg_callback; + cf.wParam = 0; + cf.lParam = 0; + sendAppMessage(WM_CALL_FUNCTION, 0, (LPARAM)&cf); +} + +static LRESULT msg_callback(WPARAM wParam, LPARAM lParam) +{ + if (wParam) + { + if (mouseHook.installed) + { + DEBUG_WARN("Mouse hook already installed"); + return 0; + } + + mouseHook.hook = SetWindowsHookEx(WH_MOUSE_LL, mouseHook_hook, NULL, 0); + if (!mouseHook.hook) + { + DEBUG_WINERROR("Failed to install the mouse hook", GetLastError()); + return 0; + } + + mouseHook.installed = true; + mouseHook.callback = (MouseHookFn)lParam; + } + else + { + if (!mouseHook.installed) + return 0; + + UnhookWindowsHookEx(mouseHook.hook); + mouseHook.installed = false; + } + + return 0; +} + +static LRESULT WINAPI mouseHook_hook(int nCode, WPARAM wParam, LPARAM lParam) +{ + if (nCode == HC_ACTION && wParam == WM_MOUSEMOVE) + { + MSLLHOOKSTRUCT *msg = (MSLLHOOKSTRUCT *)lParam; + mouseHook.callback(msg->pt.x, msg->pt.y); + } + return CallNextHookEx(mouseHook.hook, nCode, wParam, lParam); +} \ No newline at end of file diff --git a/c-host/platform/Windows/src/platform.c b/c-host/platform/Windows/src/platform.c index 3a139fa4..bdaa736b 100644 --- a/c-host/platform/Windows/src/platform.c +++ b/c-host/platform/Windows/src/platform.c @@ -17,6 +17,9 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "platform.h" +#include "windows/platform.h" +#include "windows/mousehook.h" #include #include @@ -37,6 +40,7 @@ struct osThreadHandle void * opaque; HANDLE handle; DWORD threadID; + int resultCode; }; @@ -45,6 +49,7 @@ LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) switch(msg) { case WM_CLOSE: + mouseHook_remove(); DestroyWindow(hwnd); break; @@ -52,6 +57,12 @@ LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) PostQuitMessage(0); break; + case WM_CALL_FUNCTION: + { + struct MSG_CALL_FUNCTION * cf = (struct MSG_CALL_FUNCTION *)lParam; + return cf->fn(cf->wParam, cf->lParam); + } + default: return DefWindowProc(hwnd, msg, wParam, lParam); } @@ -65,6 +76,22 @@ static int appThread(void * opaque) return result; } +LRESULT sendAppMessage(UINT Msg, WPARAM wParam, LPARAM lParam) +{ + return SendMessage(messageWnd, Msg, wParam, lParam); +} + +static BOOL WINAPI CtrlHandler(DWORD dwCtrlType) +{ + if (dwCtrlType == CTRL_C_EVENT) + { + SendMessage(messageWnd, WM_CLOSE, 0, 0); + return TRUE; + } + + return FALSE; +} + int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int result = 0; @@ -139,6 +166,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine free(infData); SetupDiDestroyDeviceInfoList(deviceInfoSet); + // setup a handler for ctrl+c + SetConsoleCtrlHandler(CtrlHandler, TRUE); + // create a message window so that our message pump works WNDCLASSEX wx = {}; wx.cbSize = sizeof(WNDCLASSEX); @@ -169,6 +199,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine { TranslateMessage(&msg); DispatchMessage(&msg); + continue; } else if (bRet < 0) { @@ -312,6 +343,11 @@ osEventHandle * os_createEvent(bool autoReset) return (osEventHandle*)event; } +osEventHandle * os_wrapEvent(HANDLE event) +{ + return (osEventHandle*)event; +} + void os_freeEvent(osEventHandle * handle) { CloseHandle((HANDLE)handle); @@ -346,6 +382,42 @@ bool os_waitEvent(osEventHandle * handle, unsigned int timeout) } } +bool os_waitEvents(osEventHandle * handles[], int count, bool waitAll, unsigned int timeout) +{ + const DWORD to = (timeout == TIMEOUT_INFINITE) ? INFINITE : (DWORD)timeout; + while(true) + { + DWORD result = WaitForMultipleObjects(count, (HANDLE*)handles, waitAll, to); + if (result >= WAIT_OBJECT_0 && result < count) + { + // null non signalled events from the handle list + for(int i = 0; i < count; ++i) + if (i != result && !os_waitEvent(handles[i], 0)) + handles[i] = NULL; + return true; + } + + if (result >= WAIT_ABANDONED_0 && result - WAIT_ABANDONED_0 < count) + continue; + + switch(result) + { + case WAIT_TIMEOUT: + if (timeout == TIMEOUT_INFINITE) + continue; + + return false; + + case WAIT_FAILED: + DEBUG_WINERROR("Wait for event failed", GetLastError()); + return false; + } + + DEBUG_ERROR("Unknown wait event return code"); + return false; + } +} + bool os_signalEvent(osEventHandle * handle) { return SetEvent((HANDLE)handle); diff --git a/c-host/platform/Windows/src/platform.h b/c-host/platform/Windows/src/platform.h new file mode 100644 index 00000000..4d14b224 --- /dev/null +++ b/c-host/platform/Windows/src/platform.h @@ -0,0 +1,32 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017-2019 Geoffrey McRae +https://looking-glass.hostfission.com + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include + +#define WM_CALL_FUNCTION (WM_USER+1) + +typedef LRESULT (*CallFunction)(WPARAM wParam, LPARAM lParam); +struct MSG_CALL_FUNCTION +{ + CallFunction fn; + WPARAM wParam; + LPARAM lParam; +}; + +LRESULT sendAppMessage(UINT Msg, WPARAM wParam, LPARAM lParam); \ No newline at end of file diff --git a/c-host/src/app.c b/c-host/src/app.c index 44759dbe..9ff2f632 100644 --- a/c-host/src/app.c +++ b/c-host/src/app.c @@ -368,6 +368,7 @@ int app_main() } finish: + iface->stop(); stopThreads(); exit: