1
0
mirror of https://github.com/Ylianst/MeshAgent synced 2025-12-10 21:33:38 +00:00

1. Updated Mouse Cursor Update to be event driven

2. Added support for remote mouse cursor rendering on Windows
This commit is contained in:
Bryan Roe
2020-02-25 15:24:00 -08:00
parent 2669b10a5b
commit 7c77677b3e
7 changed files with 303 additions and 118 deletions

View File

@@ -22,8 +22,18 @@ limitations under the License.
#include "input.h"
#include "microstack/ILibCrypto.h"
#include "meshcore/meshdefines.h"
extern void ILibAppendStringToDiskEx(char *FileName, char *data, int dataLen);
extern ILibQueue gPendingPackets;
extern int gRemoteMouseRenderDefault;
uint64_t gMouseInputTime = 0;
HWINEVENTHOOK CUR_HOOK = NULL;
WNDCLASSEXA CUR_WNDCLASS;
HWND CUR_HWND = NULL;
HANDLE CUR_APCTHREAD = NULL;
HANDLE CUR_WORKTHREAD = NULL;
int CUR_CURRENT = 0;
int CUR_APPSTARTING;
@@ -59,6 +69,68 @@ MOUSEEVENTF_MIDDLEUP 0x0040
MOUSEEVENTF_DOUBLECLK 0x0088
*/
int KVM_CursorHashToMSG(int hashcode)
{
int ret = KVM_MouseCursor_ARROW;
if (hashcode == CUR_APPSTARTING)
{
ret = KVM_MouseCursor_APPSTARTING;
}
else if (hashcode == CUR_ARROW)
{
ret = KVM_MouseCursor_ARROW;
}
else if (hashcode == CUR_CROSS)
{
ret = KVM_MouseCursor_CROSS;
}
else if (hashcode == CUR_HAND)
{
ret = KVM_MouseCursor_HAND;
}
else if (hashcode == CUR_HELP)
{
ret = KVM_MouseCursor_HELP;
}
else if (hashcode == CUR_IBEAM)
{
ret = KVM_MouseCursor_IBEAM;
}
else if (hashcode == CUR_NO)
{
ret = KVM_MouseCursor_NO;
}
else if (hashcode == CUR_SIZEALL)
{
ret = KVM_MouseCursor_SIZEALL;
}
else if (hashcode == CUR_SIZENESW)
{
ret = KVM_MouseCursor_SIZENESW;
}
else if (hashcode == CUR_SIZENS)
{
ret = KVM_MouseCursor_SIZENS;
}
else if (hashcode == CUR_SIZENWSE)
{
ret = KVM_MouseCursor_SIZENWSE;
}
else if (hashcode == CUR_SIZEWE)
{
ret = KVM_MouseCursor_SIZEWE;
}
else if (hashcode == CUR_UPARROW)
{
ret = KVM_MouseCursor_UPARROW;
}
else if (hashcode == CUR_WAIT)
{
ret = KVM_MouseCursor_WAIT;
}
return(ret);
}
int KVM_GetCursorHash(HCURSOR hc, char *buffer, size_t bufferLen)
{
int crc = 0;
@@ -71,8 +143,12 @@ int KVM_GetCursorHash(HCURSOR hc, char *buffer, size_t bufferLen)
{
//printf("CX: %ul, CY:%ul, Color: %ul, Showing: %d\n", bm.bmWidth, bm.bmHeight, ii.hbmColor, info.flags);
HDC hdcScreen = GetDC(NULL);
if (hdcScreen != NULL)
{
HDC hdcMem = CreateCompatibleDC(hdcScreen);
HBITMAP hbmCanvas = CreateCompatibleBitmap(hdcScreen, bm.bmWidth, ii.hbmColor ? bm.bmHeight : (bm.bmHeight / 2));
if (hdcMem != NULL && hbmCanvas != NULL)
{
HGDIOBJ hbmold = SelectObject(hdcMem, hbmCanvas);
BITMAPINFO bmpInfo;
char *tmpBuffer;
@@ -91,13 +167,136 @@ int KVM_GetCursorHash(HCURSOR hc, char *buffer, size_t bufferLen)
free(tmpBuffer);
SelectObject(hdcMem, hbmold);
ReleaseDC(NULL, hdcMem);
ReleaseDC(NULL, hdcScreen);
}
if (hbmCanvas != NULL) { DeleteObject(hbmCanvas); }
if (hdcMem != NULL) { ReleaseDC(NULL, hdcMem); }
if (hdcScreen != NULL) { ReleaseDC(NULL, hdcScreen); }
}
}
return(crc);
}
void __stdcall KVM_APCSink(ULONG_PTR user)
{
ILibQueue_EnQueue(gPendingPackets, (char*)user);
}
void CALLBACK KVMWinEventProc(
HWINEVENTHOOK hook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD idEventThread,
DWORD time)
{
char *buffer;
CURSORINFO info = { 0 };
int i;
if (hwnd == NULL && idObject == OBJID_CURSOR)
{
switch (event)
{
case EVENT_OBJECT_LOCATIONCHANGE:
if (gRemoteMouseRenderDefault != 0 || ((uint64_t)ILibGetUptime() - gMouseInputTime) > 500)
{
info.cbSize = sizeof(info);
GetCursorInfo(&info);
buffer = (char*)ILibMemory_SmartAllocate(12);
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_MOUSE_MOVE); // Write the type
((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)12); // Write the size
((long*)buffer)[1] = info.ptScreenPos.x;
((long*)buffer)[2] = info.ptScreenPos.y;
QueueUserAPC((PAPCFUNC)KVM_APCSink, CUR_APCTHREAD, (ULONG_PTR)buffer);
}
break;
case EVENT_OBJECT_NAMECHANGE:
case EVENT_OBJECT_HIDE:
// Mouse Cursor has changed
info.cbSize = sizeof(info);
GetCursorInfo(&info);
i = KVM_CursorHashToMSG(KVM_GetCursorHash(info.hCursor, NULL, 0));
buffer = (char*)ILibMemory_SmartAllocate(5);
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_MOUSE_CURSOR); // Write the type
((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)5); // Write the size
buffer[4] = (char)i; // Cursor Type
QueueUserAPC((PAPCFUNC)KVM_APCSink, CUR_APCTHREAD, (ULONG_PTR)buffer);
break;
default:
//printf("Unknown: %ul\n", event);
break;
}
}
}
void KVM_StopMessagePump()
{
if (CUR_HWND != NULL)
{
PostMessageA(CUR_HWND, WM_QUIT, 0, 0);
WaitForSingleObject(CUR_WORKTHREAD, 5000);
}
}
void KVM_UnInitMouseCursors()
{
if (CUR_HOOK != NULL)
{
UnhookWinEvent(CUR_HOOK);
CUR_HOOK = NULL;
KVM_StopMessagePump();
}
}
LRESULT CALLBACK KVMWindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
if (uMsg == WM_CREATE)
{
CUR_HOOK = SetWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_NAMECHANGE, NULL, KVMWinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT);
}
return(DefWindowProcA(hwnd, uMsg, wParam, lParam));
}
void KVM_PumpMessage()
{
MSG m;
while (GetMessageA(&m, CUR_HWND, 0, 0) > 0)
{
TranslateMessage(&m);
DispatchMessageA(&m);
}
}
DWORD WINAPI KVM_InitMessagePumpEx(LPVOID parm)
{
memset(&CUR_WNDCLASS, 0, sizeof(CUR_WNDCLASS));
CUR_WNDCLASS.hInstance = GetModuleHandleA(NULL);
CUR_WNDCLASS.lpszClassName = "MainWWW2Class";
CUR_WNDCLASS.cbSize = sizeof(CUR_WNDCLASS);
CUR_WNDCLASS.lpfnWndProc = KVMWindowProc;
if (RegisterClassExA(&CUR_WNDCLASS) != 0)
{
CUR_HWND = CreateWindowExA(0x00000088, "MainWWW2Class", "TestTitle", 0x00800000, 0, 0, 100, 100, 0, 0, 0, 0);
KVM_PumpMessage();
}
return(0);
}
void KVM_InitMessagePump()
{
CUR_APCTHREAD = OpenThread(THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId());
CUR_WORKTHREAD = CreateThread(NULL, 0, KVM_InitMessagePumpEx, NULL, 0, 0);
}
void KVM_InitMouseCursors()
{
CUR_ARROW = KVM_GetCursorHash(LoadCursorA(NULL, IDC_ARROW), NULL, 0);
@@ -114,17 +313,18 @@ void KVM_InitMouseCursors()
CUR_SIZEWE = KVM_GetCursorHash(LoadCursorA(NULL, IDC_SIZEWE), NULL, 0);
CUR_UPARROW = KVM_GetCursorHash(LoadCursorA(NULL, IDC_UPARROW), NULL, 0);
CUR_WAIT = KVM_GetCursorHash(LoadCursorA(NULL, IDC_WAIT), NULL, 0);
KVM_InitMessagePump();
}
KVM_MouseCursors MouseAction(double absX, double absY, int button, short wheel)
void MouseAction(double absX, double absY, int button, short wheel)
{
INPUT mouse;
KVM_MouseCursors ret = KVM_MouseCursor_NOCHANGE;
if (button == 0x88)
{
// Double click indication, no nothing on windows.
return(ret);
return;
}
mouse.type = INPUT_MOUSE;
@@ -135,74 +335,8 @@ KVM_MouseCursors MouseAction(double absX, double absY, int button, short wheel)
if (wheel) mouse.mi.dwFlags |= MOUSEEVENTF_WHEEL;
mouse.mi.time = 0;
mouse.mi.dwExtraInfo = 0;
gMouseInputTime = (uint64_t)ILibGetUptime();
SendInput(1, &mouse, sizeof(INPUT));
CURSORINFO info = { 0 };
info.cbSize = sizeof(info);
GetCursorInfo(&info);
int i = KVM_GetCursorHash(info.hCursor, NULL, 0);
if (i != CUR_CURRENT)
{
CUR_CURRENT = i;
if (CUR_CURRENT == CUR_APPSTARTING)
{
ret = KVM_MouseCursor_APPSTARTING;
}
else if (CUR_CURRENT == CUR_ARROW)
{
ret = KVM_MouseCursor_ARROW;
}
else if (CUR_CURRENT == CUR_CROSS)
{
ret = KVM_MouseCursor_CROSS;
}
else if (CUR_CURRENT == CUR_HAND)
{
ret = KVM_MouseCursor_HAND;
}
else if (CUR_CURRENT == CUR_HELP)
{
ret = KVM_MouseCursor_HELP;
}
else if (CUR_CURRENT == CUR_IBEAM)
{
ret = KVM_MouseCursor_IBEAM;
}
else if (CUR_CURRENT == CUR_NO)
{
ret = KVM_MouseCursor_NO;
}
else if (CUR_CURRENT == CUR_SIZEALL)
{
ret = KVM_MouseCursor_SIZEALL;
}
else if (CUR_CURRENT == CUR_SIZENESW)
{
ret = KVM_MouseCursor_SIZENESW;
}
else if (CUR_CURRENT == CUR_SIZENS)
{
ret = KVM_MouseCursor_SIZENS;
}
else if (CUR_CURRENT == CUR_SIZENWSE)
{
ret = KVM_MouseCursor_SIZENWSE;
}
else if (CUR_CURRENT == CUR_SIZEWE)
{
ret = KVM_MouseCursor_SIZEWE;
}
else if (CUR_CURRENT == CUR_UPARROW)
{
ret = KVM_MouseCursor_UPARROW;
}
else if (CUR_CURRENT == CUR_WAIT)
{
ret = KVM_MouseCursor_WAIT;
}
}
return(ret);
}

