Skip to content

feat: initial Linux implementation#2

Merged
ReenigneArcher merged 33 commits into
masterfrom
feat/initial-version
Jun 19, 2026
Merged

feat: initial Linux implementation#2
ReenigneArcher merged 33 commits into
masterfrom
feat/initial-version

Conversation

@ReenigneArcher

Copy link
Copy Markdown
Member

Description

Initial implementation.

Screenshot

Issues Fixed or Closed

Roadmap Issues

Type of Change

  • feat: New feature (non-breaking change which adds functionality)
  • fix: Bug fix (non-breaking change which fixes an issue)
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semicolons, etc.)
  • refactor: Code change that neither fixes a bug nor adds a feature
  • perf: Code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit
  • BREAKING CHANGE: Introduces a breaking change (can be combined with any type above)

Checklist

  • Code follows the style guidelines of this project
  • Code has been self-reviewed
  • Code has been commented, particularly in hard-to-understand areas
  • Code docstring/documentation-blocks for new or existing methods/components have been added or updated
  • Unit tests have been added or updated for any new or modified functionality

AI Usage

  • None: No AI tools were used in creating this PR
  • Light: AI provided minor assistance (formatting, simple suggestions)
  • Moderate: AI helped with code generation or debugging specific parts
  • Heavy: AI generated most or all of the code changes

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.
@ReenigneArcher ReenigneArcher changed the title Feat/initial version feat: initial version Jun 18, 2026
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.
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.
@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

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 ☂️

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.
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.
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.
@ReenigneArcher ReenigneArcher force-pushed the feat/initial-version branch 4 times, most recently from 0ca77a2 to b47b310 Compare June 19, 2026 00:43
@ReenigneArcher ReenigneArcher force-pushed the feat/initial-version branch 3 times, most recently from 2f36c12 to 1fe45e7 Compare June 19, 2026 02:20
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.
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.
@ReenigneArcher ReenigneArcher force-pushed the feat/initial-version branch 2 times, most recently from ff21bbd to 8d85dbf Compare June 19, 2026 03:53
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.
@ReenigneArcher ReenigneArcher force-pushed the feat/initial-version branch 3 times, most recently from a6d9182 to d9f6609 Compare June 19, 2026 19:16
@ReenigneArcher ReenigneArcher changed the title feat: initial version feat: initial Linux implementation Jun 19, 2026
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.
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.
@ReenigneArcher ReenigneArcher marked this pull request as ready for review June 19, 2026 22:18
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.
@ReenigneArcher ReenigneArcher merged commit 919f923 into master Jun 19, 2026
19 checks passed
@ReenigneArcher ReenigneArcher deleted the feat/initial-version branch June 19, 2026 23:41
@github-advanced-security

Copy link
Copy Markdown

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:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

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();
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
194 New issues
9 New Bugs (required ≤ 0)
184 New Code Smells (required ≤ 0)
10 Duplicated Blocks on New Code (required ≤ 0)
E Reliability Rating on New Code (required ≥ A)
1 New Vulnerabilities (required ≤ 0)
D Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants