feat: initial Linux implementation#2
Conversation
Replace the placeholder LICENSE with the MIT license (copyright 2026 LizardByte) and replace the template README with a full project README for libvirtualhid. The new README outlines goals, non-goals, reference projects, platform strategy (Windows, Linux, macOS), proposed public API, repository layout, phased implementation and testing plans, and notes that the project is MIT-licensed.
Add GoogleTest as a git submodule at third-party/googletest. Adds .gitmodules entry pointing to https://github.com/google/googletest.git and pins the submodule to commit f8d7d77c06936315286eb55f8de22cd23c188571 to include the testing framework for unit tests.
Add AGENTS.md documenting build, testing, and platform guidance: msys2/ucrt64 invocation on Windows, prefix build dirs with `cmake-build-`, and test executable `test_libvirtualhid` location. Notes gtest is vendored under `third-party/googletest`, and instructs to keep the public C++ API platform-neutral with backend-specific HID details hidden. Specifies primary focus on gamepad support (validate against Sunshine adapter/tests), Windows must remain user-mode and library buildable with MSVC and MinGW/UCRT64, and Linux should prefer uinput/evdev/uhid. Also mandates updating public docs when headers/backends/behavior change and following .clang-format for C/C++ code.
Initial project scaffolding for libvirtualhid: add CMake build system and packaging helpers, public headers (profiles, report, runtime, types) and core source implementations (profiles, report packing, runtime/fake backend, types). Include an example (sunshine_gamepad_adapter), GoogleTest-based unit tests covering profiles, reports and runtime, and helper CMake files for tests and examples. Update .gitignore to ignore CMake build directories. Provides a working in-memory fake backend and utilities for creating/packing gamepad reports to drive further development.
Add a new CI workflow (.github/workflows/ci.yml) that provides cross-platform build and test coverage using a matrix for Linux (GCC/Clang), macOS, Windows (MinGW UCRT64) and Windows MSVC. The workflow checks out the repo, installs platform-specific dependencies, configures CMake (Ninja or Visual Studio), builds, runs ctest, runs an example binary, installs artifacts and uploads the install tree per-matrix job. Also update README.md to document the new CI coverage.
Add Doxygen/Read the Docs plumbing and document the public API. - Add .readthedocs.yaml and docs/Doxyfile to configure Read the Docs and Doxygen. - Add third-party/doxyconfig as a git submodule and update .gitmodules and .gitignore. - Wire docs submodule into CMake (top-level BUILD_DOCS option) so docs can be built when top-level. - Document public headers: add Doxygen-style comments and API surface annotations to include/libvirtualhid/*.hpp (libvirtualhid.hpp, profiles.hpp, report.hpp, runtime.hpp, types.hpp). - Update README to mention the new docs directory and the doxyconfig submodule. These changes enable building hosted documentation (Read the Docs) and provide inline API documentation for consumers of the public headers.
Introduce a repository-wide .clang-format (centrally managed) to standardize C/C++ formatting, update .gitignore to ignore Python virtualenvs (.venv), and add the third-party/lizardbyte-common submodule (pointing to commit 0317edf, branch master).
Add file-level Doxygen comments and reorganize includes/formatting across the project. Group standard vs local includes, adjust whitespace and const-& style, and reflow declarations in public headers (profiles.hpp, report.hpp, runtime.hpp, types.hpp). Also update examples and unit test headers to match the new file headers and include ordering. These are formatting and documentation changes only — no functional behavior intended to be changed.
Introduce a BaseTest fixture to centralize test setup/teardown and capture std::cout for easier debugging. Adds tests/fixtures/include/fixtures/fixtures.hpp and tests/fixtures/fixtures.cpp, redefines TEST to automatically use BaseTest, and updates tests to include the new fixture header instead of pulling gtest directly. Update tests/CMakeLists.txt to compile the fixture source and add its include directory to the test binary.
Update CMakeLists.txt to change the project version from 0.1.0 to 0.0.0. This adjusts the package metadata in the build configuration to the desired version.
34f04b7 to
df7babd
Compare
Update .github/workflows/ci.yml: change the Windows-MSVC job's runner from `windows-latest` to `windows-2022`. This pins the workflow to a specific Windows image (2022) instead of the moving `latest` tag to ensure more consistent build environments.
Welcome to Codecov 🎉Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests. Thanks for integrating Codecov - We've got you covered ☂️ |
b2b04b9 to
a3e9d32
Compare
Enhance CI to collect and upload test coverage and results. Adds Python/uv setup, syncs Python tools, runs tests producing gtest XML, generates a gcovr coverage.xml, and uploads artifacts. Introduces a separate codecov job to download artifacts and push coverage/test results to Codecov (only for repos under LizardByte/ and non-MSVC platforms where applicable). Update CMakeLists to enable -fprofile-arcs/-ftest-coverage flags for non-MSVC test builds and ensure coverage flags are set before adding test sources.
a3e9d32 to
a6e6229
Compare
Enable coverage collection for Windows MSVC runs using OpenCppCoverage. Adds OPENCPPCOVERAGE_VERSION env var and installs opencppcoverage via Chocolatey for MSVC matrix jobs. Replaces the direct test invocation with a PowerShell step that runs OpenCppCoverage to export a Cobertura coverage XML and produces the JUnit report. Adds a normalization step to rewrite absolute MSVC file paths to repository-relative paths in the generated coverage.xml (and set sources to '.') so coverage consumers work correctly. Marks the Windows-MSVC job as having coverage in the report matrix.
7d30f94 to
90bfa79
Compare
Introduce an internal backend abstraction and platform backends, enabling real virtual HID devices on Linux via UHID. Add core/backend.hpp and core/backend.cpp with fake in-memory backend for tests, and wire backend gamepad lifecycle into runtime (create/submit/close and output callbacks). Implement a Linux UHID backend (src/platform/linux/uhid_backend.cpp) that opens /dev/uhid, handles UHID events, and runs a reader thread; add an unsupported_backend fallback for non-Linux platforms. Update CMake to detect when threads are required, conditionally link/find Threads, and select the appropriate platform source files. Update the exported config to find Threads when used. Update tests to assert platform-default capabilities and add an opt-in UHID integration smoke test gated by an environment variable. Document UHID usage and a sample udev rule in README. Also improve runtime cleanup and error propagation for backend operations.
Add support for backend output reports and rumble feedback. Introduces DeviceProfile::output_report_size and a parse_output_report declaration in report.hpp. Implements parse_output_report (and a read_u16 helper) to translate raw HID output reports into the profile-neutral GamepadOutput (rumble parsing when report_id and size match). Updates profiles to generate a vendor-defined output region in the HID descriptor when supports_rumble is true and set an output_report_size for those profiles. Updates the UHID backend to store the active profile, route UHID output/SET_REPORT data to the parser and callback, and return success for SET_REPORT replies. Adds unit tests validating profile output report exposure and parsing behavior, and marks the README checklist item as completed.
Introduce first-class Keyboard and Mouse device types and full runtime/backend plumbing: new types and events, CreateKeyboard/CreateMouse options and results, Keyboard/Mouse handles, validation, lifecycle and submit APIs. Extend core backend interfaces and fake backend to support backend-side keyboard/mouse implementations. Add Linux uinput support and optional X11/XTest fallback (CMake option LIBVIRTUALHID_ENABLE_XTEST), including translation helpers, UTF-8 decoding, uinput device wrapper and ioctl handling in the UHID backend. Add built-in keyboard/mouse profiles, an example adapter, CMake targets, and README documentation updates describing behavior, tests, and integration guidance.
Replace Sunshine-specific naming and wording with more generic/streaming-host-oriented terms. Renamed example sources and targets (sunshine_gamepad_adapter -> gamepad_adapter, sunshine_keyboard_mouse_adapter -> keyboard_mouse_adapter) and updated CMakeLists and CI workflow to run the new binaries. Renamed unit test and test fixture (test_sunshine_adapter -> test_gamepad_lifecycle) and updated stable_id values used in examples/tests. Documentation updates in AGENTS.md and README.md shift wording from Sunshine to remote/streaming hosts, clarify Linux uinput/uhid rules and setup, and adjust preferred backend guidance. Also refined a types.hpp comment to clarify the KeyboardKeyCode interpretation for backends.
Add an opt-in Linux discovery integration: new example (examples/linux_discovery_probe.cpp) and test (tests/unit/test_linux_discovery.cpp) that create a UHID gamepad and probe external discovery tools (sdl2-jstest, hidapitester). README updated to document the LIBVIRTUALHID_ENABLE_DISCOVERY_INTEGRATION_TESTS env var, example behavior, and related streaming-host requirements; several checklist items were adjusted. CMakeLists updated to build the linux_discovery_probe example on Linux and include the new test in the test binary. Tests skip cleanly when UHID or probe tools are unavailable.
0ca77a2 to
b47b310
Compare
2f36c12 to
1fe45e7
Compare
Replace external discovery-based tests with in-process consumer integration tests that validate virtual devices via SDL2 and libinput. Added tests/unit/test_linux_consumers.cpp and updated tests/CMakeLists.txt to use pkg-config and link PkgConfig::LIBINPUT and PkgConfig::SDL2. Removed the linux_discovery_probe example and the legacy tests/unit/test_linux_discovery.cpp, and cleaned up examples/CMakeLists.txt. Updated README to document the new Linux test requirements (SDL2, libinput, device nodes, X11/XTest where applicable) and adjusted CI (.github/workflows/ci.yml) to install libinput-dev, libsdl2-dev and pkg-config instead of the old joystick package.
1fe45e7 to
f998905
Compare
Rename the Status type to OperationStatus across the codebase and update all related APIs and implementations (constructors, factory methods, ok/code/message accessors, virtual interfaces, and return usages). Propagate the change through core/runtime, core/backend, core/types, platform implementations (linux UHID/uinput and XTest fallbacks, unsupported backend), tests/fixtures, and fake backends. Also tweak the CI workflow warning message concatenation and remove the Xlib Status macro undef block in the Linux UHID backend.
Update tests/unit/test_linux_backend.cpp to conditionally check for keyboard, mouse and XTEST fallback support when LIBVIRTUALHID_HAVE_XTEST is defined. Also reorder the output_reports expectation. This makes the fake Linux backend test adapt to builds with or without XTEST enabled so test expectations match configuration.
ff21bbd to
8d85dbf
Compare
Introduce first-class touchscreen, trackpad, and pen-tablet device types across the library. Public API: new DeviceType entries, DeviceNode reporting, Create*Options, creation results, and Runtime create_touchscreen/create_trackpad/create_pen_tablet overloads. Runtime/VirtualDevice: new Touchscreen/Trackpad/PenTablet handle classes with submit APIs (place_contact/release_contact/button/place_tool/button) and device_nodes accessors. Backend: new BackendTouchscreen/BackendTrackpad/BackendPenTablet interfaces, backend creation results, device_nodes hooks, and in-memory Fake* backends for tests; default in-memory backend capability flags updated. Profiles/reports: add DualSense USB/Bluetooth profiles, USB descriptor, report packing/parsing helpers, and parse_output_reports API; also add generic touchscreen/trackpad/pen-tablet built-in profiles. Types: add DeviceNode/DeviceNodeKind, touch/pen structures, battery/motion types, gamepad touch contact, auto-repeat interval, and various enums/fields required by new devices and DualSense features. Docs/tests: update README with Phase 2B notes and new device types; update unit tests accordingly.
a6d9182 to
d9f6609
Compare
d9f6609 to
e2a7926
Compare
Implement Bluetooth DualSense support and signed feature reports: add Bluetooth report descriptor and 78-byte report sizes, Bluetooth framing (reserved byte + report id), CRC calculation/writing, and input/output packing/parsing changes in core profiles and report handling. Extend the UHID Linux backend to reply to DualSense GET_REPORT requests (calibration, pairing, firmware), include feature CRC signing, generate/format MACs for unique IDs, and add a periodic reporter to emit steady input reports. Update README task status to reflect added parity items. Add unit/fixture tests exercising UHID feature replies, Bluetooth-framed input reports, and new libinput consumer tests for touchscreen/trackpad behavior.
e2a7926 to
fe3726f
Compare
Bump third-party/lizardbyte-common submodule from 0317edf to 8d7dcc9 to pick up upstream changes. This commit only updates the submodule pointer.
Replace fragile direct uinput ioctl setup with libevdev-based construction for uinput devices. Key changes: - src: include libevdev headers and implement a new libevdev creation path (create_libevdev_uinput_device) that configures devices via libevdev APIs and creates uinput handles; add uinput_device_ member and use libevdev_uinput_destroy when appropriate. Many per-device setup routines were converted from direct ioctl/syscall sets to libevdev enable/config helpers and absinfo construction. - CMake: add PkgConfig usage and pkg_check_modules(LIBEVDEV) in src, tests, and exported config so libevdev is required when threads are enabled; link PkgConfig::LIBEVDEV into the library and test binary. - Tests: extend test fixtures to fake/record libevdev calls (new fake libevdev structures, wrappers and macros) and add test helpers for creating and asserting libevdev-based uinput creation; update tests CMake to link libevdev. - CI & docs: install libevdev-dev in CI image and update README to document that libevdev is used internally for uinput device construction and mark the TODO as completed. This change keeps the public API unchanged while moving uinput device construction to libevdev for more robust and less error-prone setup. Tests include fakes to exercise failure and success paths of the new libevdev integration.
Relocate the public C++ headers from include/libvirtualhid to src/include/libvirtualhid and update project references accordingly. Adjust README examples, Doxygen INPUT, CMake target_include_directories and install(DIRECTORY) paths to the new location, and update the headers' @file tags to reflect their new paths so docs, build, and installation use the updated layout.
149f49a to
16efecf
Compare
Add CI/coverage/stars badges and clarify README SDL/libinput entries. Refactor Linux SDL test code: add headers, SDL_GameController RAII alias, SdlGamepadConsumerCase, and reusable helpers for inspecting joystick/controller state, waiting for input, and configuring HIDAPI hints. Introduce create/expect helper functions and two new test runners for UHID joysticks and DualSense controllers, then replace the original test with calls to these runners. Add explicit DualSense USB and Bluetooth test cases and no-op stubs for non-Linux builds. These changes reduce duplication and improve coverage for generic gamepad and DualSense behavior in SDL.
16efecf to
3b496d0
Compare
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
| EXPECT_EQ(lvh::detail::test::linux_dualsense_mac_address("02-03-04-05-06-07", 0x1020304), "02:00:01:02:03:04"); | ||
| EXPECT_EQ(lvh::detail::test::linux_dualsense_mac_address("ff:00:100:00:00:00", 0x1020304), "02:00:01:02:03:04"); | ||
|
|
||
| const auto temp_dir = std::filesystem::temp_directory_path(); |
|




Description
Initial implementation.
Screenshot
Issues Fixed or Closed
Roadmap Issues
Type of Change
Checklist
AI Usage