Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
589f3ec
feat(macOS): add gamepad broker
ReenigneArcher Sep 25, 2026
f33603a
fix(ci): repair macOS build, lint, and documentation
ReenigneArcher Sep 25, 2026
3dc2c91
fix(ci): correct lipo syntax and remaining formatting
ReenigneArcher Sep 25, 2026
5bb01ab
refactor(macos): use jthread across broker workers
ReenigneArcher Sep 25, 2026
a4021fe
fix(macos): harden broker IPC and address code analysis
ReenigneArcher Sep 25, 2026
2e33f2d
fix(macos): bound broker errors and format stable IDs
ReenigneArcher Sep 25, 2026
f1811da
fix(macos): document intentional broker security boundaries
ReenigneArcher Sep 25, 2026
813ecf4
fix(macos): scope worker analyzer annotation
ReenigneArcher Sep 25, 2026
fb9545e
refactor: share broker license policy and expand macOS CI
ReenigneArcher Sep 25, 2026
1984478
ci: keep Apple secret expressions within YAML lint limit
ReenigneArcher Sep 25, 2026
bf1419c
ci: satisfy ShellCheck in macOS broker smoke test
ReenigneArcher Sep 25, 2026
e079d4b
fix: remove obsolete Windows license constant
ReenigneArcher Sep 25, 2026
c1973f7
test: use shared license limits in Windows broker fixtures
ReenigneArcher Sep 25, 2026
97164f7
ci: scope coverage to macOS code exercised by hosted runners
ReenigneArcher Sep 25, 2026
9897aa7
ci: add YAML document start to Codecov config
ReenigneArcher Sep 25, 2026
1ec7500
ci: retain full Codecov coverage reporting
ReenigneArcher Sep 25, 2026
9688564
Add local macOS PR build and install helper
ReenigneArcher Sep 25, 2026
65858ec
Support local signed macOS PR package builds
ReenigneArcher Sep 25, 2026
2884842
Import Developer ID intermediate for local signing
ReenigneArcher Sep 25, 2026
8547c22
Document macOS virtual HID privacy approval
ReenigneArcher Sep 25, 2026
70208f7
Fix macOS local build script ShellCheck warning
ReenigneArcher Sep 25, 2026
8ce0eb5
Bundle macOS control app and install both apps in Applications
ReenigneArcher Sep 25, 2026
e108e7b
Fix macOS Xbox gamepad mapping and Steam discovery
ReenigneArcher Sep 25, 2026
348698f
Expose distinct Xbox One and Series HID identities on macOS
ReenigneArcher Sep 25, 2026
83de3fc
Share Xbox Bluetooth HID transport across Linux and macOS
ReenigneArcher Sep 26, 2026
26935c7
Fix macOS Xbox One and Series input for virtual transport
ReenigneArcher Sep 26, 2026
30c9c65
Decode wired Xbox rumble output on macOS
ReenigneArcher Sep 26, 2026
47a544a
Match macOS Xbox stick Y direction to other profiles
ReenigneArcher Sep 26, 2026
7f1d66b
Fix Linux Xbox rumble test constant after transport refactor
ReenigneArcher Sep 26, 2026
218d11a
Document verified macOS Xbox controller behavior
ReenigneArcher Sep 26, 2026
d3d77d4
Update end-user-gamepad-guide.md
ReenigneArcher Sep 27, 2026
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
26 changes: 26 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Local macOS PR build settings. Copy this file to .env; .env is ignored by Git.
# Paste values after = without quotes, even for paths containing spaces.
# Use full paths beginning with /Users/... for local files.

# Apple ID used for notarization, and its app-specific password.
APPLE_ID=
APPLE_NOTARYTOOL_PASSWORD=

# The original Developer ID Application .p12 file and its export password.
# Leave the file/password blank only if the certificate and private key are
# already available in this Mac's Keychain.
APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_P12_FILE=
APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_P12_PASSWORD=

# Downloaded provisioning profile for dev.lizardbyte.app.libvirtualhid.
# A profile for another bundle ID will not work.
APPLE_MACOS_VIRTUAL_HID_PROVISIONING_PROFILE=

# Optional: the script detects these from the profile and certificate.
APPLE_TEAM_ID=
APPLE_CODESIGN_IDENTITY=

# Optional alternatives if you have the GitHub workflow's base64 values
# instead of the original local files. Leave blank when using paths above.
APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_BASE64=
APPLE_MACOS_VIRTUAL_HID_PROVISIONING_PROFILE_BASE64=
14 changes: 9 additions & 5 deletions .github/workflows/ci-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,11 @@ jobs:
-S .

