Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,16 @@ be compiler-neutral: prefer a stable C ABI, named pipe, device interface IOCTL,
or similar control channel over passing C++ STL types across that boundary.

The current Windows backend selects a UMDF control-channel implementation for
`BackendKind::platform_default`. It probes `\\.\LibVirtualHid`, reports
`requires_installed_driver = true`, and only advertises gamepad/output-report
support when the driver package is installed and the control device can be
opened. The client library stays buildable with MSVC and MinGW/UCRT64 because
the backend talks to the driver through fixed-size C protocol structures and
Win32 `DeviceIoControl` calls. The default control device path can be overridden
for diagnostics with `LIBVIRTUALHID_WINDOWS_CONTROL_DEVICE`.
`BackendKind::platform_default`. It always exposes keyboard and mouse through
Win32 `SendInput`, then probes `\\.\LibVirtualHid` for descriptor-driven virtual
gamepads. It reports `requires_installed_driver = true`, and only advertises
gamepad/output-report support when the driver package is installed and the
control device can be opened. Touchscreen, trackpad, and pen tablet support are
not implemented in the Windows backend yet. The client library stays buildable
with MSVC and MinGW/UCRT64 because the gamepad path talks to the driver through
fixed-size C protocol structures and Win32 `DeviceIoControl` calls. The default
control device path can be overridden for diagnostics with
`LIBVIRTUALHID_WINDOWS_CONTROL_DEVICE`.

The UMDF driver uses Windows Virtual HID Framework (VHF) for OS-visible gamepad
devices. Create requests start a VHF child device from the requested descriptor,
Expand Down
11 changes: 9 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,15 @@ target_sources(${PROJECT_NAME}

if(LIBVIRTUALHID_USES_THREADS)
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBEVDEV REQUIRED IMPORTED_TARGET libevdev)
if(LIBEVDEV_CUSTOM_INCLUDE_DIR AND LIBEVDEV_CUSTOM_LIBRARY)
add_library(PkgConfig::LIBEVDEV UNKNOWN IMPORTED)
set_target_properties(PkgConfig::LIBEVDEV PROPERTIES
IMPORTED_LOCATION "${LIBEVDEV_CUSTOM_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${LIBEVDEV_CUSTOM_INCLUDE_DIR}")
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBEVDEV REQUIRED IMPORTED_TARGET libevdev)
endif()
if(LIBVIRTUALHID_ENABLE_XTEST)
find_package(X11 QUIET)
endif()
Expand Down
1 change: 1 addition & 0 deletions src/platform/windows/control_protocol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
namespace lvh::detail::windows {

inline constexpr std::string_view default_control_device_path {LVH_WINDOWS_CONTROL_DEVICE_PATH};
inline constexpr std::string_view global_control_device_path {LVH_WINDOWS_GLOBAL_CONTROL_DEVICE_PATH};

inline std::uint32_t gamepad_flags(const GamepadProfileCapabilities &capabilities) {
std::uint32_t flags = 0;
Expand Down
6 changes: 5 additions & 1 deletion src/platform/windows/driver/libvirtualhid_umdf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ EVT_VHF_ASYNC_OPERATION LvhEvtVhfWriteReport;
namespace {

constexpr auto symbolic_link_name = L"\\DosDevices\\LibVirtualHid";
constexpr auto global_symbolic_link_name = L"\\DosDevices\\Global\\LibVirtualHid";

struct DeviceRecord {
std::mutex mutex;
Expand Down Expand Up @@ -472,12 +473,15 @@ NTSTATUS LvhEvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init) {
}

UNICODE_STRING symbolic_link;
RtlInitUnicodeString(&symbolic_link, symbolic_link_name);
RtlInitUnicodeString(&symbolic_link, global_symbolic_link_name);
status = WdfDeviceCreateSymbolicLink(device, &symbolic_link);
if (!NT_SUCCESS(status)) {
return status;
}

RtlInitUnicodeString(&symbolic_link, symbolic_link_name);
static_cast<void>(WdfDeviceCreateSymbolicLink(device, &symbolic_link));

status = initialize_vhf_target(device);
if (!NT_SUCCESS(status)) {
return status;
Expand Down
2 changes: 2 additions & 0 deletions src/platform/windows/shared/lvh_windows_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

inline constexpr uint32_t LVH_WINDOWS_CONTROL_PROTOCOL_VERSION = 1u;
inline constexpr char LVH_WINDOWS_CONTROL_DEVICE_PATH[] = R"(\\.\LibVirtualHid)";
inline constexpr char LVH_WINDOWS_GLOBAL_CONTROL_DEVICE_PATH[] = R"(\\.\Global\LibVirtualHid)";

inline constexpr uint32_t LVH_WINDOWS_MAX_REPORT_DESCRIPTOR_SIZE = 1024u;
inline constexpr uint32_t LVH_WINDOWS_MAX_INPUT_REPORT_SIZE = 256u;
Expand Down Expand Up @@ -161,6 +162,7 @@ enum {
};

static const char LVH_WINDOWS_CONTROL_DEVICE_PATH[] = "\\\\.\\LibVirtualHid";
static const char LVH_WINDOWS_GLOBAL_CONTROL_DEVICE_PATH[] = "\\\\.\\Global\\LibVirtualHid";

static const uint32_t LVH_WINDOWS_IOCTL_CREATE_GAMEPAD = 0x8000E000u;
static const uint32_t LVH_WINDOWS_IOCTL_DESTROY_DEVICE = 0x8000E004u;
Expand Down
Loading
Loading