mirror of
https://github.com/Alia5/GlosSI.git
synced 2024-11-01 09:20:17 +00:00
489 lines
19 KiB
C++
489 lines
19 KiB
C++
|
/*
|
||
|
Copyright 2021 Peter Repukat - FlatspotSoftware
|
||
|
|
||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
you may not use this file except in compliance with the License.
|
||
|
You may obtain a copy of the License at
|
||
|
|
||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
Unless required by applicable law or agreed to in writing, software
|
||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
See the License for the specific language governing permissions and
|
||
|
limitations under the License.
|
||
|
*/
|
||
|
|
||
|
// parts of code adapted from https://github.com/ViGEm/HidHide/blob/HEAD/HidHideCLI/src/HID.cpp
|
||
|
// // (c) Eric Korff de Gidts
|
||
|
// SPDX-License-Identifier: MIT
|
||
|
|
||
|
#include "HidHide.h"
|
||
|
|
||
|
#include <iostream>
|
||
|
#include <numeric>
|
||
|
#include <spdlog/spdlog.h>
|
||
|
#include <vector>
|
||
|
|
||
|
// Device configuration related
|
||
|
#include <cfgmgr32.h>
|
||
|
|
||
|
#include <initguid.h>
|
||
|
//
|
||
|
#include <devguid.h>
|
||
|
#include <devpkey.h>
|
||
|
#include <regex>
|
||
|
|
||
|
// {D61CA365-5AF4-4486-998B-9DB4734C6CA3}add the XUSB class GUID as it is missing in the public interfaces
|
||
|
DEFINE_GUID(GUID_DEVCLASS_XUSBCLASS, 0xD61CA365, 0x5AF4, 0x4486, 0x99, 0x8B, 0x9D, 0xB4, 0x73, 0x4C, 0x6C, 0xA3);
|
||
|
// {EC87F1E3-C13B-4100-B5F7-8B84D54260CB} add the XUSB interface class GUID as it is missing in the public interfaces
|
||
|
DEFINE_GUID(GUID_DEVINTERFACE_XUSB, 0xEC87F1E3, 0xC13B, 0x4100, 0xB5, 0xF7, 0x8B, 0x84, 0xD5, 0x42, 0x60, 0xCB);
|
||
|
// {00000000-0000-0000-FFFF-FFFFFFFFFFFF} the system container id
|
||
|
DEFINE_GUID(GUID_CONTAINER_ID_SYSTEM, 0x00000000, 0x0000, 0x0000, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
|
||
|
|
||
|
HidHide::HidHide() = default;
|
||
|
|
||
|
void HidHide::openCtrlDevice()
|
||
|
{
|
||
|
hidhide_handle = CreateFile(
|
||
|
L"\\\\.\\HidHide",
|
||
|
GENERIC_READ,
|
||
|
(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL);
|
||
|
}
|
||
|
|
||
|
void HidHide::closeCtrlDevice()
|
||
|
{
|
||
|
if (hidhide_handle == nullptr) {
|
||
|
return;
|
||
|
}
|
||
|
CloseHandle(hidhide_handle);
|
||
|
hidhide_handle = nullptr;
|
||
|
}
|
||
|
|
||
|
void HidHide::hideDevices(const std::filesystem::path& steam_path)
|
||
|
{
|
||
|
openCtrlDevice();
|
||
|
auto active = getActive();
|
||
|
if (active) {
|
||
|
// disable hidhide so we can see devices ourselves
|
||
|
setActive(false);
|
||
|
}
|
||
|
auto whitelist = getAppWhiteList();
|
||
|
// has anyone more than 4 keys to open overlay?!
|
||
|
std::wsmatch m;
|
||
|
const auto steam_path_string = steam_path.wstring();
|
||
|
if (!std::regex_search(steam_path_string, m, std::wregex(L"(.:)(\\/|\\\\)")) || m.size() < 3) {
|
||
|
spdlog::warn("Couldn't detect steam drive letter; Device hiding may not function");
|
||
|
return;
|
||
|
}
|
||
|
const auto dos_device = DosDeviceForVolume(m[1]);
|
||
|
if (dos_device.empty()) {
|
||
|
spdlog::warn("Couldn't detect steam drive letter DOS Path; Device hiding may not function");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (const auto& exe : whitelist_executeables_) {
|
||
|
auto path = std::regex_replace(steam_path_string, std::wregex(L"(.:)(\\/|\\\\)"), dos_device + L"\\");
|
||
|
path = std::regex_replace(path, std::wregex(L"\\/"), L"\\") + L"\\" + std::wstring{exe};
|
||
|
if (std::ranges::none_of(whitelist, [&path](auto ep) { // make copy!
|
||
|
auto p = path; // non-const(!) copy of path
|
||
|
std::ranges::transform(path, p.begin(), tolower);
|
||
|
std::ranges::transform(ep, ep.begin(), tolower);
|
||
|
return p == ep;
|
||
|
})) {
|
||
|
whitelist.push_back(path);
|
||
|
}
|
||
|
}
|
||
|
setAppWhiteList(whitelist);
|
||
|
|
||
|
const auto device_list = GetHidDeviceList();
|
||
|
auto blacklist = getBlackListDevices();
|
||
|
|
||
|
for (const auto& dev : device_list) {
|
||
|
if (std::ranges::none_of(blacklist, [&dev](const auto& blackdev) {
|
||
|
return blackdev == dev.device_instance_path || blackdev == dev.base_container_device_instance_path;
|
||
|
})) {
|
||
|
if (!dev.device_instance_path.empty()) {
|
||
|
blacklist.push_back(dev.device_instance_path);
|
||
|
}
|
||
|
if (!dev.device_instance_path.empty()) {
|
||
|
blacklist.push_back(dev.base_container_device_instance_path);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
setBlacklistDevices(blacklist);
|
||
|
setActive(true);
|
||
|
closeCtrlDevice();
|
||
|
spdlog::info("Hid Gaming Devices"); // TODO: add list of blacklisted devices
|
||
|
}
|
||
|
|
||
|
void HidHide::disableHidHide()
|
||
|
{
|
||
|
openCtrlDevice();
|
||
|
setActive(false);
|
||
|
closeCtrlDevice();
|
||
|
spdlog::info("Un-hid Gaming Devices"); // TODO: add list of blacklisted devices
|
||
|
}
|
||
|
|
||
|
std::wstring HidHide::DosDeviceForVolume(const std::wstring& volume)
|
||
|
{
|
||
|
std::vector<WCHAR> buffer(UNICODE_STRING_MAX_CHARS);
|
||
|
QueryDosDeviceW(volume.c_str(), buffer.data(), static_cast<DWORD>(buffer.size()));
|
||
|
return {buffer.data()};
|
||
|
}
|
||
|
|
||
|
std::vector<std::wstring> HidHide::getAppWhiteList() const
|
||
|
{
|
||
|
DWORD bytes_needed = getRequiredOutputBufferSize(IOCTL_TYPE::GET_WHITELIST);
|
||
|
if (bytes_needed == 0) {
|
||
|
return std::vector<std::wstring>{};
|
||
|
}
|
||
|
std::vector<WCHAR> buffer(bytes_needed);
|
||
|
if (!DeviceIoControl(
|
||
|
hidhide_handle, static_cast<DWORD>(IOCTL_TYPE::GET_WHITELIST), nullptr, 0, buffer.data(), static_cast<DWORD>(buffer.size() * sizeof(WCHAR)), &bytes_needed, nullptr)) {
|
||
|
spdlog::error("Couldn't retrieve HidHide Whitelist");
|
||
|
return std::vector<std::wstring>{};
|
||
|
}
|
||
|
return BufferToStringVec(buffer);
|
||
|
}
|
||
|
|
||
|
std::vector<std::wstring> HidHide::getBlackListDevices() const
|
||
|
{
|
||
|
DWORD bytes_needed = getRequiredOutputBufferSize(IOCTL_TYPE::GET_BLACKLIST);
|
||
|
if (bytes_needed == 0) {
|
||
|
return std::vector<std::wstring>{};
|
||
|
}
|
||
|
std::vector<WCHAR> buffer(bytes_needed);
|
||
|
if (!DeviceIoControl(
|
||
|
hidhide_handle, static_cast<DWORD>(IOCTL_TYPE::GET_BLACKLIST), nullptr, 0, buffer.data(), static_cast<DWORD>(buffer.size() * sizeof(WCHAR)), &bytes_needed, nullptr)) {
|
||
|
spdlog::error("Couldn't retrieve HidHide Blacklist");
|
||
|
return std::vector<std::wstring>{};
|
||
|
}
|
||
|
return BufferToStringVec(buffer);
|
||
|
}
|
||
|
|
||
|
bool HidHide::getActive() const
|
||
|
{
|
||
|
DWORD bytes_needed;
|
||
|
BOOLEAN res;
|
||
|
if (!DeviceIoControl(
|
||
|
hidhide_handle, static_cast<DWORD>(IOCTL_TYPE::GET_ACTIVE), nullptr, 0, &res, sizeof(BOOLEAN), &bytes_needed, nullptr)) {
|
||
|
spdlog::error("Couldn't retrieve HidHide State");
|
||
|
return false;
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
void HidHide::setAppWhiteList(const std::vector<std::wstring>& whitelist) const
|
||
|
{
|
||
|
DWORD bytes_needed;
|
||
|
auto buffer = StringListToMultiString(whitelist);
|
||
|
if (!DeviceIoControl(
|
||
|
hidhide_handle, static_cast<DWORD>(IOCTL_TYPE::SET_WHITELIST), buffer.data(), static_cast<DWORD>(buffer.size() * sizeof(WCHAR)), nullptr, 0, &bytes_needed, nullptr)) {
|
||
|
spdlog::error("Couldn't set HidHide WhiteList");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HidHide::setBlacklistDevices(const std::vector<std::wstring>& blacklist) const
|
||
|
{
|
||
|
DWORD bytes_needed;
|
||
|
auto buffer = StringListToMultiString(blacklist);
|
||
|
if (!DeviceIoControl(
|
||
|
hidhide_handle, static_cast<DWORD>(IOCTL_TYPE::SET_BLACKLIST), buffer.data(), static_cast<DWORD>(buffer.size() * sizeof(WCHAR)), nullptr, 0, &bytes_needed, nullptr)) {
|
||
|
spdlog::error("Couldn't set HidHide BlackList");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HidHide::setActive(bool active) const
|
||
|
{
|
||
|
DWORD bytes_needed;
|
||
|
if (!DeviceIoControl(
|
||
|
hidhide_handle, static_cast<DWORD>(IOCTL_TYPE::SET_ACTIVE), &active, sizeof(BOOLEAN), nullptr, 0, &bytes_needed, nullptr)) {
|
||
|
spdlog::error("Couldn't set HidHide State");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DWORD HidHide::getRequiredOutputBufferSize(IOCTL_TYPE type) const
|
||
|
{
|
||
|
DWORD bytes_needed;
|
||
|
if (!DeviceIoControl(hidhide_handle, static_cast<DWORD>(type), nullptr, 0, nullptr, 0, &bytes_needed, nullptr)) {
|
||
|
spdlog::error("Couldn't determine required HidHide output buffer size; type: {}", type);
|
||
|
return 0;
|
||
|
}
|
||
|
return bytes_needed;
|
||
|
}
|
||
|
|
||
|
std::vector<std::wstring> HidHide::BufferToStringVec(const auto& buffer)
|
||
|
{
|
||
|
std::vector<std::wstring> res;
|
||
|
if (buffer[0] != L'\0') {
|
||
|
res.emplace_back();
|
||
|
for (const auto& ch : buffer) {
|
||
|
if (ch == L'\0') {
|
||
|
if ((res.end() - 1)->length() == 0) {
|
||
|
res.erase(res.end() - 1);
|
||
|
break;
|
||
|
}
|
||
|
res.emplace_back();
|
||
|
continue;
|
||
|
}
|
||
|
(res.end() - 1)->push_back(ch);
|
||
|
}
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
std::vector<WCHAR> HidHide::StringListToMultiString(const std::vector<std::wstring>& stringlist)
|
||
|
{
|
||
|
auto res = std::accumulate(stringlist.begin(), stringlist.end(), std::vector<WCHAR>{}, [](auto acc, const auto& curr) {
|
||
|
acc.insert(acc.end(), curr.begin(), curr.end());
|
||
|
acc.push_back(L'\0');
|
||
|
return acc;
|
||
|
});
|
||
|
res.push_back(L'\0');
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
std::vector<HidHide::SmallHidInfo> HidHide::GetHidDeviceList()
|
||
|
{
|
||
|
std::wstring hid_class_guid_string;
|
||
|
hid_class_guid_string.resize(39);
|
||
|
if (!StringFromGUID2(GUID_DEVCLASS_HIDCLASS, hid_class_guid_string.data(), static_cast<int>(hid_class_guid_string.size()))) {
|
||
|
spdlog::error("couldn't convert GUID to string");
|
||
|
}
|
||
|
|
||
|
ULONG needed{};
|
||
|
if (const auto result = CM_Get_Device_ID_List_SizeW(&needed, hid_class_guid_string.c_str(), CM_GETIDLIST_FILTER_CLASS);
|
||
|
(CR_SUCCESS != result)) {
|
||
|
spdlog::error("Couldn't get device id list size; code: {}", result);
|
||
|
}
|
||
|
std::vector<WCHAR> buffer(needed);
|
||
|
if (const auto result = CM_Get_Device_ID_ListW(hid_class_guid_string.c_str(), buffer.data(), needed, CM_GETIDLIST_FILTER_CLASS);
|
||
|
(CR_SUCCESS != result)) {
|
||
|
spdlog::error("Couldn't get device id list; code: {}", result);
|
||
|
}
|
||
|
|
||
|
auto device_instance_paths = BufferToStringVec(buffer);
|
||
|
device_instance_paths.erase(
|
||
|
std::ranges::remove_if(
|
||
|
device_instance_paths,
|
||
|
[](const auto& dev) { return !DevicePresent(dev); })
|
||
|
.begin(),
|
||
|
device_instance_paths.end());
|
||
|
|
||
|
GUID hid_device_interface_guid{};
|
||
|
HidD_GetHidGuid(&hid_device_interface_guid);
|
||
|
std::vector<SmallHidInfo> res;
|
||
|
for (auto& instance_path : device_instance_paths) {
|
||
|
auto symlink = SymbolicLink(hid_device_interface_guid, instance_path);
|
||
|
if (!symlink.empty()) {
|
||
|
res.push_back(GetDeviceInfo(instance_path, symlink));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
res.erase(
|
||
|
std::ranges::remove_if(
|
||
|
res,
|
||
|
[](const auto& dev) { return !dev.gaming_device; })
|
||
|
.begin(),
|
||
|
res.end());
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
HidHide::SmallHidInfo HidHide::GetDeviceInfo(const DeviceInstancePath& instance_path, const std::filesystem::path& symlink)
|
||
|
{
|
||
|
SmallHidInfo res;
|
||
|
res.device_instance_path = instance_path;
|
||
|
|
||
|
// Open a handle to communicate with the HID device
|
||
|
const CloseHandlePtr device_object(
|
||
|
CreateFileW(
|
||
|
symlink.c_str(),
|
||
|
GENERIC_READ,
|
||
|
(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
|
||
|
nullptr,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
nullptr),
|
||
|
&CloseHandle);
|
||
|
if (INVALID_HANDLE_VALUE == device_object.get()) {
|
||
|
const auto err = GetLastError();
|
||
|
switch (err) {
|
||
|
case ERROR_ACCESS_DENIED:
|
||
|
// The device is opened exclusively and in use hence we can't interact with it
|
||
|
__fallthrough;
|
||
|
case ERROR_SHARING_VIOLATION:
|
||
|
// The device is (most-likely) cloaked by Hid Hide itself while its client application isn't on the white-list
|
||
|
__fallthrough;
|
||
|
case ERROR_FILE_NOT_FOUND:
|
||
|
// The device is currently not present hence we can't query its details
|
||
|
return res;
|
||
|
default:
|
||
|
spdlog::error(L"Couldn't open device {}; code: {}", instance_path, err);
|
||
|
return res;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PHIDP_PREPARSED_DATA pre_parsed_data;
|
||
|
if (!HidD_GetPreparsedData(device_object.get(), &pre_parsed_data)) {
|
||
|
spdlog::error(L"Couldn't get PreParsed data; Device: {}", instance_path);
|
||
|
return {};
|
||
|
}
|
||
|
const HidD_FreePreparsedDataPtr free_preparsed_data_ptr(pre_parsed_data, &HidD_FreePreparsedData);
|
||
|
|
||
|
HIDP_CAPS capabilities;
|
||
|
if (HIDP_STATUS_SUCCESS != HidP_GetCaps(pre_parsed_data, &capabilities)) {
|
||
|
spdlog::error(L"Could get Hid capabilities; Device: {}", instance_path);
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
HIDD_ATTRIBUTES attributes;
|
||
|
if (!HidD_GetAttributes(device_object.get(), &attributes)) {
|
||
|
spdlog::error(L"Could get Hid attributes; Device: {}", instance_path);
|
||
|
return {};
|
||
|
}
|
||
|
std::wstring buffer;
|
||
|
buffer.resize(127 * sizeof WCHAR);
|
||
|
res.name = (HidD_GetProductString(device_object.get(), buffer.data(), static_cast<ULONG>(sizeof(WCHAR) * buffer.size()))
|
||
|
? buffer
|
||
|
: L"");
|
||
|
res.base_container_device_instance_path = BaseContainerDeviceInstancePath(instance_path);
|
||
|
res.gaming_device = IsGamingDevice(attributes, capabilities);
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
bool HidHide::DevicePresent(const DeviceInstancePath& dev)
|
||
|
{
|
||
|
DEVINST dev_inst{};
|
||
|
if (
|
||
|
const auto result = CM_Locate_DevNodeW(&dev_inst, const_cast<DEVINSTID_W>(dev.c_str()), CM_LOCATE_DEVNODE_NORMAL);
|
||
|
(CR_NO_SUCH_DEVNODE == result) || (CR_SUCCESS == result)) {
|
||
|
return (CR_SUCCESS == result);
|
||
|
}
|
||
|
spdlog::error(L"Couldn't determine if device \"{}\" is present", dev);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
std::filesystem::path HidHide::SymbolicLink(GUID const& interface_guid, DeviceInstancePath const& instance_path)
|
||
|
{
|
||
|
// Ask the device for the device interface
|
||
|
// Note that this call will succeed, whether or not the interface is present, but the iterator will have no entries, when the device interface isn't supported
|
||
|
const SetupDiDestroyDeviceInfoListPtr handle(SetupDiGetClassDevsW(&interface_guid, instance_path.c_str(), nullptr, DIGCF_DEVICEINTERFACE), &SetupDiDestroyDeviceInfoList);
|
||
|
if (INVALID_HANDLE_VALUE == handle.get()) {
|
||
|
spdlog::error(L"Device Handle invalid; device: {}", instance_path);
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
// Is the interface supported ?
|
||
|
SP_DEVICE_INTERFACE_DATA device_interface_data;
|
||
|
device_interface_data.cbSize = sizeof(device_interface_data);
|
||
|
if (!SetupDiEnumDeviceInterfaces(handle.get(), nullptr, &interface_guid, 0, &device_interface_data)) {
|
||
|
if (ERROR_NO_MORE_ITEMS != GetLastError()) {
|
||
|
spdlog::error(L"Couldn't get Device interfaces; device: {}", instance_path);
|
||
|
return {};
|
||
|
}
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
// Determine the buffer length needed
|
||
|
DWORD needed{};
|
||
|
if (!SetupDiGetDeviceInterfaceDetailW(handle.get(), &device_interface_data, nullptr, 0, &needed, nullptr) && ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
|
||
|
spdlog::error(L"Couldn't get Device interface details; device: {}", instance_path);
|
||
|
return {};
|
||
|
}
|
||
|
std::vector<BYTE> buffer(needed);
|
||
|
|
||
|
// Acquire the detailed data containing the symbolic link (aka. device path)
|
||
|
auto& [cbSize, DevicePath]{*reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA_W>(buffer.data())};
|
||
|
cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
|
||
|
if (!SetupDiGetDeviceInterfaceDetailW(handle.get(), &device_interface_data, reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA_W>(buffer.data()), static_cast<DWORD>(buffer.size()), nullptr, nullptr)) {
|
||
|
spdlog::error(L"Couldn't get Device interface details; device: {}", instance_path);
|
||
|
return {};
|
||
|
}
|
||
|
return {std::wstring(DevicePath)};
|
||
|
}
|
||
|
|
||
|
HidHide::DeviceInstancePath HidHide::BaseContainerDeviceInstancePath(DeviceInstancePath const& device_instance_path)
|
||
|
{
|
||
|
const GUID base_container_id(BaseContainerId(device_instance_path));
|
||
|
if ((GUID_NULL == base_container_id) || (GUID_CONTAINER_ID_SYSTEM == base_container_id))
|
||
|
return (std::wstring{});
|
||
|
for (auto it{device_instance_path};;) {
|
||
|
if (const auto device_instance_path_parent = DeviceInstancePathParent(it); (base_container_id == BaseContainerId(device_instance_path_parent)))
|
||
|
it = device_instance_path_parent;
|
||
|
else
|
||
|
return (it);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GUID HidHide::BaseContainerId(DeviceInstancePath const& device_instance_path)
|
||
|
{
|
||
|
// Bail out when the device instance path is empty
|
||
|
if (device_instance_path.empty())
|
||
|
return (GUID_NULL);
|
||
|
|
||
|
DEVINST devInst{};
|
||
|
DEVPROPTYPE devPropType{};
|
||
|
GUID buffer{};
|
||
|
ULONG needed{sizeof(buffer)};
|
||
|
if (const auto result = CM_Locate_DevNodeW(&devInst, const_cast<DEVINSTID_W>(device_instance_path.c_str()), CM_LOCATE_DEVNODE_PHANTOM); (CR_SUCCESS != result)) {
|
||
|
spdlog::error(L"Couldn't locate device DevNode; Device {}; Code: {}", device_instance_path, result);
|
||
|
return {};
|
||
|
}
|
||
|
if (const auto result = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_Device_ContainerId, &devPropType, reinterpret_cast<PBYTE>(&buffer), &needed, 0); (CR_SUCCESS != result)) {
|
||
|
// Bail out when the container id property isn't present
|
||
|
if (CR_NO_SUCH_VALUE == result) {
|
||
|
return (GUID_NULL);
|
||
|
}
|
||
|
spdlog::error(L"Couldn't locate device DevNode Property; Device {}; Code: {}", device_instance_path, result);
|
||
|
return {};
|
||
|
}
|
||
|
if (DEVPROP_TYPE_GUID != devPropType) {
|
||
|
spdlog::error(L"Device Prop is not GUID; Device {}", device_instance_path);
|
||
|
return {};
|
||
|
}
|
||
|
return (buffer);
|
||
|
}
|
||
|
|
||
|
HidHide::DeviceInstancePath HidHide::DeviceInstancePathParent(DeviceInstancePath const& device_instance_path)
|
||
|
{
|
||
|
DEVINST dev_inst{};
|
||
|
DEVPROPTYPE dev_prop_type{};
|
||
|
DEVINST dev_inst_parent{};
|
||
|
std::wstring res;
|
||
|
res.resize(UNICODE_STRING_MAX_CHARS);
|
||
|
ULONG needed{static_cast<ULONG>(res.size())};
|
||
|
if (const auto result = CM_Locate_DevNodeW(&dev_inst, const_cast<DEVINSTID_W>(device_instance_path.c_str()), CM_LOCATE_DEVNODE_PHANTOM); (CR_SUCCESS != result)) {
|
||
|
spdlog::error(L"Couldn't locate device DevNode; Device {}; Code: {}", device_instance_path, result);
|
||
|
return {};
|
||
|
}
|
||
|
if (const auto result = CM_Get_Parent(&dev_inst_parent, dev_inst, 0); (CR_SUCCESS != result)) {
|
||
|
spdlog::error(L"Couldn't get device Parent; Device {}; Code: {}", device_instance_path, result);
|
||
|
return {};
|
||
|
}
|
||
|
if (const auto result = CM_Get_DevNode_PropertyW(dev_inst_parent, &DEVPKEY_Device_InstanceId, &dev_prop_type, reinterpret_cast<PBYTE>(res.data()), &needed, 0); (CR_SUCCESS != result)) {
|
||
|
spdlog::error(L"Couldn't locate device DevNode Property; Device {}; Code: {}", device_instance_path, result);
|
||
|
return {};
|
||
|
}
|
||
|
if (DEVPROP_TYPE_STRING != dev_prop_type) {
|
||
|
spdlog::error(L"Device Prop is not STRING; Device {}", device_instance_path);
|
||
|
return {};
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
bool HidHide::IsGamingDevice(const HIDD_ATTRIBUTES& attributes, const HIDP_CAPS& capabilities)
|
||
|
{
|
||
|
return (
|
||
|
// 0x28DE 0x1142 = Valve Corporation Steam Controller
|
||
|
// keep them for now
|
||
|
/* ((attributes.VendorID == 0x28DE) && (attributes.ProductID == 0x1142)) || */
|
||
|
(0x05 == capabilities.UsagePage) || (0x01 == capabilities.UsagePage) && ((0x04 == capabilities.Usage) || (0x05 == capabilities.Usage)));
|
||
|
}
|