- name: Build
run: cmake --build cmake-build-ci --config ${{ env.CMAKE_BUILD_CONFIG }} --parallel 2
run: >-
cmake
-DLIBVIRTUALHID_BUILD_DIRECTORY=cmake-build-ci
-DLIBVIRTUALHID_BUILD_CONFIG=${{ env.CMAKE_BUILD_CONFIG }}
-P cmake/build_with_max_jobs.cmake

- name: Download Windows driver installer artifact
if: runner.os == 'Windows'
Expand Down Expand Up @@ -598,7 +602,7 @@ jobs:
- name: Build and install FreeBSD package
if: matrix.kind == 'freebsd'
run: |
cmake --build cmake-build-package --parallel 2
cmake --build cmake-build-package --parallel "$(sysctl -n hw.ncpu)"
cmake --install cmake-build-package
test ! -d cmake-build-package/install/lib/cmake/lizardbyte-common

Expand All @@ -616,7 +620,7 @@ jobs:
-B cmake-build-package-consumer \
-G Ninja \
-S tests/package-consumer
cmake --build cmake-build-package-consumer --parallel 2
cmake --build cmake-build-package-consumer --parallel "$(sysctl -n hw.ncpu)"

- name: Upload report artifact
if: >-
Expand Down Expand Up @@ -676,7 +680,7 @@ jobs:

- name: Build and install package
run: |
cmake --build cmake-build-package --parallel 2
cmake --build cmake-build-package --parallel "$(nproc)"
cmake --install cmake-build-package
test ! -d cmake-build-package/install/lib/cmake/lizardbyte-common

Expand All @@ -691,4 +695,4 @@ jobs:
-B cmake-build-package-consumer \
-G Ninja \
-S tests/package-consumer
cmake --build cmake-build-package-consumer --parallel 2
cmake --build cmake-build-package-consumer --parallel "$(nproc)"
2 changes: 1 addition & 1 deletion .github/workflows/ci-driver.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ jobs:
libvirtualhid_broker
gamepad_adapter
virtualhid_control
--parallel 2
--parallel $([Environment]::ProcessorCount)

- name: Validate Windows driver setup helper
shell: pwsh
Expand Down
131 changes: 131 additions & 0 deletions .github/workflows/ci-macos-broker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
---
name: CI-macOS-Broker
permissions: {}

on:
workflow_call:
inputs:
publish_release:
required: true
type: string
release_version:
required: true
type: string
secrets:
APPLE_ID:
required: false
APPLE_TEAM_ID:
required: false
APPLE_NOTARYTOOL_PASSWORD:
required: false
APPLE_CODESIGN_IDENTITY:
required: false
APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_BASE64:
required: false
APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_P12_PASSWORD:
required: false
APPLE_MACOS_VIRTUAL_HID_PROVISIONING_PROFILE_BASE64:
required: false

env:
MACOSX_DEPLOYMENT_TARGET: '14.2'

jobs:
macos_broker:
name: Universal macOS broker
permissions:
contents: read
runs-on: macos-15
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
submodules: recursive

- name: Install dependencies
run: brew install cmake

- name: Configure universal build
env:
BUILD_VERSION: ${{ inputs.release_version }}
run: |
cmake -B cmake-build-macos-universal -S . \
-DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_DOCS=OFF \
-DBUILD_TESTS=ON \
-DLIBVIRTUALHID_BUILD_TOOLS=ON \
-DLIBVIRTUALHID_WARNINGS_AS_ERRORS=ON

- name: Build and inspect architectures
run: |
cmake --build cmake-build-macos-universal --parallel "$(sysctl -n hw.ncpu)"
for binary in \
cmake-build-macos-universal/src/platform/macos/broker/VirtualHIDBroker.app/Contents/MacOS/VirtualHIDBroker \
cmake-build-macos-universal/tools/VirtualHIDControl.app/Contents/MacOS/VirtualHIDControl \
cmake-build-macos-universal/src/platform/macos/broker/libvirtualhid-license \
cmake-build-macos-universal/src/libvirtualhid.a; do
xcrun lipo "${binary}" -verify_arch arm64
xcrun lipo "${binary}" -verify_arch x86_64
done

- name: Test broker policy and protocol
run: |
cmake-build-macos-universal/tests/test_libvirtualhid \
'--gtest_filter=BrokerLicensePolicyTest.*:GitHubActionsEvaluationTest.*:MacosBrokerProtocolTest.*'

