mirror of
https://github.com/gnif/LookingGlass.git
synced 2025-04-29 01:56:27 +00:00
get display DPI info to scale mouse movement
This commit is contained in:
parent
0bd5f0b2f1
commit
7e4d323427
@ -57,7 +57,7 @@ typedef enum CursorType
|
|||||||
CursorType;
|
CursorType;
|
||||||
|
|
||||||
#define KVMFR_MAGIC "KVMFR---"
|
#define KVMFR_MAGIC "KVMFR---"
|
||||||
#define KVMFR_VERSION 5
|
#define KVMFR_VERSION 6
|
||||||
|
|
||||||
typedef struct KVMFR
|
typedef struct KVMFR
|
||||||
{
|
{
|
||||||
@ -80,12 +80,13 @@ KVMFRCursor;
|
|||||||
|
|
||||||
typedef struct KVMFRFrame
|
typedef struct KVMFRFrame
|
||||||
{
|
{
|
||||||
uint32_t formatVer; // the frame format version number
|
uint32_t formatVer; // the frame format version number
|
||||||
FrameType type; // the frame data type
|
FrameType type; // the frame data type
|
||||||
uint32_t width; // the width
|
uint32_t width; // the width
|
||||||
uint32_t height; // the height
|
uint32_t height; // the height
|
||||||
uint32_t stride; // the row stride (zero if compressed data)
|
uint32_t stride; // the row stride (zero if compressed data)
|
||||||
uint32_t pitch; // the row pitch (stride in bytes or the compressed frame size)
|
uint32_t pitch; // the row pitch (stride in bytes or the compressed frame size)
|
||||||
uint32_t offset; // offset from the start of this header to the FrameBuffer header
|
uint32_t offset; // offset from the start of this header to the FrameBuffer header
|
||||||
|
uint32_t mouseScalePercent; // movement scale factor of the mouse (relates to DPI of display, 100 = no scale)
|
||||||
}
|
}
|
||||||
KVMFRFrame;
|
KVMFRFrame;
|
||||||
|
25
common/include/common/dpi.h
Normal file
25
common/include/common/dpi.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||||
|
Copyright (C) 2017-2020 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>
|
||||||
|
|
||||||
|
// At 100% scaling, Windows reports 96 DPI.
|
||||||
|
#define DPI_100_PERCENT 96
|
||||||
|
|
||||||
|
UINT monitor_dpi(HMONITOR hMonitor);
|
@ -7,6 +7,7 @@ include_directories(
|
|||||||
|
|
||||||
add_library(lg_common_platform_code STATIC
|
add_library(lg_common_platform_code STATIC
|
||||||
crash.c
|
crash.c
|
||||||
|
dpi.c
|
||||||
sysinfo.c
|
sysinfo.c
|
||||||
thread.c
|
thread.c
|
||||||
event.c
|
event.c
|
||||||
|
37
common/src/platform/windows/dpi.c
Normal file
37
common/src/platform/windows/dpi.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "common/dpi.h"
|
||||||
|
#include "common/windebug.h"
|
||||||
|
|
||||||
|
typedef enum MONITOR_DPI_TYPE {
|
||||||
|
MDT_EFFECTIVE_DPI,
|
||||||
|
MDT_ANGULAR_DPI,
|
||||||
|
MDT_RAW_DPI,
|
||||||
|
MDT_DEFAULT
|
||||||
|
} MONITOR_DPI_TYPE;
|
||||||
|
typedef HRESULT (WINAPI *GetDpiForMonitor_t)(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT * dpiX, UINT * dpiY);
|
||||||
|
|
||||||
|
UINT monitor_dpi(HMONITOR hMonitor)
|
||||||
|
{
|
||||||
|
HMODULE shcore = LoadLibraryA("shcore.dll");
|
||||||
|
if (!shcore)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Could not load shcore.dll");
|
||||||
|
return DPI_100_PERCENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetDpiForMonitor_t GetDpiForMonitor = (GetDpiForMonitor_t) GetProcAddress(shcore, "GetDpiForMonitor");
|
||||||
|
if (!GetDpiForMonitor)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Could not find GetDpiForMonitor");
|
||||||
|
return DPI_100_PERCENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT dpiX, dpiY;
|
||||||
|
HRESULT status = GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
|
||||||
|
if (FAILED(status))
|
||||||
|
{
|
||||||
|
DEBUG_WINERROR("GetDpiForMonitor failed", status);
|
||||||
|
return DPI_100_PERCENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dpiX;
|
||||||
|
}
|
@ -93,6 +93,7 @@ typedef struct CaptureInterface
|
|||||||
bool (*deinit )();
|
bool (*deinit )();
|
||||||
void (*free )();
|
void (*free )();
|
||||||
unsigned int (*getMaxFrameSize)();
|
unsigned int (*getMaxFrameSize)();
|
||||||
|
unsigned int (*getMouseScale )();
|
||||||
|
|
||||||
CaptureResult (*capture )();
|
CaptureResult (*capture )();
|
||||||
CaptureResult (*waitFrame )(CaptureFrame * frame);
|
CaptureResult (*waitFrame )(CaptureFrame * frame);
|
||||||
|
@ -169,6 +169,11 @@ static unsigned int xcb_getMaxFrameSize()
|
|||||||
return this->width * this->height * 4;
|
return this->width * this->height * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int xcb_getMouseScale()
|
||||||
|
{
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
static CaptureResult xcb_capture()
|
static CaptureResult xcb_capture()
|
||||||
{
|
{
|
||||||
assert(this);
|
assert(this);
|
||||||
@ -241,6 +246,7 @@ struct CaptureInterface Capture_XCB =
|
|||||||
.deinit = xcb_deinit,
|
.deinit = xcb_deinit,
|
||||||
.free = xcb_free,
|
.free = xcb_free,
|
||||||
.getMaxFrameSize = xcb_getMaxFrameSize,
|
.getMaxFrameSize = xcb_getMaxFrameSize,
|
||||||
|
.getMouseScale = xcb_getMouseScale,
|
||||||
.capture = xcb_capture,
|
.capture = xcb_capture,
|
||||||
.waitFrame = xcb_waitFrame,
|
.waitFrame = xcb_waitFrame,
|
||||||
.getFrame = xcb_getFrame,
|
.getFrame = xcb_getFrame,
|
||||||
|
@ -24,6 +24,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "common/option.h"
|
#include "common/option.h"
|
||||||
#include "common/locking.h"
|
#include "common/locking.h"
|
||||||
#include "common/event.h"
|
#include "common/event.h"
|
||||||
|
#include "common/dpi.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
@ -98,12 +99,12 @@ struct iface
|
|||||||
unsigned int pitch;
|
unsigned int pitch;
|
||||||
unsigned int stride;
|
unsigned int stride;
|
||||||
CaptureFormat format;
|
CaptureFormat format;
|
||||||
|
unsigned int dpi;
|
||||||
|
|
||||||
int lastPointerX, lastPointerY;
|
int lastPointerX, lastPointerY;
|
||||||
bool lastPointerVisible;
|
bool lastPointerVisible;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool dpiDone = false;
|
|
||||||
static struct iface * this = NULL;
|
static struct iface * this = NULL;
|
||||||
|
|
||||||
// forwards
|
// forwards
|
||||||
@ -210,22 +211,6 @@ static bool dxgi_init()
|
|||||||
DEBUG_INFO("looking-glass-host.exe InstallService");
|
DEBUG_INFO("looking-glass-host.exe InstallService");
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is required for DXGI 1.5 support to function
|
|
||||||
if (!dpiDone)
|
|
||||||
{
|
|
||||||
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
|
|
||||||
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4)
|
|
||||||
typedef BOOL (*User32_SetProcessDpiAwarenessContext)(DPI_AWARENESS_CONTEXT value);
|
|
||||||
|
|
||||||
HMODULE user32 = LoadLibraryA("user32.dll");
|
|
||||||
User32_SetProcessDpiAwarenessContext fn;
|
|
||||||
fn = (User32_SetProcessDpiAwarenessContext)GetProcAddress(user32, "SetProcessDpiAwarenessContext");
|
|
||||||
if (fn)
|
|
||||||
fn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
|
||||||
FreeLibrary(user32);
|
|
||||||
dpiDone = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT status;
|
HRESULT status;
|
||||||
DXGI_OUTPUT_DESC outputDesc;
|
DXGI_OUTPUT_DESC outputDesc;
|
||||||
|
|
||||||
@ -388,6 +373,7 @@ static bool dxgi_init()
|
|||||||
IDXGIAdapter1_GetDesc1(this->adapter, &adapterDesc);
|
IDXGIAdapter1_GetDesc1(this->adapter, &adapterDesc);
|
||||||
this->width = outputDesc.DesktopCoordinates.right - outputDesc.DesktopCoordinates.left;
|
this->width = outputDesc.DesktopCoordinates.right - outputDesc.DesktopCoordinates.left;
|
||||||
this->height = outputDesc.DesktopCoordinates.bottom - outputDesc.DesktopCoordinates.top;
|
this->height = outputDesc.DesktopCoordinates.bottom - outputDesc.DesktopCoordinates.top;
|
||||||
|
this->dpi = monitor_dpi(outputDesc.Monitor);
|
||||||
++this->formatVer;
|
++this->formatVer;
|
||||||
|
|
||||||
DEBUG_INFO("Device Descripion: %ls" , adapterDesc.Description);
|
DEBUG_INFO("Device Descripion: %ls" , adapterDesc.Description);
|
||||||
@ -688,6 +674,14 @@ static unsigned int dxgi_getMaxFrameSize()
|
|||||||
return this->height * this->pitch;
|
return this->height * this->pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int dxgi_getMouseScale()
|
||||||
|
{
|
||||||
|
assert(this);
|
||||||
|
assert(this->initialized);
|
||||||
|
|
||||||
|
return this->dpi * 100 / DPI_100_PERCENT;
|
||||||
|
}
|
||||||
|
|
||||||
static CaptureResult dxgi_hResultToCaptureResult(const HRESULT status)
|
static CaptureResult dxgi_hResultToCaptureResult(const HRESULT status)
|
||||||
{
|
{
|
||||||
switch(status)
|
switch(status)
|
||||||
@ -1013,6 +1007,7 @@ struct CaptureInterface Capture_DXGI =
|
|||||||
.deinit = dxgi_deinit,
|
.deinit = dxgi_deinit,
|
||||||
.free = dxgi_free,
|
.free = dxgi_free,
|
||||||
.getMaxFrameSize = dxgi_getMaxFrameSize,
|
.getMaxFrameSize = dxgi_getMaxFrameSize,
|
||||||
|
.getMouseScale = dxgi_getMouseScale,
|
||||||
.capture = dxgi_capture,
|
.capture = dxgi_capture,
|
||||||
.waitFrame = dxgi_waitFrame,
|
.waitFrame = dxgi_waitFrame,
|
||||||
.getFrame = dxgi_getFrame
|
.getFrame = dxgi_getFrame
|
||||||
|
@ -25,6 +25,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "common/framebuffer.h"
|
#include "common/framebuffer.h"
|
||||||
#include "common/event.h"
|
#include "common/event.h"
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
|
#include "common/dpi.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@ -44,6 +45,7 @@ struct iface
|
|||||||
|
|
||||||
unsigned int maxWidth , maxHeight;
|
unsigned int maxWidth , maxHeight;
|
||||||
unsigned int width , height;
|
unsigned int width , height;
|
||||||
|
unsigned int dpi;
|
||||||
|
|
||||||
unsigned int formatVer;
|
unsigned int formatVer;
|
||||||
unsigned int grabWidth, grabHeight, grabStride;
|
unsigned int grabWidth, grabHeight, grabStride;
|
||||||
@ -65,7 +67,7 @@ static struct iface * this = NULL;
|
|||||||
static void nvfbc_free();
|
static void nvfbc_free();
|
||||||
static int pointerThread(void * unused);
|
static int pointerThread(void * unused);
|
||||||
|
|
||||||
static void getDesktopSize(unsigned int * width, unsigned int * height)
|
static void getDesktopSize(unsigned int * width, unsigned int * height, unsigned int * dpi)
|
||||||
{
|
{
|
||||||
HMONITOR monitor = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTOPRIMARY);
|
HMONITOR monitor = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTOPRIMARY);
|
||||||
MONITORINFO monitorInfo = {
|
MONITORINFO monitorInfo = {
|
||||||
@ -73,6 +75,7 @@ static void getDesktopSize(unsigned int * width, unsigned int * height)
|
|||||||
};
|
};
|
||||||
|
|
||||||
GetMonitorInfo(monitor, &monitorInfo);
|
GetMonitorInfo(monitor, &monitorInfo);
|
||||||
|
*dpi = monitor_dpi(monitor);
|
||||||
CloseHandle(monitor);
|
CloseHandle(monitor);
|
||||||
|
|
||||||
*width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
|
*width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
|
||||||
@ -163,7 +166,7 @@ static bool nvfbc_create(
|
|||||||
static bool nvfbc_init()
|
static bool nvfbc_init()
|
||||||
{
|
{
|
||||||
this->stop = false;
|
this->stop = false;
|
||||||
getDesktopSize(&this->width, &this->height);
|
getDesktopSize(&this->width, &this->height, &this->dpi);
|
||||||
lgResetEvent(this->frameEvent);
|
lgResetEvent(this->frameEvent);
|
||||||
|
|
||||||
HANDLE event;
|
HANDLE event;
|
||||||
@ -245,9 +248,14 @@ static unsigned int nvfbc_getMaxFrameSize()
|
|||||||
return this->maxWidth * this->maxHeight * 4;
|
return this->maxWidth * this->maxHeight * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int nvfbc_getMouseScale()
|
||||||
|
{
|
||||||
|
return this->dpi * 100 / DPI_100_PERCENT;
|
||||||
|
}
|
||||||
|
|
||||||
static CaptureResult nvfbc_capture()
|
static CaptureResult nvfbc_capture()
|
||||||
{
|
{
|
||||||
getDesktopSize(&this->width, &this->height);
|
getDesktopSize(&this->width, &this->height, &this->dpi);
|
||||||
NvFBCFrameGrabInfo grabInfo;
|
NvFBCFrameGrabInfo grabInfo;
|
||||||
CaptureResult result = NvFBCToSysCapture(
|
CaptureResult result = NvFBCToSysCapture(
|
||||||
this->nvfbc,
|
this->nvfbc,
|
||||||
@ -397,6 +405,7 @@ struct CaptureInterface Capture_NVFBC =
|
|||||||
.deinit = nvfbc_deinit,
|
.deinit = nvfbc_deinit,
|
||||||
.free = nvfbc_free,
|
.free = nvfbc_free,
|
||||||
.getMaxFrameSize = nvfbc_getMaxFrameSize,
|
.getMaxFrameSize = nvfbc_getMaxFrameSize,
|
||||||
|
.getMouseScale = nvfbc_getMouseScale,
|
||||||
.capture = nvfbc_capture,
|
.capture = nvfbc_capture,
|
||||||
.waitFrame = nvfbc_waitFrame,
|
.waitFrame = nvfbc_waitFrame,
|
||||||
.getFrame = nvfbc_getFrame
|
.getFrame = nvfbc_getFrame
|
||||||
|
@ -226,6 +226,18 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
// setup a handler for ctrl+c
|
// setup a handler for ctrl+c
|
||||||
SetConsoleCtrlHandler(CtrlHandler, TRUE);
|
SetConsoleCtrlHandler(CtrlHandler, TRUE);
|
||||||
|
|
||||||
|
// enable high DPI awareness
|
||||||
|
// this is required for DXGI 1.5 support to function and also capturing desktops with high DPI
|
||||||
|
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
|
||||||
|
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4)
|
||||||
|
typedef BOOL (*User32_SetProcessDpiAwarenessContext)(DPI_AWARENESS_CONTEXT value);
|
||||||
|
|
||||||
|
HMODULE user32 = GetModuleHandle("user32.dll");
|
||||||
|
User32_SetProcessDpiAwarenessContext fn;
|
||||||
|
fn = (User32_SetProcessDpiAwarenessContext)GetProcAddress(user32, "SetProcessDpiAwarenessContext");
|
||||||
|
if (fn)
|
||||||
|
fn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||||
|
|
||||||
// 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);
|
||||||
@ -249,7 +261,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
app.messageWnd = CreateWindowEx(0, MAKEINTATOM(class), NULL, 0, 0, 0, 0, 0, NULL, NULL, hInstance, NULL);
|
app.messageWnd = CreateWindowEx(0, MAKEINTATOM(class), NULL, 0, 0, 0, 0, 0, NULL, NULL, hInstance, NULL);
|
||||||
|
|
||||||
// this is needed so that unprivileged processes can send us this message
|
// this is needed so that unprivileged processes can send us this message
|
||||||
HMODULE user32 = GetModuleHandle("user32.dll");
|
|
||||||
_ChangeWindowMessageFilterEx = (PChangeWindowMessageFilterEx)GetProcAddress(user32, "ChangeWindowMessageFilterEx");
|
_ChangeWindowMessageFilterEx = (PChangeWindowMessageFilterEx)GetProcAddress(user32, "ChangeWindowMessageFilterEx");
|
||||||
if (_ChangeWindowMessageFilterEx)
|
if (_ChangeWindowMessageFilterEx)
|
||||||
_ChangeWindowMessageFilterEx(app.messageWnd, app.trayRestartMsg, MSGFLT_ALLOW, NULL);
|
_ChangeWindowMessageFilterEx(app.messageWnd, app.trayRestartMsg, MSGFLT_ALLOW, NULL);
|
||||||
|
@ -186,13 +186,14 @@ static int frameThread(void * opaque)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
fi->formatVer = frame.formatVer;
|
fi->formatVer = frame.formatVer;
|
||||||
fi->width = frame.width;
|
fi->width = frame.width;
|
||||||
fi->height = frame.height;
|
fi->height = frame.height;
|
||||||
fi->stride = frame.stride;
|
fi->stride = frame.stride;
|
||||||
fi->pitch = frame.pitch;
|
fi->pitch = frame.pitch;
|
||||||
fi->offset = pageSize - FrameBufferStructSize;
|
fi->offset = pageSize - FrameBufferStructSize;
|
||||||
frameValid = true;
|
fi->mouseScalePercent = app.iface->getMouseScale();
|
||||||
|
frameValid = true;
|
||||||
|
|
||||||
// put the framebuffer on the border of the next page
|
// put the framebuffer on the border of the next page
|
||||||
// this is to allow for aligned DMA transfers by the receiver
|
// this is to allow for aligned DMA transfers by the receiver
|
||||||
|
Loading…
x
Reference in New Issue
Block a user