mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-25 14:57:20 +00:00
[c-host] tons of windows specific fixes
This commit is contained in:
parent
3f13485ced
commit
0cac3e1c40
@ -76,6 +76,7 @@ typedef struct CaptureInterface
|
|||||||
const char * (*getName )();
|
const char * (*getName )();
|
||||||
bool (*create )();
|
bool (*create )();
|
||||||
bool (*init )(void * pointerShape, const unsigned int pointerSize);
|
bool (*init )(void * pointerShape, const unsigned int pointerSize);
|
||||||
|
void (*stop )();
|
||||||
bool (*deinit )();
|
bool (*deinit )();
|
||||||
void (*free )();
|
void (*free )();
|
||||||
unsigned int (*getMaxFrameSize)();
|
unsigned int (*getMaxFrameSize)();
|
||||||
|
@ -47,5 +47,6 @@ typedef struct osEventHandle osEventHandle;
|
|||||||
osEventHandle * os_createEvent(bool autoReset);
|
osEventHandle * os_createEvent(bool autoReset);
|
||||||
void os_freeEvent (osEventHandle * handle);
|
void os_freeEvent (osEventHandle * handle);
|
||||||
bool os_waitEvent (osEventHandle * handle, unsigned int timeout);
|
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_signalEvent(osEventHandle * handle);
|
||||||
bool os_resetEvent (osEventHandle * handle);
|
bool os_resetEvent (osEventHandle * handle);
|
Binary file not shown.
@ -8,11 +8,20 @@ include_directories(
|
|||||||
add_library(platform_Windows STATIC
|
add_library(platform_Windows STATIC
|
||||||
src/platform.c
|
src/platform.c
|
||||||
src/windebug.c
|
src/windebug.c
|
||||||
|
src/mousehook.c
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory("capture")
|
add_subdirectory("capture")
|
||||||
|
|
||||||
|
FIND_PROGRAM(WINDRES_EXECUTABLE NAMES "windres.exe" DOC "windres executable")
|
||||||
|
ADD_CUSTOM_COMMAND(TARGET platform_Windows POST_BUILD
|
||||||
|
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
||||||
|
COMMAND ${WINDRES_EXECUTABLE} -i resource.rc -o "${PROJECT_BINARY_DIR}/resource.o"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
target_link_libraries(platform_Windows
|
target_link_libraries(platform_Windows
|
||||||
|
"${PROJECT_BINARY_DIR}/resource.o"
|
||||||
capture
|
capture
|
||||||
setupapi
|
setupapi
|
||||||
)
|
)
|
||||||
|
12
c-host/platform/Windows/app.manifest
Normal file
12
c-host/platform/Windows/app.manifest
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="hello" type="win32"/>
|
||||||
|
<description>Hello World</description>
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges>
|
||||||
|
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
</assembly>
|
@ -55,7 +55,7 @@ Pointer;
|
|||||||
struct iface
|
struct iface
|
||||||
{
|
{
|
||||||
bool initialized;
|
bool initialized;
|
||||||
bool reinit;
|
bool stop;
|
||||||
IDXGIFactory1 * factory;
|
IDXGIFactory1 * factory;
|
||||||
IDXGIAdapter1 * adapter;
|
IDXGIAdapter1 * adapter;
|
||||||
IDXGIOutput * output;
|
IDXGIOutput * output;
|
||||||
@ -158,7 +158,7 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize)
|
|||||||
this->pointerSize = pointerSize;
|
this->pointerSize = pointerSize;
|
||||||
this->pointerUsed = 0;
|
this->pointerUsed = 0;
|
||||||
|
|
||||||
this->reinit = false;
|
this->stop = false;
|
||||||
this->texRIndex = 0;
|
this->texRIndex = 0;
|
||||||
this->texWIndex = 0;
|
this->texWIndex = 0;
|
||||||
os_resetEvent(this->frameEvent);
|
os_resetEvent(this->frameEvent);
|
||||||
@ -402,6 +402,13 @@ fail:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dxgi_stop()
|
||||||
|
{
|
||||||
|
this->stop = true;
|
||||||
|
os_signalEvent(this->frameEvent );
|
||||||
|
os_signalEvent(this->pointerEvent);
|
||||||
|
}
|
||||||
|
|
||||||
static bool dxgi_deinit()
|
static bool dxgi_deinit()
|
||||||
{
|
{
|
||||||
assert(this);
|
assert(this);
|
||||||
@ -497,7 +504,7 @@ static unsigned int dxgi_getMaxFrameSize()
|
|||||||
return this->height * this->pitch;
|
return this->height * this->pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static CaptureResult dxgi_capture_int()
|
static CaptureResult dxgi_capture()
|
||||||
{
|
{
|
||||||
assert(this);
|
assert(this);
|
||||||
assert(this->initialized);
|
assert(this->initialized);
|
||||||
@ -641,36 +648,18 @@ inline static CaptureResult dxgi_capture_int()
|
|||||||
return CAPTURE_RESULT_OK;
|
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)
|
static CaptureResult dxgi_getFrame(CaptureFrame * frame)
|
||||||
{
|
{
|
||||||
assert(this);
|
assert(this);
|
||||||
assert(this->initialized);
|
assert(this->initialized);
|
||||||
|
|
||||||
if (this->reinit)
|
|
||||||
return CAPTURE_RESULT_REINIT;
|
|
||||||
|
|
||||||
if (!os_waitEvent(this->frameEvent, TIMEOUT_INFINITE))
|
if (!os_waitEvent(this->frameEvent, TIMEOUT_INFINITE))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to wait on the frame event");
|
DEBUG_ERROR("Failed to wait on the frame event");
|
||||||
return CAPTURE_RESULT_ERROR;
|
return CAPTURE_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->reinit)
|
if (this->stop)
|
||||||
return CAPTURE_RESULT_REINIT;
|
return CAPTURE_RESULT_REINIT;
|
||||||
|
|
||||||
Texture * tex = &this->texture[this->texRIndex];
|
Texture * tex = &this->texture[this->texRIndex];
|
||||||
@ -695,16 +684,13 @@ static CaptureResult dxgi_getPointer(CapturePointer * pointer)
|
|||||||
assert(this);
|
assert(this);
|
||||||
assert(this->initialized);
|
assert(this->initialized);
|
||||||
|
|
||||||
if (this->reinit)
|
|
||||||
return CAPTURE_RESULT_REINIT;
|
|
||||||
|
|
||||||
if (!os_waitEvent(this->pointerEvent, TIMEOUT_INFINITE))
|
if (!os_waitEvent(this->pointerEvent, TIMEOUT_INFINITE))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to wait on the pointer event");
|
DEBUG_ERROR("Failed to wait on the pointer event");
|
||||||
return CAPTURE_RESULT_ERROR;
|
return CAPTURE_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->reinit)
|
if (this->stop)
|
||||||
return CAPTURE_RESULT_REINIT;
|
return CAPTURE_RESULT_REINIT;
|
||||||
|
|
||||||
Pointer p;
|
Pointer p;
|
||||||
@ -761,6 +747,7 @@ struct CaptureInterface Capture_DXGI =
|
|||||||
.getName = dxgi_getName,
|
.getName = dxgi_getName,
|
||||||
.create = dxgi_create,
|
.create = dxgi_create,
|
||||||
.init = dxgi_init,
|
.init = dxgi_init,
|
||||||
|
.stop = dxgi_stop,
|
||||||
.deinit = dxgi_deinit,
|
.deinit = dxgi_deinit,
|
||||||
.free = dxgi_free,
|
.free = dxgi_free,
|
||||||
.getMaxFrameSize = dxgi_getMaxFrameSize,
|
.getMaxFrameSize = dxgi_getMaxFrameSize,
|
||||||
|
@ -12,3 +12,7 @@ target_include_directories(capture_NVFBC
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
src
|
src
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_link_libraries(capture_NVFBC
|
||||||
|
platform_Windows
|
||||||
|
)
|
||||||
|
@ -19,8 +19,9 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
#include "interface/capture.h"
|
#include "interface/capture.h"
|
||||||
#include "interface/platform.h"
|
#include "interface/platform.h"
|
||||||
#include "debug.h"
|
#include "windows/platform.h"
|
||||||
#include "windows/windebug.h"
|
#include "windows/windebug.h"
|
||||||
|
#include "windows/mousehook.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@ -30,7 +31,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
struct iface
|
struct iface
|
||||||
{
|
{
|
||||||
bool reinit;
|
bool stop;
|
||||||
NvFBCHandle nvfbc;
|
NvFBCHandle nvfbc;
|
||||||
|
|
||||||
void * pointerShape;
|
void * pointerShape;
|
||||||
@ -43,7 +44,10 @@ struct iface
|
|||||||
NvFBCFrameGrabInfo grabInfo;
|
NvFBCFrameGrabInfo grabInfo;
|
||||||
|
|
||||||
osEventHandle * frameEvent;
|
osEventHandle * frameEvent;
|
||||||
HANDLE cursorEvent;
|
osEventHandle * cursorEvents[2];
|
||||||
|
|
||||||
|
int mouseX, mouseY, mouseHotX, mouseHotY;
|
||||||
|
bool mouseVisible;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct iface * this = NULL;
|
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;
|
*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()
|
static const char * nvfbc_getName()
|
||||||
{
|
{
|
||||||
return "NVFBC (NVidia Frame Buffer Capture)";
|
return "NVFBC (NVidia Frame Buffer Capture)";
|
||||||
@ -95,13 +106,14 @@ static bool nvfbc_create()
|
|||||||
|
|
||||||
static bool nvfbc_init(void * pointerShape, const unsigned int pointerSize)
|
static bool nvfbc_init(void * pointerShape, const unsigned int pointerSize)
|
||||||
{
|
{
|
||||||
this->reinit = false;
|
this->stop = false;
|
||||||
this->pointerShape = pointerShape;
|
this->pointerShape = pointerShape;
|
||||||
this->pointerSize = pointerSize;
|
this->pointerSize = pointerSize;
|
||||||
|
|
||||||
getDesktopSize(&this->width, &this->height);
|
getDesktopSize(&this->width, &this->height);
|
||||||
os_resetEvent(this->frameEvent);
|
os_resetEvent(this->frameEvent);
|
||||||
|
|
||||||
|
HANDLE event;
|
||||||
if (!NvFBCToSysSetup(
|
if (!NvFBCToSysSetup(
|
||||||
this->nvfbc,
|
this->nvfbc,
|
||||||
BUFFER_FMT_ARGB10,
|
BUFFER_FMT_ARGB10,
|
||||||
@ -111,18 +123,30 @@ static bool nvfbc_init(void * pointerShape, const unsigned int pointerSize)
|
|||||||
0,
|
0,
|
||||||
(void **)&this->frameBuffer,
|
(void **)&this->frameBuffer,
|
||||||
NULL,
|
NULL,
|
||||||
&this->cursorEvent
|
&event
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->cursorEvents[0] = os_wrapEvent(event);
|
||||||
|
this->cursorEvents[1] = os_createEvent(true);
|
||||||
|
mouseHook_install(on_mouseMove);
|
||||||
|
|
||||||
Sleep(100);
|
Sleep(100);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nvfbc_stop()
|
||||||
|
{
|
||||||
|
this->stop = true;
|
||||||
|
os_signalEvent(this->cursorEvents[1]);
|
||||||
|
os_signalEvent(this->frameEvent);
|
||||||
|
}
|
||||||
|
|
||||||
static bool nvfbc_deinit()
|
static bool nvfbc_deinit()
|
||||||
{
|
{
|
||||||
|
mouseHook_remove();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +196,7 @@ static CaptureResult nvfbc_getFrame(CaptureFrame * frame)
|
|||||||
return CAPTURE_RESULT_ERROR;
|
return CAPTURE_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->reinit)
|
if (this->stop)
|
||||||
return CAPTURE_RESULT_REINIT;
|
return CAPTURE_RESULT_REINIT;
|
||||||
|
|
||||||
frame->width = this->grabInfo.dwWidth;
|
frame->width = this->grabInfo.dwWidth;
|
||||||
@ -195,37 +219,33 @@ static CaptureResult nvfbc_getFrame(CaptureFrame * frame)
|
|||||||
|
|
||||||
static CaptureResult nvfbc_getPointer(CapturePointer * pointer)
|
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;
|
DEBUG_ERROR("Failed to wait on the cursor events");
|
||||||
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;
|
return CAPTURE_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sig)
|
if (this->stop)
|
||||||
break;
|
|
||||||
|
|
||||||
DEBUG_ERROR("Unknown wait event return code");
|
|
||||||
return CAPTURE_RESULT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->reinit)
|
|
||||||
return CAPTURE_RESULT_REINIT;
|
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 =
|
struct CaptureInterface Capture_NVFBC =
|
||||||
@ -233,6 +253,7 @@ struct CaptureInterface Capture_NVFBC =
|
|||||||
.getName = nvfbc_getName,
|
.getName = nvfbc_getName,
|
||||||
.create = nvfbc_create,
|
.create = nvfbc_create,
|
||||||
.init = nvfbc_init,
|
.init = nvfbc_init,
|
||||||
|
.stop = nvfbc_stop,
|
||||||
.deinit = nvfbc_deinit,
|
.deinit = nvfbc_deinit,
|
||||||
.free = nvfbc_free,
|
.free = nvfbc_free,
|
||||||
.getMaxFrameSize = nvfbc_getMaxFrameSize,
|
.getMaxFrameSize = nvfbc_getMaxFrameSize,
|
||||||
|
23
c-host/platform/Windows/include/windows/mousehook.h
Normal file
23
c-host/platform/Windows/include/windows/mousehook.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||||
|
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>
|
||||||
|
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();
|
23
c-host/platform/Windows/include/windows/platform.h
Normal file
23
c-host/platform/Windows/include/windows/platform.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||||
|
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>
|
||||||
|
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 <windows.h>
|
||||||
|
|
||||||
|
osEventHandle * os_wrapEvent(HANDLE event);
|
3
c-host/platform/Windows/resource.rc
Normal file
3
c-host/platform/Windows/resource.rc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "winuser.h"
|
||||||
|
|
||||||
|
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "app.manifest"
|
98
c-host/platform/Windows/src/mousehook.c
Normal file
98
c-host/platform/Windows/src/mousehook.c
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||||
|
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>
|
||||||
|
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 <windows.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
@ -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
|
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include "windows/platform.h"
|
||||||
|
#include "windows/mousehook.h"
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <setupapi.h>
|
#include <setupapi.h>
|
||||||
|
|
||||||
@ -37,6 +40,7 @@ struct osThreadHandle
|
|||||||
void * opaque;
|
void * opaque;
|
||||||
HANDLE handle;
|
HANDLE handle;
|
||||||
DWORD threadID;
|
DWORD threadID;
|
||||||
|
|
||||||
int resultCode;
|
int resultCode;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -45,6 +49,7 @@ LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||||||
switch(msg)
|
switch(msg)
|
||||||
{
|
{
|
||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
|
mouseHook_remove();
|
||||||
DestroyWindow(hwnd);
|
DestroyWindow(hwnd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -52,6 +57,12 @@ LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WM_CALL_FUNCTION:
|
||||||
|
{
|
||||||
|
struct MSG_CALL_FUNCTION * cf = (struct MSG_CALL_FUNCTION *)lParam;
|
||||||
|
return cf->fn(cf->wParam, cf->lParam);
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
@ -65,6 +76,22 @@ static int appThread(void * opaque)
|
|||||||
return result;
|
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 WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
@ -139,6 +166,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
free(infData);
|
free(infData);
|
||||||
SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
||||||
|
|
||||||
|
// setup a handler for ctrl+c
|
||||||
|
SetConsoleCtrlHandler(CtrlHandler, TRUE);
|
||||||
|
|
||||||
// create a message window so that our message pump works
|
// create a message window so that our message pump works
|
||||||
WNDCLASSEX wx = {};
|
WNDCLASSEX wx = {};
|
||||||
wx.cbSize = sizeof(WNDCLASSEX);
|
wx.cbSize = sizeof(WNDCLASSEX);
|
||||||
@ -169,6 +199,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
{
|
{
|
||||||
TranslateMessage(&msg);
|
TranslateMessage(&msg);
|
||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else if (bRet < 0)
|
else if (bRet < 0)
|
||||||
{
|
{
|
||||||
@ -312,6 +343,11 @@ osEventHandle * os_createEvent(bool autoReset)
|
|||||||
return (osEventHandle*)event;
|
return (osEventHandle*)event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osEventHandle * os_wrapEvent(HANDLE event)
|
||||||
|
{
|
||||||
|
return (osEventHandle*)event;
|
||||||
|
}
|
||||||
|
|
||||||
void os_freeEvent(osEventHandle * handle)
|
void os_freeEvent(osEventHandle * handle)
|
||||||
{
|
{
|
||||||
CloseHandle((HANDLE)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)
|
bool os_signalEvent(osEventHandle * handle)
|
||||||
{
|
{
|
||||||
return SetEvent((HANDLE)handle);
|
return SetEvent((HANDLE)handle);
|
||||||
|
32
c-host/platform/Windows/src/platform.h
Normal file
32
c-host/platform/Windows/src/platform.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||||
|
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>
|
||||||
|
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.h>
|
||||||
|
|
||||||
|
#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);
|
@ -368,6 +368,7 @@ int app_main()
|
|||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
|
iface->stop();
|
||||||
stopThreads();
|
stopThreads();
|
||||||
exit:
|
exit:
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user