- name: Smoke test broker and license IPC
run: |
broker=cmake-build-macos-universal/src/platform/macos/broker/VirtualHIDBroker.app/Contents/MacOS/VirtualHIDBroker
license_cli=cmake-build-macos-universal/src/platform/macos/broker/libvirtualhid-license
sudo -n env GITHUB_ACTIONS=true "${broker}" &
broker_pid=$!
trap 'sudo -n kill "${broker_pid}" 2>/dev/null || true' EXIT
ready=false
for (( attempt = 0; attempt < 20; ++attempt )); do
if status_output="$("${license_cli}" status 2>&1)"; then
ready=true
break
fi
sleep 1
done
if [[ "${ready}" != true ]]; then
echo 'Broker did not become ready' >&2
exit 1
fi
grep -F 'Plan: GitHub Actions Evaluation' <<< "${status_output}"
if "${license_cli}" validate >/dev/null 2>&1; then
echo 'Unlicensed validation unexpectedly succeeded' >&2
exit 1
fi

- name: Import Developer ID certificate
if: inputs.publish_release == 'true'
uses: apple-actions/import-codesign-certs@5142e029c445c10ffc7149d172e540235a065466 # v7.0.0
with:
p12-file-base64: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_BASE64 }}
p12-password: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_P12_PASSWORD }}

- name: Sign, notarize, and package
if: inputs.publish_release == 'true'
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_NOTARYTOOL_PASSWORD: ${{ secrets.APPLE_NOTARYTOOL_PASSWORD }}
APPLE_CODESIGN_IDENTITY: ${{ secrets.APPLE_CODESIGN_IDENTITY }}
PROFILE_BASE64: ${{ secrets.APPLE_MACOS_VIRTUAL_HID_PROVISIONING_PROFILE_BASE64 }}
run: |
test -n "${PROFILE_BASE64}" || { echo 'Approved macOS virtual HID provisioning profile is required'; exit 1; }
test -n "${APPLE_ID}" && test -n "${APPLE_TEAM_ID}" && test -n "${APPLE_NOTARYTOOL_PASSWORD}"
profile_path="${RUNNER_TEMP}/libvirtualhid-broker.provisionprofile"
printf '%s' "${PROFILE_BASE64}" | base64 -D > "${profile_path}"
export APPLE_MACOS_VIRTUAL_HID_PROVISIONING_PROFILE="${profile_path}"
bash scripts/macos/package-dmg.sh cmake-build-macos-universal cmake-build-macos-universal/artifacts

- name: Upload disk image
if: inputs.publish_release == 'true'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: macos-virtual-hid-installer
path: cmake-build-macos-universal/artifacts/libvirtualhid-macOS-universal.dmg
if-no-files-found: error
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,27 @@ jobs:
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}

macos_broker:
name: macOS Broker
needs: setup_release
permissions:
contents: read
uses: ./.github/workflows/ci-macos-broker.yml
with:
publish_release: ${{ needs.setup_release.outputs.publish_release }}
release_version: ${{ needs.setup_release.outputs.release_version }}
secrets:
APPLE_ID: ${{ github.event_name == 'push' && secrets.APPLE_ID || '' }}
APPLE_TEAM_ID: ${{ github.event_name == 'push' && secrets.APPLE_TEAM_ID || '' }}
APPLE_NOTARYTOOL_PASSWORD: ${{ github.event_name == 'push' && secrets.APPLE_NOTARYTOOL_PASSWORD || '' }}
APPLE_CODESIGN_IDENTITY: ${{ github.event_name == 'push' && secrets.APPLE_CODESIGN_IDENTITY || '' }}
APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_BASE64: >-
${{ github.event_name == 'push' && secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_BASE64 || '' }}
APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_P12_PASSWORD: >-
${{ github.event_name == 'push' && secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_P12_PASSWORD || '' }}
APPLE_MACOS_VIRTUAL_HID_PROVISIONING_PROFILE_BASE64: >-
${{ github.event_name == 'push' && secrets.APPLE_MACOS_VIRTUAL_HID_PROVISIONING_PROFILE_BASE64 || '' }}

build:
name: Library
needs:
Expand Down Expand Up @@ -104,10 +125,12 @@ jobs:
needs.setup_release.outputs.publish_release == 'true' &&
needs.build.result == 'success' &&
needs.driver.result == 'success' &&
needs.macos_broker.result == 'success' &&
startsWith(github.repository, 'LizardByte/')
needs:
- build
- driver
- macos_broker
- setup_release
permissions:
contents: read
Expand All @@ -119,10 +142,17 @@ jobs:
name: windows-driver-installer
path: windows-driver-installer

