diff --git a/idd/LGIdd/util/CSRWLock.h b/idd/LGCommon/CSRWLock.h similarity index 100% rename from idd/LGIdd/util/CSRWLock.h rename to idd/LGCommon/CSRWLock.h diff --git a/idd/LGIdd.sln b/idd/LGIdd.sln index 7af20bf9..30bd53ca 100644 --- a/idd/LGIdd.sln +++ b/idd/LGIdd.sln @@ -6,9 +6,12 @@ MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LGIdd", "LGIdd\LGIdd.vcxproj", "{1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}" ProjectSection(ProjectDependencies) = postProject {0045D7AD-3F26-4B87-81CB-78D18839596D} = {0045D7AD-3F26-4B87-81CB-78D18839596D} + {23EC8370-5F3B-4D18-8C31-E89A154F3666} = {23EC8370-5F3B-4D18-8C31-E89A154F3666} {FFCC376C-4D98-4B50-B431-E1BBC9C67E65} = {FFCC376C-4D98-4B50-B431-E1BBC9C67E65} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LGInput", "LGInput\LGInput.vcxproj", "{2477B25B-CB62-4AD9-A260-CE5F00D77EEB}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LGMP", "..\repos\LGMP\LGMP.vcxproj", "{FFCC376C-4D98-4B50-B431-E1BBC9C67E65}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LGIddHelper", "LGIddHelper\LGIddHelper.vcxproj", "{0045D7AD-3F26-4B87-81CB-78D18839596D}" @@ -17,6 +20,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LGCommon", "LGCommon", "{AC ProjectSection(SolutionItems) = preProject LGCommon\CDebug.cpp = LGCommon\CDebug.cpp LGCommon\CDebug.h = LGCommon\CDebug.h + LGCommon\CSRWLock.h = LGCommon\CSRWLock.h LGCommon\DefaultDisplayModes.h = LGCommon\DefaultDisplayModes.h LGCommon\PipeMsg.h = LGCommon\PipeMsg.h EndProjectSection @@ -26,49 +30,55 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 + Debug-LGInput|x64 = Debug-LGInput|x64 Release|x64 = Release|x64 - Release|x86 = Release|x86 + Release-LGInput|x64 = Release-LGInput|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|x64.ActiveCfg = Debug|x64 {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|x64.Build.0 = Debug|x64 {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|x64.Deploy.0 = Debug|x64 - {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|x86.ActiveCfg = Debug|Win32 - {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|x86.Build.0 = Debug|Win32 - {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug|x86.Deploy.0 = Debug|Win32 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug-LGInput|x64.ActiveCfg = Debug-LGInput|x64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug-LGInput|x64.Build.0 = Debug-LGInput|x64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Debug-LGInput|x64.Deploy.0 = Debug-LGInput|x64 {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|x64.ActiveCfg = Release|x64 {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|x64.Build.0 = Release|x64 {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|x64.Deploy.0 = Release|x64 - {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|x86.ActiveCfg = Release|Win32 - {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|x86.Build.0 = Release|Win32 - {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release|x86.Deploy.0 = Release|Win32 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release-LGInput|x64.ActiveCfg = Release-LGInput|x64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release-LGInput|x64.Build.0 = Release-LGInput|x64 + {1CBF3DAA-0726-4F5F-88A2-04D95FB6591A}.Release-LGInput|x64.Deploy.0 = Release-LGInput|x64 + {2477B25B-CB62-4AD9-A260-CE5F00D77EEB}.Debug|x64.ActiveCfg = Debug|x64 + {2477B25B-CB62-4AD9-A260-CE5F00D77EEB}.Debug|x64.Build.0 = Debug|x64 + {2477B25B-CB62-4AD9-A260-CE5F00D77EEB}.Debug-LGInput|x64.ActiveCfg = Debug|x64 + {2477B25B-CB62-4AD9-A260-CE5F00D77EEB}.Debug-LGInput|x64.Build.0 = Debug|x64 + {2477B25B-CB62-4AD9-A260-CE5F00D77EEB}.Release|x64.ActiveCfg = Release|x64 + {2477B25B-CB62-4AD9-A260-CE5F00D77EEB}.Release|x64.Build.0 = Release|x64 + {2477B25B-CB62-4AD9-A260-CE5F00D77EEB}.Release-LGInput|x64.ActiveCfg = Release|x64 + {2477B25B-CB62-4AD9-A260-CE5F00D77EEB}.Release-LGInput|x64.Build.0 = Release|x64 {FFCC376C-4D98-4B50-B431-E1BBC9C67E65}.Debug|x64.ActiveCfg = Debug|x64 {FFCC376C-4D98-4B50-B431-E1BBC9C67E65}.Debug|x64.Build.0 = Debug|x64 - {FFCC376C-4D98-4B50-B431-E1BBC9C67E65}.Debug|x86.ActiveCfg = Debug|Win32 - {FFCC376C-4D98-4B50-B431-E1BBC9C67E65}.Debug|x86.Build.0 = Debug|Win32 - {FFCC376C-4D98-4B50-B431-E1BBC9C67E65}.Debug|x86.Deploy.0 = Debug|Win32 + {FFCC376C-4D98-4B50-B431-E1BBC9C67E65}.Debug-LGInput|x64.ActiveCfg = Debug|x64 + {FFCC376C-4D98-4B50-B431-E1BBC9C67E65}.Debug-LGInput|x64.Build.0 = Debug|x64 {FFCC376C-4D98-4B50-B431-E1BBC9C67E65}.Release|x64.ActiveCfg = Release|x64 {FFCC376C-4D98-4B50-B431-E1BBC9C67E65}.Release|x64.Build.0 = Release|x64 - {FFCC376C-4D98-4B50-B431-E1BBC9C67E65}.Release|x86.ActiveCfg = Release|Win32 - {FFCC376C-4D98-4B50-B431-E1BBC9C67E65}.Release|x86.Build.0 = Release|Win32 - {FFCC376C-4D98-4B50-B431-E1BBC9C67E65}.Release|x86.Deploy.0 = Release|Win32 + {FFCC376C-4D98-4B50-B431-E1BBC9C67E65}.Release-LGInput|x64.ActiveCfg = Release|x64 + {FFCC376C-4D98-4B50-B431-E1BBC9C67E65}.Release-LGInput|x64.Build.0 = Release|x64 {0045D7AD-3F26-4B87-81CB-78D18839596D}.Debug|x64.ActiveCfg = Debug|x64 {0045D7AD-3F26-4B87-81CB-78D18839596D}.Debug|x64.Build.0 = Debug|x64 - {0045D7AD-3F26-4B87-81CB-78D18839596D}.Debug|x86.ActiveCfg = Debug|Win32 - {0045D7AD-3F26-4B87-81CB-78D18839596D}.Debug|x86.Build.0 = Debug|Win32 + {0045D7AD-3F26-4B87-81CB-78D18839596D}.Debug-LGInput|x64.ActiveCfg = Debug|x64 + {0045D7AD-3F26-4B87-81CB-78D18839596D}.Debug-LGInput|x64.Build.0 = Debug|x64 {0045D7AD-3F26-4B87-81CB-78D18839596D}.Release|x64.ActiveCfg = Release|x64 {0045D7AD-3F26-4B87-81CB-78D18839596D}.Release|x64.Build.0 = Release|x64 - {0045D7AD-3F26-4B87-81CB-78D18839596D}.Release|x86.ActiveCfg = Release|Win32 - {0045D7AD-3F26-4B87-81CB-78D18839596D}.Release|x86.Build.0 = Release|Win32 + {0045D7AD-3F26-4B87-81CB-78D18839596D}.Release-LGInput|x64.ActiveCfg = Release|x64 + {0045D7AD-3F26-4B87-81CB-78D18839596D}.Release-LGInput|x64.Build.0 = Release|x64 {23EC8370-5F3B-4D18-8C31-E89A154F3666}.Debug|x64.ActiveCfg = Debug|x64 {23EC8370-5F3B-4D18-8C31-E89A154F3666}.Debug|x64.Build.0 = Debug|x64 - {23EC8370-5F3B-4D18-8C31-E89A154F3666}.Debug|x86.ActiveCfg = Debug|Win32 - {23EC8370-5F3B-4D18-8C31-E89A154F3666}.Debug|x86.Build.0 = Debug|Win32 + {23EC8370-5F3B-4D18-8C31-E89A154F3666}.Debug-LGInput|x64.ActiveCfg = Debug|x64 + {23EC8370-5F3B-4D18-8C31-E89A154F3666}.Debug-LGInput|x64.Build.0 = Debug|x64 {23EC8370-5F3B-4D18-8C31-E89A154F3666}.Release|x64.ActiveCfg = Release|x64 {23EC8370-5F3B-4D18-8C31-E89A154F3666}.Release|x64.Build.0 = Release|x64 - {23EC8370-5F3B-4D18-8C31-E89A154F3666}.Release|x86.ActiveCfg = Release|Win32 - {23EC8370-5F3B-4D18-8C31-E89A154F3666}.Release|x86.Build.0 = Release|Win32 + {23EC8370-5F3B-4D18-8C31-E89A154F3666}.Release-LGInput|x64.ActiveCfg = Release|x64 + {23EC8370-5F3B-4D18-8C31-E89A154F3666}.Release-LGInput|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/idd/LGIdd/LGIdd.vcxproj b/idd/LGIdd/LGIdd.vcxproj index eb0c3bc5..3edb4197 100644 --- a/idd/LGIdd/LGIdd.vcxproj +++ b/idd/LGIdd/LGIdd.vcxproj @@ -18,6 +18,14 @@ Release x64 + + Debug-LGInput + x64 + + + Release-LGInput + x64 + @@ -109,7 +117,6 @@ - @@ -121,8 +128,14 @@ 12.0 Debug Win32 + Debug + Release + $(Configuration) + true LGIdd 10.0.26100.0 + $([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)\..')) + $(LGDriverSolutionDir) WindowsUserModeDriver10.0 @@ -134,11 +147,11 @@ DynamicLibrary Universal - + DynamicLibrary Universal - + DynamicLibrary Universal @@ -167,7 +180,7 @@ 25 <_NT_TARGET_VERSION>0xA000005 - + Windows10 true 2 @@ -180,7 +193,7 @@ <_NT_TARGET_VERSION>0xA000005 WindowsUserModeDriver10.0 - + Windows10 false 2 @@ -208,14 +221,18 @@ DbgengRemoteDebugger true - + DbgengRemoteDebugger true - + DbgengRemoteDebugger true + + $([MSBuild]::NormalizeDirectory('$(LGDriverSolutionDir)$(Platform)\$(LGBaseConfiguration)')) + $([MSBuild]::NormalizeDirectory('$(LGDriverSolutionDir)$(LGBaseConfiguration)')) + true @@ -246,7 +263,7 @@ SHA1 - + true true @@ -261,7 +278,7 @@ SHA1 - + true true @@ -278,13 +295,58 @@ + + + + + + + + {2477b25b-cb62-4ad9-a260-ce5f00d77eeb} + false + false + LGInput + Configuration=$(LGBaseConfiguration);Platform=$(Platform);SolutionDir=$(LGDriverSolutionDir) + {ffcc376c-4d98-4b50-b431-e1bbc9c67e65} + Configuration=$(LGBaseConfiguration);Platform=$(Platform);SolutionDir=$(LGDriverSolutionDir) + + false + CustomCommand + %ComSpec% /d /s /c LGIddInstall.exe install LGIdd LGInput + %ComSpec% /d /s /c LGIddInstall.exe install LGInput LGIdd + $(PackageDir)LGIddInstall.exe + + + + + + + + + PackageTestSign + PackageProductionSign + Inf2Cat + + + + + diff --git a/idd/LGIdd/LGIdd.vcxproj.filters b/idd/LGIdd/LGIdd.vcxproj.filters index 8c7e3b6f..03dd0305 100644 --- a/idd/LGIdd/LGIdd.vcxproj.filters +++ b/idd/LGIdd/LGIdd.vcxproj.filters @@ -193,9 +193,6 @@ Platform - - Utilities - diff --git a/idd/LGIdd/capture/CHardwareFrameProcessor.cpp b/idd/LGIdd/capture/CHardwareFrameProcessor.cpp index bcad171e..abd4a742 100644 --- a/idd/LGIdd/capture/CHardwareFrameProcessor.cpp +++ b/idd/LGIdd/capture/CHardwareFrameProcessor.cpp @@ -21,7 +21,7 @@ #include "capture/CHardwareFrameProcessor.h" #include "capture/CFrameProcessorUtil.h" #include "transport/IFrameTransport.h" -#include "util/CSRWLock.h" +#include "CSRWLock.h" #include "CDebug.h" #include diff --git a/idd/LGIdd/capture/CSoftwareFrameProcessor.cpp b/idd/LGIdd/capture/CSoftwareFrameProcessor.cpp index 4699d610..fad3575c 100644 --- a/idd/LGIdd/capture/CSoftwareFrameProcessor.cpp +++ b/idd/LGIdd/capture/CSoftwareFrameProcessor.cpp @@ -21,8 +21,8 @@ #include "capture/CSoftwareFrameProcessor.h" #include "capture/CFrameProcessorUtil.h" #include "capture/FramePipeline.h" +#include "CSRWLock.h" #include "transport/IFrameTransport.h" -#include "util/CSRWLock.h" #include "CDebug.h" #include diff --git a/idd/LGIdd/capture/CSwapChainProcessor.cpp b/idd/LGIdd/capture/CSwapChainProcessor.cpp index 2d6010b2..d40baeb9 100644 --- a/idd/LGIdd/capture/CSwapChainProcessor.cpp +++ b/idd/LGIdd/capture/CSwapChainProcessor.cpp @@ -20,13 +20,13 @@ #include "capture/CSwapChainProcessor.h" #include "capture/CFrameProcessorUtil.h" +#include "CSRWLock.h" #include "display/IddCxCompat.h" #include "display/CDeviceContext.h" #include "display/CMonitorContext.h" #include "platform/CPlatformInfo.h" #include "transport/IFrameTransport.h" #include "transport/IControlTransport.h" -#include "util/CSRWLock.h" #include #include diff --git a/idd/LGIdd/display/CDisplayConfiguration.cpp b/idd/LGIdd/display/CDisplayConfiguration.cpp index 3be72330..a2fc511e 100644 --- a/idd/LGIdd/display/CDisplayConfiguration.cpp +++ b/idd/LGIdd/display/CDisplayConfiguration.cpp @@ -21,7 +21,7 @@ #include "display/CDisplayConfiguration.h" #include "CDebug.h" -#include "util/CSRWLock.h" +#include "CSRWLock.h" #include #include diff --git a/idd/LGIddInstall/LGIddInstall.c b/idd/LGIddInstall/LGIddInstall.c index dcd60c05..abd38bc9 100644 --- a/idd/LGIddInstall/LGIddInstall.c +++ b/idd/LGIddInstall/LGIddInstall.c @@ -36,17 +36,76 @@ #define LGIDD_CLASS_GUID GUID_DEVCLASS_DISPLAY #define LGIDD_CLASS_NAME L"Display" +#define LGIDD_NAME L"LGIdd" #define LGIDD_HWID L"Root\\LGIdd" #define LGIDD_HWID_MULTI_SZ (LGIDD_HWID "\0") #define LGIDD_INF_NAME L"LGIdd.inf" +#define LGIDD_PACKAGE_DIR L"LGIdd" +#define LGINPUT_CLASS_GUID GUID_DEVCLASS_HIDCLASS +#define LGINPUT_CLASS_NAME L"HIDClass" +#define LGINPUT_NAME L"LGInput" +#define LGINPUT_HWID L"Root\\LGInput" +#define LGINPUT_HWID_MULTI_SZ (LGINPUT_HWID "\0") +#define LGINPUT_INF_NAME L"LGInput.inf" +#define LGINPUT_PACKAGE_DIR L"LGInput" #define LGIDD_REGKEY L"Software\\LookingGlass\\IDD" +#define DEVICE_COUNT 2 + +typedef struct DeviceDesc +{ + const GUID *classGuid; + LPCWSTR className; + LPCWSTR name; + LPCWSTR hardwareId; + LPCWSTR hardwareIdMultiSz; + DWORD hardwareIdMultiSzSize; + LPCWSTR infName; + LPCWSTR packageDir; +} +DeviceDesc; + +static const DeviceDesc LGIDD_DEVICE = +{ + .classGuid = &LGIDD_CLASS_GUID, + .className = LGIDD_CLASS_NAME, + .name = LGIDD_NAME, + .hardwareId = LGIDD_HWID, + .hardwareIdMultiSz = LGIDD_HWID_MULTI_SZ, + .hardwareIdMultiSzSize = sizeof LGIDD_HWID_MULTI_SZ, + .infName = LGIDD_INF_NAME, + .packageDir = LGIDD_PACKAGE_DIR, +}; + +static const DeviceDesc LGINPUT_DEVICE = +{ + .classGuid = &LGINPUT_CLASS_GUID, + .className = LGINPUT_CLASS_NAME, + .name = LGINPUT_NAME, + .hardwareId = LGINPUT_HWID, + .hardwareIdMultiSz = LGINPUT_HWID_MULTI_SZ, + .hardwareIdMultiSzSize = sizeof LGINPUT_HWID_MULTI_SZ, + .infName = LGINPUT_INF_NAME, + .packageDir = LGINPUT_PACKAGE_DIR, +}; void usage(wchar_t *program) { - wprintf(L"Usage: %s \n", program); + wprintf(L"Usage: %s install [LGIdd LGInput|LGInput LGIdd]\n", program); + wprintf(L" %s uninstall\n", program); exit(2); } +const DeviceDesc *getDeviceByName(LPCWSTR name) +{ + if (!_wcsicmp(name, LGIDD_DEVICE.name)) + return &LGIDD_DEVICE; + + if (!_wcsicmp(name, LGINPUT_DEVICE.name)) + return &LGINPUT_DEVICE; + + return NULL; +} + void debugWinError(const wchar_t *desc, HRESULT status) { wchar_t *buffer; @@ -154,11 +213,18 @@ DWORD deleteKeyTreeHKLM() return ec; } -typedef bool (*IDD_FOUND_PROC)(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDevInfo, void *pContext); +typedef bool (*DEVICE_FOUND_PROC)(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDevInfo, void *pContext); -bool findIddDevice(IDD_FOUND_PROC procFound, void *pContext) +typedef struct DeviceRemovalContext { - HDEVINFO hDevInfo = SetupDiGetClassDevsW(&LGIDD_CLASS_GUID, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT); + LPBOOL pbNeedRestart; + bool success; +} +DeviceRemovalContext; + +bool findDevice(const DeviceDesc *device, DEVICE_FOUND_PROC procFound, void *pContext) +{ + HDEVINFO hDevInfo = SetupDiGetClassDevsW(device->classGuid, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT); if (hDevInfo == INVALID_HANDLE_VALUE) { debugWinError(L"SetupDiGetClassDevsW", GetLastError()); @@ -205,7 +271,7 @@ bool findIddDevice(IDD_FOUND_PROC procFound, void *pContext) for (LPWSTR lpHwId = lpBuffer; *lpHwId; lpHwId += wcslen(lpBuffer) + 1) { - if (!lstrcmpiW(lpHwId, LGIDD_HWID)) + if (!lstrcmpiW(lpHwId, device->hardwareId)) { found = true; break; @@ -232,24 +298,24 @@ enum DeviceCreated { DEVICE_UNKNOWN, }; -bool isIddDeviceCreatedEnum(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDevInfo, void *pContext) +bool isDeviceCreatedEnum(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDevInfo, void *pContext) { enum DeviceCreated *result = pContext; *result = DEVICE_CREATED; return false; } -enum DeviceCreated isIddDeviceCreated() +enum DeviceCreated isDeviceCreated(const DeviceDesc *device) { enum DeviceCreated result = DEVICE_UNKNOWN; - if (findIddDevice(isIddDeviceCreatedEnum, &result) && result == DEVICE_UNKNOWN) + if (findDevice(device, isDeviceCreatedEnum, &result) && result == DEVICE_UNKNOWN) result = DEVICE_NOT_CREATED; return result; } -bool createIddDevice(void) +bool createDevice(const DeviceDesc *device) { - HDEVINFO hDevInfo = SetupDiCreateDeviceInfoList(&LGIDD_CLASS_GUID, NULL); + HDEVINFO hDevInfo = SetupDiCreateDeviceInfoList(device->classGuid, NULL); if (hDevInfo == INVALID_HANDLE_VALUE) { debugWinError(L"SetupDiCreateDeviceInfoList", GetLastError()); @@ -257,13 +323,14 @@ bool createIddDevice(void) } SP_DEVINFO_DATA devInfo = { .cbSize = sizeof devInfo, 0 }; - if (!SetupDiCreateDeviceInfoW(hDevInfo, LGIDD_CLASS_NAME, &LGIDD_CLASS_GUID, NULL, NULL, DICD_GENERATE_ID, &devInfo)) + if (!SetupDiCreateDeviceInfoW(hDevInfo, device->className, device->classGuid, NULL, NULL, DICD_GENERATE_ID, &devInfo)) { debugWinError(L"SetupDiCreateDeviceInfoW", GetLastError()); goto fail; } - if (!SetupDiSetDeviceRegistryPropertyW(hDevInfo, &devInfo, SPDRP_HARDWAREID, (PBYTE) LGIDD_HWID_MULTI_SZ, sizeof LGIDD_HWID_MULTI_SZ)) + if (!SetupDiSetDeviceRegistryPropertyW(hDevInfo, &devInfo, SPDRP_HARDWAREID, + (PBYTE) device->hardwareIdMultiSz, device->hardwareIdMultiSzSize)) { debugWinError(L"SetupDiSetDeviceRegistryPropertyW", GetLastError()); goto fail; @@ -282,9 +349,9 @@ fail: return false; } -bool destroyIddDeviceEnum(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDevInfo, void* pContext) +bool destroyDeviceEnum(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDevInfo, void *pContext) { - LPBOOL pbNeedRestart = pContext; + DeviceRemovalContext *context = pContext; BOOL bNeedRestart; WCHAR szInfPath[MAX_PATH] = { 0 }; @@ -312,40 +379,39 @@ bool destroyIddDeviceEnum(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDevInfo, void* pC uninstall: if (DiUninstallDevice(NULL, hDevInfo, pDevInfo, 0, &bNeedRestart)) - *pbNeedRestart |= bNeedRestart; + *context->pbNeedRestart |= bNeedRestart; else { debugWinError(L"DiUninstallDevice", GetLastError()); + context->success = false; return true; } if (*szInfPath) { if (DiUninstallDriverW(NULL, szInfPath, 0, &bNeedRestart)) - *pbNeedRestart |= bNeedRestart; + *context->pbNeedRestart |= bNeedRestart; else + { debugWinError(L"DiUninstallDriverW", GetLastError()); - } - - DWORD ec = deleteKeyTreeHKLM(); - if (ec != ERROR_SUCCESS) - { - debugWinError(L"deleteKeyTreeHKLM failed", ec); - // this is non-fatal + context->success = false; + } } return true; } -void destroyIddDevice(LPBOOL pbNeedRestart) +bool destroyDevice(const DeviceDesc *device, LPBOOL pbNeedRestart) { - findIddDevice(destroyIddDeviceEnum, pbNeedRestart); + DeviceRemovalContext context = { pbNeedRestart, true }; + + return findDevice(device, destroyDeviceEnum, &context) && context.success; } -bool getIddInfPath(LPWSTR lpszInf) +bool getInfPath(const DeviceDesc *device, LPWSTR lpszInf) { WCHAR szDir[MAX_PATH]; - WCHAR szInf[MAX_PATH]; + WCHAR szPackageDir[MAX_PATH]; if (!GetModuleFileNameW(NULL, szDir, MAX_PATH)) { @@ -354,7 +420,7 @@ bool getIddInfPath(LPWSTR lpszInf) } *PathFindFileNameW(szDir) = 0; - if (!PathCombineW(lpszInf, szDir, LGIDD_INF_NAME)) + if (!PathCombineW(lpszInf, szDir, device->infName)) { debugWinError(L"PathCombineW", GetLastError()); return false; @@ -362,18 +428,28 @@ bool getIddInfPath(LPWSTR lpszInf) if (!PathFileExistsW(lpszInf)) { - fwprintf(stderr, L"INF file does not exist: %s\n", szInf); - return false; + if (!PathCombineW(szPackageDir, szDir, device->packageDir) || + !PathCombineW(lpszInf, szPackageDir, device->infName)) + { + debugWinError(L"PathCombineW", GetLastError()); + return false; + } + + if (!PathFileExistsW(lpszInf)) + { + fwprintf(stderr, L"INF file does not exist: %s\n", lpszInf); + return false; + } } return true; } -bool installIddInf(PBOOL pbNeedRestart) +bool installInf(const DeviceDesc *device, PBOOL pbNeedRestart) { WCHAR szInf[MAX_PATH]; - if (!getIddInfPath(szInf)) + if (!getInfPath(device, szInf)) return false; if (!DiInstallDriverW(NULL, szInf, DIIRFLAG_FORCE_INF, pbNeedRestart)) @@ -385,41 +461,75 @@ bool installIddInf(PBOOL pbNeedRestart) return true; } -void install() +void install(const DeviceDesc *const devices[DEVICE_COUNT]) { - switch (isIddDeviceCreated()) + enum DeviceCreated created[DEVICE_COUNT]; + + for (size_t i = 0; i < DEVICE_COUNT; ++i) { - case DEVICE_NOT_CREATED: - wprintf(L"Creating LGIdd device: %s...\n", LGIDD_HWID); - if (!createIddDevice()) + created[i] = isDeviceCreated(devices[i]); + if (created[i] == DEVICE_UNKNOWN) exit(1); + } - // fallthrough - case DEVICE_CREATED: - _putws(L"Preparing registry key..."); - if (!ensureKeyWithAce()) - exit(1); - - _putws(L"Installing INF..."); - BOOL bNeedRestart; - if (!installIddInf(&bNeedRestart)) - exit(1); - - if (bNeedRestart) - { - _putws(L"Restart required to complete installation"); - exit(12); - } - break; - case DEVICE_UNKNOWN: + _putws(L"Preparing registry key..."); + if (!ensureKeyWithAce()) exit(1); + + BOOL bNeedRestart = FALSE; + BOOL bInfNeedRestart = FALSE; + + for (size_t i = 0; i < DEVICE_COUNT; ++i) + { + const DeviceDesc *device = devices[i]; + + if (created[i] == DEVICE_NOT_CREATED) + { + wprintf(L"Preinstalling %s INF...\n", device->name); + bInfNeedRestart = FALSE; + if (!installInf(device, &bInfNeedRestart)) + exit(1); + bNeedRestart |= bInfNeedRestart; + + wprintf(L"Creating %s device: %s...\n", device->name, device->hardwareId); + if (!createDevice(device)) + exit(1); + } + + wprintf(L"Installing %s INF...\n", device->name); + bInfNeedRestart = FALSE; + if (!installInf(device, &bInfNeedRestart)) + exit(1); + bNeedRestart |= bInfNeedRestart; + } + + if (bNeedRestart) + { + _putws(L"Restart required to complete installation"); + exit(12); } } void uninstall() { BOOL bNeedRestart = 0; - destroyIddDevice(&bNeedRestart); + bool success = true; + + _putws(L"Uninstalling LGInput..."); + success &= destroyDevice(&LGINPUT_DEVICE, &bNeedRestart); + + _putws(L"Uninstalling LGIdd..."); + success &= destroyDevice(&LGIDD_DEVICE, &bNeedRestart); + + DWORD ec = deleteKeyTreeHKLM(); + if (ec != ERROR_SUCCESS) + { + debugWinError(L"deleteKeyTreeHKLM failed", ec); + // this is non-fatal + } + + if (!success) + exit(1); if (bNeedRestart) { @@ -432,13 +542,32 @@ int wmain(int argc, wchar_t **argv) { _setmode(_fileno(stderr), _O_U16TEXT); - if (argc != 2) + if (argc < 2) usage(argv[0]); if (!wcscmp(argv[1], L"install")) - install(); + { + const DeviceDesc *devices[DEVICE_COUNT] = { &LGIDD_DEVICE, &LGINPUT_DEVICE }; + + if (argc != 2) + { + if (argc != 4) + usage(argv[0]); + + devices[0] = getDeviceByName(argv[2]); + devices[1] = getDeviceByName(argv[3]); + if (!devices[0] || !devices[1] || devices[0] == devices[1]) + usage(argv[0]); + } + + install(devices); + } else if (!wcscmp(argv[1], L"uninstall")) + { + if (argc != 2) + usage(argv[0]); uninstall(); + } else usage(argv[0]); } diff --git a/idd/LGInput/CHIDDevice.cpp b/idd/LGInput/CHIDDevice.cpp new file mode 100644 index 00000000..edad1cc3 --- /dev/null +++ b/idd/LGInput/CHIDDevice.cpp @@ -0,0 +1,400 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * 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 "CHIDDevice.h" + +#include "CSRWLock.h" +#include "HIDReports.h" + +#include + +static constexpr USHORT LG_INPUT_VENDOR_ID = 0x0000; +static constexpr USHORT LG_INPUT_PRODUCT_ID = 0x0000; +static constexpr USHORT LG_INPUT_VERSION = 0x0001; +static constexpr size_t REPORT_QUEUE_LENGTH = 64; + +struct HIDQueuedReport +{ + UCHAR data[sizeof(HIDKeyboardReport)]; + size_t size; +}; + +struct HIDDeviceContext +{ + WDFQUEUE reportQueue; + HID_DEVICE_ATTRIBUTES attributes; + HID_DESCRIPTOR descriptor; + UCHAR keyboardLeds; + SRWLOCK reportLock; + bool active; + bool stopping; + size_t reportHead; + size_t reportCount; + HIDQueuedReport reports[REPORT_QUEUE_LENGTH]; +}; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(HIDDeviceContext, HIDGetDeviceContext); + +static SRWLOCK s_deviceLock = SRWLOCK_INIT; +static HIDDeviceContext * s_device = nullptr; + +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL HIDEvtIoDeviceControl; +EVT_WDF_OBJECT_CONTEXT_CLEANUP HIDEvtReportQueueCleanup; + +static NTSTATUS CopyToRequest( + _In_ WDFREQUEST request, + _In_reads_bytes_(size) const void * buffer, + _In_ size_t size) +{ + WDFMEMORY memory; + NTSTATUS status = WdfRequestRetrieveOutputMemory(request, &memory); + if (!NT_SUCCESS(status)) + return status; + + size_t bufferSize; + WdfMemoryGetBuffer(memory, &bufferSize); + if (bufferSize < size) + return STATUS_BUFFER_TOO_SMALL; + + status = WdfMemoryCopyFromBuffer( + memory, 0, const_cast(buffer), size); + if (NT_SUCCESS(status)) + WdfRequestSetInformation(request, size); + + return status; +} + +static NTSTATUS GetOutputReport( + _In_ WDFREQUEST request, + _Out_ HID_XFER_PACKET * packet) +{ + WDFMEMORY memory; + NTSTATUS status = WdfRequestRetrieveOutputMemory(request, &memory); + if (!NT_SUCCESS(status)) + return status; + + // mshidumdf carries the report ID in the output buffer length. + size_t outputBufferLength; + WdfMemoryGetBuffer(memory, &outputBufferLength); + packet->reportId = static_cast(outputBufferLength); + + status = WdfRequestRetrieveInputMemory(request, &memory); + if (!NT_SUCCESS(status)) + return status; + + size_t reportSize; + packet->reportBuffer = + static_cast(WdfMemoryGetBuffer(memory, &reportSize)); + packet->reportBufferLen = static_cast(reportSize); + return STATUS_SUCCESS; +} + +static NTSTATUS SetOutputReport( + _In_ WDFQUEUE queue, + _In_ WDFREQUEST request) +{ + HID_XFER_PACKET packet = {}; + NTSTATUS status = GetOutputReport(request, &packet); + if (!NT_SUCCESS(status)) + return status; + + if (packet.reportId != HID_REPORT_ID_KEYBOARD || + packet.reportBufferLen < sizeof(HIDKeyboardLedsReport)) + return STATUS_INVALID_PARAMETER; + + const HIDKeyboardLedsReport * report = + reinterpret_cast(packet.reportBuffer); + if (report->reportId != HID_REPORT_ID_KEYBOARD) + return STATUS_INVALID_PARAMETER; + + WDFDEVICE device = WdfIoQueueGetDevice(queue); + HIDGetDeviceContext(device)->keyboardLeds = report->leds; + WdfRequestSetInformation(request, sizeof(*report)); + return STATUS_SUCCESS; +} + +static void PopReport( + _Inout_ HIDDeviceContext * context, + _Out_ HIDQueuedReport * report) +{ + *report = context->reports[context->reportHead]; + context->reportHead = + (context->reportHead + 1) % REPORT_QUEUE_LENGTH; + --context->reportCount; +} + +static NTSTATUS QueueReport( + _Inout_ HIDDeviceContext * context, + _In_reads_bytes_(size) const void * data, + _In_ size_t size) +{ + if (context->reportCount == REPORT_QUEUE_LENGTH) + return STATUS_BUFFER_OVERFLOW; + + const size_t index = + (context->reportHead + context->reportCount) % REPORT_QUEUE_LENGTH; + HIDQueuedReport * report = &context->reports[index]; + CopyMemory(report->data, data, size); + report->size = size; + ++context->reportCount; + return STATUS_SUCCESS; +} + +static NTSTATUS ReadReport( + _In_ HIDDeviceContext * context, + _In_ WDFREQUEST request, + _Out_ bool * complete) +{ + HIDQueuedReport report = {}; + bool haveReport = false; + *complete = true; + + NTSTATUS status; + { + CSRWExclusiveLock lock(&context->reportLock); + if (context->stopping || !context->active) + status = STATUS_DEVICE_NOT_READY; + else if (context->reportCount) + { + PopReport(context, &report); + haveReport = true; + status = STATUS_SUCCESS; + } + else + { + status = WdfRequestForwardToIoQueue(request, context->reportQueue); + *complete = !NT_SUCCESS(status); + } + } + + if (haveReport) + status = CopyToRequest(request, report.data, report.size); + return status; +} + +static NTSTATUS ActivateDevice(_Inout_ HIDDeviceContext * context) +{ + CSRWExclusiveLock lock(&context->reportLock); + if (context->stopping) + return STATUS_DEVICE_NOT_READY; + + WdfIoQueueStart(context->reportQueue); + context->active = true; + return STATUS_SUCCESS; +} + +static NTSTATUS DeactivateDevice(_Inout_ HIDDeviceContext * context) +{ + CSRWExclusiveLock lock(&context->reportLock); + if (context->stopping) + return STATUS_DEVICE_NOT_READY; + + context->active = false; + context->reportHead = 0; + context->reportCount = 0; + WdfIoQueuePurgeSynchronously(context->reportQueue); + return STATUS_SUCCESS; +} + +static NTSTATUS CreateQueues(_In_ WDFDEVICE device) +{ + WDF_IO_QUEUE_CONFIG queueConfig; + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( + &queueConfig, WdfIoQueueDispatchParallel); + queueConfig.EvtIoDeviceControl = HIDEvtIoDeviceControl; + + NTSTATUS status = WdfIoQueueCreate( + device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, WDF_NO_HANDLE); + if (!NT_SUCCESS(status)) + return status; + + WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); + + WDF_OBJECT_ATTRIBUTES queueAttributes; + WDF_OBJECT_ATTRIBUTES_INIT(&queueAttributes); + queueAttributes.EvtCleanupCallback = HIDEvtReportQueueCleanup; + return WdfIoQueueCreate( + device, + &queueConfig, + &queueAttributes, + &HIDGetDeviceContext(device)->reportQueue); +} + +NTSTATUS CHIDDevice::Create(_Inout_ PWDFDEVICE_INIT deviceInit) +{ + WdfFdoInitSetFilter(deviceInit); + + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, HIDDeviceContext); + + WDFDEVICE device; + NTSTATUS status = WdfDeviceCreate(&deviceInit, &attributes, &device); + if (!NT_SUCCESS(status)) + return status; + + HIDDeviceContext * context = HIDGetDeviceContext(device); + RtlZeroMemory(context, sizeof(*context)); + InitializeSRWLock(&context->reportLock); + context->active = true; + + context->attributes.Size = + static_cast(sizeof(context->attributes)); + context->attributes.VendorID = LG_INPUT_VENDOR_ID; + context->attributes.ProductID = LG_INPUT_PRODUCT_ID; + context->attributes.VersionNumber = LG_INPUT_VERSION; + + context->descriptor.bLength = + static_cast(sizeof(context->descriptor)); + context->descriptor.bDescriptorType = HID_HID_DESCRIPTOR_TYPE; + context->descriptor.bcdHID = 0x0111; + context->descriptor.bCountry = 0; + context->descriptor.bNumDescriptors = 1; + auto & reportDescriptor = context->descriptor.DescriptorList[0]; + reportDescriptor.bReportType = HID_REPORT_DESCRIPTOR_TYPE; + reportDescriptor.wReportLength = + static_cast(HIDGetReportDescriptorSize()); + + status = CreateQueues(device); + if (!NT_SUCCESS(status)) + return status; + + { + CSRWExclusiveLock lock(&s_deviceLock); + s_device = context; + } + return STATUS_SUCCESS; +} + +NTSTATUS CHIDDevice::SubmitReport( + _In_reads_bytes_(size) const void * report, + _In_ size_t size) +{ + if (!report || !size) + return STATUS_INVALID_PARAMETER; + + const UCHAR reportId = *static_cast(report); + if (HIDGetInputReportSize(reportId) != size) + return STATUS_INVALID_PARAMETER; + + CSRWSharedLock deviceLock(&s_deviceLock); + HIDDeviceContext * context = s_device; + if (!context) + return STATUS_DEVICE_NOT_READY; + + WDFREQUEST request = nullptr; + NTSTATUS status; + { + CSRWExclusiveLock reportLock(&context->reportLock); + if (context->stopping || !context->active) + status = STATUS_DEVICE_NOT_READY; + else + { + status = WdfIoQueueRetrieveNextRequest(context->reportQueue, &request); + if (status == STATUS_NO_MORE_ENTRIES) + { + request = nullptr; + status = QueueReport(context, report, size); + } + } + } + + if (request) + { + status = CopyToRequest(request, report, size); + WdfRequestComplete(request, status); + } + + return status; +} + +VOID HIDEvtIoDeviceControl( + _In_ WDFQUEUE queue, + _In_ WDFREQUEST request, + _In_ size_t outputBufferLength, + _In_ size_t inputBufferLength, + _In_ ULONG ioControlCode) +{ + UNREFERENCED_PARAMETER(outputBufferLength); + UNREFERENCED_PARAMETER(inputBufferLength); + + HIDDeviceContext * context = + HIDGetDeviceContext(WdfIoQueueGetDevice(queue)); + NTSTATUS status; + bool complete = true; + + switch (ioControlCode) + { + case IOCTL_HID_GET_DEVICE_DESCRIPTOR: + status = CopyToRequest( + request, &context->descriptor, context->descriptor.bLength); + break; + + case IOCTL_HID_GET_DEVICE_ATTRIBUTES: + status = CopyToRequest( + request, &context->attributes, sizeof(context->attributes)); + break; + + case IOCTL_HID_GET_REPORT_DESCRIPTOR: + status = CopyToRequest( + request, HIDGetReportDescriptor(), HIDGetReportDescriptorSize()); + break; + + case IOCTL_HID_READ_REPORT: + status = ReadReport(context, request, &complete); + break; + + case IOCTL_HID_WRITE_REPORT: + case IOCTL_UMDF_HID_SET_OUTPUT_REPORT: + status = SetOutputReport(queue, request); + break; + + case IOCTL_HID_ACTIVATE_DEVICE: + status = ActivateDevice(context); + break; + + case IOCTL_HID_DEACTIVATE_DEVICE: + status = DeactivateDevice(context); + break; + + default: + status = STATUS_NOT_SUPPORTED; + break; + } + + if (complete) + WdfRequestComplete(request, status); +} + +VOID HIDEvtReportQueueCleanup(_In_ WDFOBJECT object) +{ + HIDDeviceContext * context = + HIDGetDeviceContext(WdfIoQueueGetDevice((WDFQUEUE)object)); + + CSRWExclusiveLock deviceLock(&s_deviceLock); + if (s_device == context) + s_device = nullptr; + + { + CSRWExclusiveLock reportLock(&context->reportLock); + context->stopping = true; + context->reportHead = 0; + context->reportCount = 0; + } +} diff --git a/idd/LGInput/CHIDDevice.h b/idd/LGInput/CHIDDevice.h new file mode 100644 index 00000000..86385a28 --- /dev/null +++ b/idd/LGInput/CHIDDevice.h @@ -0,0 +1,33 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * 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 + */ + +#pragma once + +#include +#include + +class CHIDDevice +{ +public: + static NTSTATUS Create(_Inout_ PWDFDEVICE_INIT deviceInit); + static NTSTATUS SubmitReport( + _In_reads_bytes_(size) const void * report, + _In_ size_t size); +}; diff --git a/idd/LGInput/Driver.cpp b/idd/LGInput/Driver.cpp new file mode 100644 index 00000000..a8c624ab --- /dev/null +++ b/idd/LGInput/Driver.cpp @@ -0,0 +1,95 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * 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 "Driver.h" +#include "Driver.tmh" + +#include "CDebug.h" +#include "CHIDDevice.h" + +NTSTATUS DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath) +{ + g_debug.Init(L"looking-glass-input"); + DEBUG_INFO("Looking Glass Input Driver"); + +#if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0 + WPP_INIT_TRACING(MYDRIVER_TRACING_ID); +#else + WPP_INIT_TRACING(DriverObject, RegistryPath); +#endif + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); + + WDF_DRIVER_CONFIG config; + WDF_DRIVER_CONFIG_INIT(&config, LGInputEvtDeviceAdd); + + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.EvtCleanupCallback = LGInputEvtDriverContextCleanup; + + const NTSTATUS status = WdfDriverCreate( + DriverObject, RegistryPath, &attributes, &config, WDF_NO_HANDLE); + if (!NT_SUCCESS(status)) + { + TraceEvents( + TRACE_LEVEL_ERROR, + TRACE_DRIVER, + "WdfDriverCreate failed %!STATUS!", + status); +#if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0 + WPP_CLEANUP(); +#else + WPP_CLEANUP(DriverObject); +#endif + return status; + } + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit"); + return status; +} + +NTSTATUS LGInputEvtDeviceAdd( + _In_ WDFDRIVER Driver, + _Inout_ PWDFDEVICE_INIT DeviceInit) +{ + UNREFERENCED_PARAMETER(Driver); + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); + const NTSTATUS status = CHIDDevice::Create(DeviceInit); + if (!NT_SUCCESS(status)) + DEBUG_ERROR_HR(status, "Failed to create the HID input device"); + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit"); + return status; +} + +VOID LGInputEvtDriverContextCleanup(_In_ WDFOBJECT DriverObject) +{ + UNREFERENCED_PARAMETER(DriverObject); + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); + +#if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0 + WPP_CLEANUP(); +#else + WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)DriverObject)); +#endif +} diff --git a/idd/LGInput/Driver.h b/idd/LGInput/Driver.h new file mode 100644 index 00000000..5099b136 --- /dev/null +++ b/idd/LGInput/Driver.h @@ -0,0 +1,33 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * 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 + */ + +#pragma once + +#include +#include + +#include "Trace.h" + +EXTERN_C_START +DRIVER_INITIALIZE DriverEntry; +EXTERN_C_END + +EVT_WDF_DRIVER_DEVICE_ADD LGInputEvtDeviceAdd; +EVT_WDF_OBJECT_CONTEXT_CLEANUP LGInputEvtDriverContextCleanup; diff --git a/idd/LGInput/HIDReports.cpp b/idd/LGInput/HIDReports.cpp new file mode 100644 index 00000000..77507061 --- /dev/null +++ b/idd/LGInput/HIDReports.cpp @@ -0,0 +1,151 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * 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 "HIDReports.h" + +static const uint8_t REPORT_DESCRIPTOR[] = +{ + // Absolute tablet, report ID 1. + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x85, HID_REPORT_ID_TABLET, + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (Button 1) + 0x29, 0x05, // Usage Maximum (Button 5) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x05, // Report Count (5) + 0x81, 0x02, // Input (Data, Variable, Absolute) + 0x75, 0x03, // Report Size (3) + 0x95, 0x01, // Report Count (1) + 0x81, 0x03, // Input (Constant) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x7F, // Logical Maximum (32767) + 0x75, 0x10, // Report Size (16) + 0x95, 0x02, // Report Count (2) + 0x81, 0x02, // Input (Data, Variable, Absolute) + 0xC0, // End Collection + 0xC0, // End Collection + + // Relative mouse, report ID 2. + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x85, HID_REPORT_ID_MOUSE, + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (Button 1) + 0x29, 0x05, // Usage Maximum (Button 5) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x05, // Report Count (5) + 0x81, 0x02, // Input (Data, Variable, Absolute) + 0x75, 0x03, // Report Size (3) + 0x95, 0x01, // Report Count (1) + 0x81, 0x03, // Input (Constant) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x16, 0x00, 0x80, // Logical Minimum (-32768) + 0x26, 0xFF, 0x7F, // Logical Maximum (32767) + 0x75, 0x10, // Report Size (16) + 0x95, 0x02, // Report Count (2) + 0x81, 0x06, // Input (Data, Variable, Relative) + 0x09, 0x38, // Usage (Wheel) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x81, 0x06, // Input (Data, Variable, Relative) + 0xC0, // End Collection + 0xC0, // End Collection + + // Keyboard, report ID 3. + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x06, // Usage (Keyboard) + 0xA1, 0x01, // Collection (Application) + 0x85, HID_REPORT_ID_KEYBOARD, + 0x05, 0x07, // Usage Page (Keyboard) + 0x19, 0xE0, // Usage Minimum (Left Control) + 0x29, 0xE7, // Usage Maximum (Right GUI) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x81, 0x02, // Input (Data, Variable, Absolute) + 0x95, 0x01, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x03, // Input (Constant) + 0x05, 0x08, // Usage Page (LEDs) + 0x19, 0x01, // Usage Minimum (Num Lock) + 0x29, 0x05, // Usage Maximum (Kana) + 0x95, 0x05, // Report Count (5) + 0x75, 0x01, // Report Size (1) + 0x91, 0x02, // Output (Data, Variable, Absolute) + 0x95, 0x01, // Report Count (1) + 0x75, 0x03, // Report Size (3) + 0x91, 0x03, // Output (Constant) + 0x05, 0x07, // Usage Page (Keyboard) + 0x19, 0x00, // Usage Minimum (0) + 0x2A, 0xE7, 0x00, // Usage Maximum (231) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xE7, 0x00, // Logical Maximum (231) + 0x75, 0x08, // Report Size (8) + 0x95, 0x06, // Report Count (6) + 0x81, 0x00, // Input (Data, Array, Absolute) + 0xC0, // End Collection +}; + +const uint8_t * HIDGetReportDescriptor() +{ + return REPORT_DESCRIPTOR; +} + +size_t HIDGetReportDescriptorSize() +{ + return sizeof(REPORT_DESCRIPTOR); +} + +size_t HIDGetInputReportSize(uint8_t reportId) +{ + switch (reportId) + { + case HID_REPORT_ID_TABLET: + return sizeof(HIDTabletReport); + + case HID_REPORT_ID_MOUSE: + return sizeof(HIDMouseReport); + + case HID_REPORT_ID_KEYBOARD: + return sizeof(HIDKeyboardReport); + + default: + return 0; + } +} diff --git a/idd/LGInput/HIDReports.h b/idd/LGInput/HIDReports.h new file mode 100644 index 00000000..0282ade2 --- /dev/null +++ b/idd/LGInput/HIDReports.h @@ -0,0 +1,75 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * 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 + */ + +#pragma once + +#include +#include + +enum HIDReportId : uint8_t +{ + HID_REPORT_ID_TABLET = 1, + HID_REPORT_ID_MOUSE = 2, + HID_REPORT_ID_KEYBOARD = 3, +}; + +#pragma pack(push, 1) + +struct HIDTabletReport +{ + uint8_t reportId; + uint8_t buttons; + uint16_t x; + uint16_t y; +}; + +struct HIDMouseReport +{ + uint8_t reportId; + uint8_t buttons; + int16_t x; + int16_t y; + int8_t wheel; +}; + +struct HIDKeyboardReport +{ + uint8_t reportId; + uint8_t modifiers; + uint8_t reserved; + uint8_t keys[6]; +}; + +struct HIDKeyboardLedsReport +{ + uint8_t reportId; + uint8_t leds; +}; + +#pragma pack(pop) + +static_assert(sizeof(HIDTabletReport) == 6); +static_assert(sizeof(HIDMouseReport) == 7); +static_assert(sizeof(HIDKeyboardReport) == 9); +static_assert(sizeof(HIDKeyboardLedsReport) == 2); + +const uint8_t * HIDGetReportDescriptor(); +size_t HIDGetReportDescriptorSize(); +size_t HIDGetInputReportSize(uint8_t reportId); diff --git a/idd/LGInput/LGInput.inf b/idd/LGInput/LGInput.inf new file mode 100644 index 00000000..14c733b4 --- /dev/null +++ b/idd/LGInput/LGInput.inf @@ -0,0 +1,75 @@ +; +; LGInput.inf +; + +[Version] +Signature="$Windows NT$" +Class=HIDClass +ClassGuid={745A17A0-74D3-11D0-B6FE-00A0C90F57DA} +Provider=%ManufacturerName% +CatalogFile=LGInput.cat +DriverVer=0.1 +PnpLockdown=1 + +[Manufacturer] +%ManufacturerName%=Standard,NT$ARCH$.10.0 + +[Standard.NT$ARCH$.10.0] +%DeviceName%=LGInput_Install,Root\LGInput + +[LGInput_Install.NT] +CopyFiles=UMDriverCopy + +[LGInput_Install.NT.hw] +AddReg=LGInput_HardwareSettings + +[LGInput_HardwareSettings] +HKR,,"LowerFilters",0x00010008,"WUDFRd" + +[LGInput_Install.NT.Services] +AddService=WUDFRd,0x000001f8,WUDFRD_ServiceInstall +AddService=mshidumdf,0x000001fa,mshidumdf_ServiceInstall + +[mshidumdf_ServiceInstall] +ServiceType=1 +StartType=3 +ErrorControl=1 +ServiceBinary=%12%\mshidumdf.sys + +[WUDFRD_ServiceInstall] +DisplayName=%WudfRdDisplayName% +ServiceType=1 +StartType=3 +ErrorControl=1 +ServiceBinary=%12%\WUDFRd.sys + +[LGInput_Install.NT.Wdf] +UmdfService=LGInput,LGInput_ServiceInstall +UmdfServiceOrder=LGInput +UmdfKernelModeClientPolicy=AllowKernelModeClients +UmdfFileObjectPolicy=AllowNullAndUnknownFileObjects +UmdfMethodNeitherAction=Copy +UmdfFsContextUsePolicy=CanUseFsContext2 +UmdfHostProcessSharing=ProcessSharingDisabled + +[LGInput_ServiceInstall] +UmdfLibraryVersion=$UMDFVERSION$ +ServiceBinary=%12%\UMDF\LGInput.dll + +[DestinationDirs] +UMDriverCopy=12,UMDF + +[UMDriverCopy] +LGInput.dll + +[SourceDisksNames] +1=%DiskName% + +[SourceDisksFiles] +LGInput.dll=1 + +[Strings] +ManufacturerName="Looking Glass" +DiskName="LGInput Installation Disk" +DeviceName="Looking Glass" +WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" diff --git a/idd/LGInput/LGInput.vcxproj b/idd/LGInput/LGInput.vcxproj new file mode 100644 index 00000000..1923159e --- /dev/null +++ b/idd/LGInput/LGInput.vcxproj @@ -0,0 +1,104 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + Common\CDebug.cpp + + + + + + + + Common\CDebug.h + + + Common\CSRWLock.h + + + + + + + + + + + {2477B25B-CB62-4AD9-A260-CE5F00D77EEB} + LGInput + 10.0.26100.0 + 2 + Debug + Win32 + + + + Windows10 + Universal + UMDF + WindowsUserModeDriver10.0 + DynamicLibrary + 25 + 25 + <_NT_TARGET_VERSION>0xA000005 + Spectre + + + true + + + false + + + + + + + + + LGInput + DbgengRemoteDebugger + true + + + + true + true + Trace.h + /EHsc /D_ATL_NO_WIN_SUPPORT %(AdditionalOptions) + $(ProjectDir)..\LGCommon;$(DDK_INC_PATH);%(AdditionalIncludeDirectories) + + + %(AdditionalDependencies);OneCoreUAP.lib + + + SHA1 + + + + + + + + diff --git a/idd/LGInput/LGInput.vcxproj.filters b/idd/LGInput/LGInput.vcxproj.filters new file mode 100644 index 00000000..d47340fd --- /dev/null +++ b/idd/LGInput/LGInput.vcxproj.filters @@ -0,0 +1,54 @@ + + + + + {B48E885A-BB8C-4DD5-8145-587B360AAB3B} + + + {D9688549-A0BE-46E6-8FAB-AE454D90E0FA} + + + {938E49D6-F954-4EBE-80AB-E0F67E677F27} + + + + + Driver + + + + + Common + + + Common + + + Driver + + + Driver + + + HID + + + Driver + + + + + Common + + + Driver + + + Driver + + + HID + + + diff --git a/idd/LGInput/Trace.h b/idd/LGInput/Trace.h new file mode 100644 index 00000000..f4354ceb --- /dev/null +++ b/idd/LGInput/Trace.h @@ -0,0 +1,50 @@ +/** + * Looking Glass + * Copyright © 2017-2026 The Looking Glass Authors + * https://looking-glass.io + * + * 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 + */ + +#pragma once + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + LGInputTraceGuid, (1d279434,7f85,42cd,b4b9,9a3d6f5cb774), \ + \ + WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ + WPP_DEFINE_BIT(TRACE_DRIVER)) + +#define WPP_FLAG_LEVEL_LOGGER(flag, level) \ + WPP_LEVEL_LOGGER(flag) + +#define WPP_FLAG_LEVEL_ENABLED(flag, level) \ + (WPP_LEVEL_ENABLED(flag) && \ + WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) + +#define WPP_LEVEL_FLAGS_LOGGER(lvl, flags) \ + WPP_LEVEL_LOGGER(flags) + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ + (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) + +// begin_wpp config +// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); +// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...); +// end_wpp + +#if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0 + #define MYDRIVER_TRACING_ID L"Microsoft\\UMDF2.0\\LGInput V1.0" +#endif diff --git a/idd/installer.nsi b/idd/installer.nsi index ddb81f1a..8c6bd5dc 100644 --- a/idd/installer.nsi +++ b/idd/installer.nsi @@ -59,7 +59,7 @@ InstallDir "$PROGRAMFILES64\Looking Glass (IDD)" ;Install and uninstall pages !insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_LICENSE "LICENSE.txt" +!insertmacro MUI_PAGE_LICENSE "LICENSE" !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_INSTFILES @@ -172,13 +172,16 @@ Section "!Indirect Display Driver (IDD)" Section1 DetailPrint "Extracting IDD" SetOutPath $INSTDIR File lgidd.cat + File /oname=LGInput.cat "LGInput\LGInput.cat" File LGIdd.dll + File /oname=LGInput.dll "LGInput\LGInput.dll" File LGIdd.inf + File /oname=LGInput.inf "LGInput\LGInput.inf" File LGIddHelper.exe File LGIddInstall.exe DetailPrint "Extracting support files" - File LICENSE.txt + File /oname=LICENSE.txt LICENSE WriteUninstaller $INSTDIR\uninstaller.exe ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 @@ -232,8 +235,11 @@ Section "Uninstall" Section6 Delete "$INSTDIR\ivshmem.sys" Delete "$INSTDIR\ivshmem.pdb" Delete "$INSTDIR\lgidd.cat" + Delete "$INSTDIR\LGInput.cat" Delete "$INSTDIR\LGIdd.dll" + Delete "$INSTDIR\LGInput.dll" Delete "$INSTDIR\LGIdd.inf" + Delete "$INSTDIR\LGInput.inf" Delete "$INSTDIR\LGIddHelper.exe" Delete "$INSTDIR\LGIddInstall.exe" Delete "$INSTDIR\LICENSE.txt"