View File

@@ -36,7 +36,8 @@ typedef enum KVM_MouseCursors
}KVM_MouseCursors;
void KVM_InitMouseCursors();
KVM_MouseCursors MouseAction(double absX, double absY, int button, short wheel);
void KVM_UnInitMouseCursors();
void MouseAction(double absX, double absY, int button, short wheel);
void KeyAction(unsigned char keycode, int up);
int TouchInit();
void TouchUnInit();

View File

@@ -38,6 +38,7 @@ limitations under the License.
// #define KVMDEBUGENABLED 1
ILibProcessPipe_SpawnTypes gProcessSpawnType = ILibProcessPipe_SpawnTypes_USER;
int gProcessTSID = -1;
extern int gRemoteMouseRenderDefault;
#pragma pack(push, 1)
typedef struct KVMDebugLog
@@ -115,6 +116,8 @@ HANDLE hStdIn = INVALID_HANDLE_VALUE;
int ThreadRunning = 0;
int kvmConsoleMode = 0;
ILibQueue gPendingPackets = NULL;
ILibRemoteLogging gKVMRemoteLogging = NULL;
#ifdef _WINSERVICE
void kvm_slave_OnRawForwardLog(ILibRemoteLogging sender, ILibRemoteLogging_Modules module, ILibRemoteLogging_Flags flags, char *buffer, int bufferLen)
@@ -509,15 +512,7 @@ int kvm_server_inputdata(char* block, int blocklen, ILibKVM_WriteHandler writeHa
// Perform the mouse movement
if (size == 12) w = ((short)ntohs(((short*)(block))[5]));
curcursor = MouseAction((((double)x / (double)SCREEN_WIDTH)), (((double)y / (double)SCREEN_HEIGHT)), (int)(unsigned char)(block[5]), w);
if (curcursor != KVM_MouseCursor_NOCHANGE)
{
char buffer[8];
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_MOUSE_CURSOR); // Write the type
((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)5); // Write the size
buffer[4] = (char)curcursor; // Cursor Type
writeHandler((char*)buffer, 5, reserved);
}
MouseAction((((double)x / (double)SCREEN_WIDTH)), (((double)y / (double)SCREEN_HEIGHT)), (int)(unsigned char)(block[5]), w);
}
break;
}
@@ -819,7 +814,10 @@ DWORD WINAPI kvm_server_mainloop_ex(LPVOID parm)
int row, col;
ILibKVM_WriteHandler writeHandler = (ILibKVM_WriteHandler)((void**)parm)[0];
void *reserved = ((void**)parm)[1];
char *tmoBuffer;
long mouseMove[3] = { 0,0,0 };
gPendingPackets = ILibQueue_Create();
KVM_InitMouseCursors();
#ifdef _WINSERVICE
@@ -895,18 +893,6 @@ DWORD WINAPI kvm_server_mainloop_ex(LPVOID parm)
// Loop and send only when a tile changes.
while (!g_shutdown)
{
/*
cur_timestamp = util_gettime();
if (prev_timestamp != 0)
{
time_diff = (FRAME_RATE_TIMER - (cur_timestamp - prev_timestamp));
if (time_diff < 20) { time_diff = 20; }
}
printf("%d\r\n", cur_timestamp);
Sleep(time_diff);
prev_timestamp = cur_timestamp;
*/
KVMDEBUG("kvm_server_mainloop / loop1", (int)GetCurrentThreadId());
// Reset all the flags to TILE_TODO
@@ -918,8 +904,29 @@ DWORD WINAPI kvm_server_mainloop_ex(LPVOID parm)
CheckDesktopSwitch(1, writeHandler, reserved);
if (g_shutdown) break;
// Enter Alertable State, so we can dispatch any packets if necessary.
// We are doing it here, in case we need to merge any data with the bitmaps
SleepEx(0, TRUE);
mouseMove[0] = 0;
while ((tmoBuffer = ILibQueue_DeQueue(gPendingPackets)) != NULL)
{
if (ntohs(((unsigned short*)tmoBuffer)[0]) == MNG_KVM_MOUSE_MOVE)
{
mouseMove[0] = 1;
mouseMove[1] = ((long*)tmoBuffer)[1] - VSCREEN_X;
mouseMove[2] = ((long*)tmoBuffer)[2] - VSCREEN_Y;
}
else
{
writeHandler(tmoBuffer, (int)ILibMemory_Size(tmoBuffer), reserved);
}
ILibMemory_Free(tmoBuffer);
}
// Scan the desktop
if (get_desktop_buffer(&desktop, &desktopsize) == 1 || desktop == NULL)
if (get_desktop_buffer(&desktop, &desktopsize, mouseMove) == 1 || desktop == NULL)
{
#ifdef _WINSERVICE
if (!kvmConsoleMode)
@@ -930,7 +937,8 @@ DWORD WINAPI kvm_server_mainloop_ex(LPVOID parm)
KVMDEBUG("get_desktop_buffer() failed, shutting down", (int)GetCurrentThreadId());
g_shutdown = 1;
}
else {
else
{
bmpInfo = get_bmp_info(TILE_WIDTH, TILE_HEIGHT);
for (row = 0; row < TILE_HEIGHT_COUNT; row++) {
for (col = 0; col < TILE_WIDTH_COUNT; col++) {
@@ -983,7 +991,6 @@ DWORD WINAPI kvm_server_mainloop_ex(LPVOID parm)
}
KVMDEBUG("kvm_server_mainloop / end3", (int)GetCurrentThreadId());
KVMDEBUG("kvm_server_mainloop / end2", (int)GetCurrentThreadId());
// if (kvmthread != NULL) { CloseHandle(kvmthread); kvmthread = NULL; }
@@ -997,6 +1004,15 @@ DWORD WINAPI kvm_server_mainloop_ex(LPVOID parm)
KVMDEBUG("kvm_server_mainloop / end", (int)GetCurrentThreadId());
KVM_UnInitMouseCursors();
while ((tmoBuffer = ILibQueue_DeQueue(gPendingPackets)) != NULL)
{
ILibMemory_Free(tmoBuffer);
}
ILibQueue_Destroy(gPendingPackets);
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: Process Exiting...");
ThreadRunning = 0;

View File

@@ -478,7 +478,7 @@ int get_tile_at(int x, int y, void** buffer, long long *bufferSize, void *deskto
}
// This function captures the entire desktop buffer to scan.
int get_desktop_buffer(void **buffer, long long *bufferSize)
int get_desktop_buffer(void **buffer, long long *bufferSize, long* mouseMove)
{
BITMAPINFO bmpInfo;
@@ -502,6 +502,36 @@ int get_desktop_buffer(void **buffer, long long *bufferSize)
KVMDEBUG("BitBlt() returned FALSE", 0);
return 1; // If the copy fails, error out.
}
if (mouseMove[0] != 0)
{
CURSORINFO info = { 0 };
BITMAP bm;
ICONINFO ii;
info.cbSize = sizeof(info);
GetCursorInfo(&info);
GetIconInfo(info.hCursor, &ii);
if (GetObject(ii.hbmMask, sizeof(bm), &bm) == sizeof(bm))
{
HDC hdcScreen = GetDC(NULL);
if (hdcScreen != NULL)
{
HDC hdcMem = CreateCompatibleDC(hdcScreen);
HBITMAP hbmCanvas = CreateCompatibleBitmap(hdcScreen, bm.bmWidth, ii.hbmColor ? bm.bmHeight : (bm.bmHeight / 2));
if(hdcMem!=NULL && hbmCanvas != NULL)
{
HGDIOBJ hbmold = SelectObject(hdcMem, hbmCanvas);
DrawIconEx(hdcMem, 0, 0, info.hCursor, bm.bmWidth, ii.hbmColor ? bm.bmHeight : (bm.bmHeight / 2), 0, NULL, DI_NORMAL);
BitBlt(hCaptureDC, mouseMove[1], mouseMove[2], bm.bmWidth, ii.hbmColor ? bm.bmHeight : (bm.bmHeight / 2), hdcMem, 0, 0, SRCPAINT);
SelectObject(hdcMem, hbmold);
}
if (hbmCanvas != NULL) { DeleteObject(hbmCanvas); }
if (hdcMem != NULL) { ReleaseDC(NULL, hdcMem); }
if (hdcScreen != NULL) { ReleaseDC(NULL, hdcScreen); }
}
}
}
}
else
{

View File

@@ -40,7 +40,7 @@ enum TILE_FLAGS_ENUM {
short initialize_gdiplus();
void teardown_gdiplus();
int get_tile_at(int x, int y, void** buffer, long long *bufferSize, void *desktop, int row, int col);
int get_desktop_buffer(void **buffer, long long *bufferSize);
int get_desktop_buffer(void **buffer, long long *bufferSize, long*);
BITMAPINFO get_bmp_info(int width, int height);
void set_tile_compression(int type, int level);
void switch_to_desktop_context();

View File

@@ -46,6 +46,8 @@ limitations under the License.
#include <sys/wait.h>
#endif
int gRemoteMouseRenderDefault = 0;
#ifdef _LINKVM
#ifdef WIN32
#include "KVM/Windows/kvm.h"
@@ -100,7 +102,7 @@ int ILibDuktape_HECI_Debug = 0;
#endif
#endif
extern int ILibDuktape_ModSearch_ShowNames;
extern int ILibDuktape_ModSearch_ShowNames;
char* MeshAgentHost_BatteryInfo_STRINGS[] = { "UNKNOWN", "HIGH_CHARGE", "LOW_CHARGE", "NO_BATTERY", "CRITICAL_CHARGE", "", "", "", "CHARGING" };
JS_ENGINE_CONTEXT MeshAgent_JavaCore_ContextGuid = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
@@ -3425,6 +3427,7 @@ void MeshServer_Connect(MeshAgentHostContainer *agent)
if (agent->serverConnectionState != 0) return;
util_random(sizeof(int), (char*)&timeout);
gRemoteMouseRenderDefault = ILibSimpleDataStore_Get(agent->masterDb, "remoteMouseRender", NULL, 0);
agent->disableUpdate = ILibSimpleDataStore_Get(agent->masterDb, "disableUpdate", NULL, 0);
agent->forceUpdate = ILibSimpleDataStore_Get(agent->masterDb, "forceUpdate", NULL, 0);
agent->logUpdate = ILibSimpleDataStore_Get(agent->masterDb, "logUpdate", NULL, 0);

View File

@@ -27,6 +27,7 @@ typedef enum RemoteManagementCommands
MNG_KVM_KEY = 1,
MNG_KVM_MOUSE = 2,
MNG_KVM_MOUSE_CURSOR = 88,
MNG_KVM_MOUSE_MOVE = 89,
MNG_KVM_PICTURE = 3,
MNG_KVM_COPY = 4,
MNG_KVM_COMPRESSION = 5,