- name: Download macOS disk image
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: macos-virtual-hid-installer
path: macos-virtual-hid-installer

- name: Prepare release artifact
run: |
mkdir -p artifacts
cp windows-driver-installer/*.msi artifacts/
cp macos-virtual-hid-installer/*.dmg artifacts/

- name: Validate release metadata
env:
Expand All @@ -134,6 +164,7 @@ jobs:
test -n "${RELEASE_VERSION}"
test "${RELEASE_COMMIT}" = "${GITHUB_SHA}"
test -s "artifacts/libvirtualhid-Windows-AMD64-driver-installer.msi"
test -s "artifacts/libvirtualhid-macOS-universal.dmg"

- name: Create/Update GitHub Release
if: needs.setup_release.outputs.publish_release == 'true'
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# Python
.venv/

# Local macOS signing credentials
/.env

# CMake
build/
cmake-build-*/
Expand Down
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ option(LIBVIRTUALHID_BUILD_WINDOWS_DRIVER "Build the Windows UMDF2 driver packag
option(LIBVIRTUALHID_BUILD_WINDOWS_BROKER
"Build the Windows broker service used by the monetized UMDF driver package"
${LIBVIRTUALHID_BUILD_WINDOWS_DRIVER})
option(LIBVIRTUALHID_BUILD_MACOS_BROKER
"Build the licensed macOS virtual HID broker"
${APPLE})
option(LIBVIRTUALHID_INSTALL
"Install libvirtualhid targets, headers, and CMake package files" ${LIBVIRTUALHID_IS_TOP_LEVEL})
option(LIBVIRTUALHID_ENABLE_PACKAGING "Enable CPack package metadata" ${LIBVIRTUALHID_INSTALL})
Expand Down Expand Up @@ -136,6 +139,11 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
add_subdirectory(src/platform/windows/broker)
endif()

if(APPLE AND LIBVIRTUALHID_BUILD_MACOS_BROKER)
enable_language(OBJCXX)
add_subdirectory(src/platform/macos/broker)
endif()

if(BUILD_DOCS)
include(third-party/dockle/cmake/Dockle.cmake)
dockle_add_docs(docs TARGETS api)
Expand Down
5 changes: 3 additions & 2 deletions LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ summary and does not replace the complete license texts.
- The cross-platform library source, public headers, non-driver backends,
examples, tests, build scripts, and documentation are licensed under the
[MIT License](LICENSES/MIT.md), except where the license map says otherwise.
- The Windows UMDF driver, broker, proprietary entitlement and evaluation
sources, and generated Windows driver package artifacts are licensed under
- The Windows UMDF driver, Windows and macOS brokers, proprietary entitlement
and evaluation sources, and generated Windows driver and macOS broker package
artifacts are licensed under
the [LizardByte Source-Available License 1.0](LICENSES/LicenseRef-LizardByte-SAL-1.0.md).

See the [license map](LICENSES/license-map.md) for the authoritative repository path
Expand Down
8 changes: 6 additions & 2 deletions LICENSES/license-map.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# License Map

`libvirtualhid` uses separate licenses for the cross-platform library and the
Windows driver package.
Windows driver and macOS broker packages.

- LB-SAL 1.0 SPDX custom identifier: `LicenseRef-LizardByte-SAL-1.0`.
- Cross-platform library source, public headers, non-driver backends, examples,
Expand All @@ -15,8 +15,12 @@ Windows driver package.
[LizardByte Source-Available License 1.0](https://github.com/LizardByte/libvirtualhid/blob/master/LICENSES/LicenseRef-LizardByte-SAL-1.0.md).
- Generated Windows driver package artifacts, including the driver MSI:
[LizardByte Source-Available License 1.0](https://github.com/LizardByte/libvirtualhid/blob/master/LICENSES/LicenseRef-LizardByte-SAL-1.0.md).
- macOS broker source under `src/platform/macos/broker/`, plus generated macOS
broker bundles and DMGs:
[LizardByte Source-Available License 1.0](https://github.com/LizardByte/libvirtualhid/blob/master/LICENSES/LicenseRef-LizardByte-SAL-1.0.md).

Every installed library distribution includes the MIT notice under
`share/licenses/libvirtualhid`. The Windows driver MSI may include MIT-licensed
helper components from this repository; packaged installs include both license
texts for that reason.
texts for that reason. The macOS broker DMG likewise includes the MIT library
and the LB-SAL broker, with both license texts.
Loading
Loading