You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

hidapi

Package Overview
Dependencies
Maintainers
1
Versions
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

hidapi - cargo Package Compare versions

Comparing version
2.5.0
to
2.5.1
+6
.cargo_vcs_info.json
{
"git": {
"sha1": "19b3f78096fc6e3cfe3e45c007161e31b8aa7eb7"
},
"path_in_vcs": ""
}
+29
-41

@@ -6,18 +6,12 @@ # This file is automatically @generated by Cargo.

[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
[[package]]
name = "cc"
version = "1.0.78"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"

@@ -31,4 +25,10 @@ [[package]]

[[package]]
name = "hermit-abi"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f"
[[package]]
name = "hidapi"
version = "2.5.0"
version = "2.5.1"
dependencies = [

@@ -45,6 +45,17 @@ "cc",

[[package]]
name = "io-lifetimes"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi",
"libc",
"windows-sys",
]
[[package]]
name = "libc"
version = "0.2.139"
version = "0.2.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"

@@ -62,15 +73,6 @@ [[package]]

[[package]]
name = "memoffset"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
dependencies = [
"autocfg",
]
[[package]]
name = "nix"
version = "0.26.2"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
dependencies = [

@@ -80,14 +82,5 @@ "bitflags",

"libc",
"memoffset",
"pin-utils",
"static_assertions",
]
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"

@@ -99,13 +92,8 @@ version = "0.3.26"

[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "udev"
version = "0.7.0"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebdbbd670373442a12fe9ef7aeb53aec4147a5a27a00bbc3ab639f08f48191a"
checksum = "50051c6e22be28ee6f217d50014f3bc29e81c20dc66ff7ca0d5c5226e1dcc5a1"
dependencies = [
"io-lifetimes",
"libc",

@@ -112,0 +100,0 @@ "libudev-sys",

@@ -15,3 +15,3 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO

name = "hidapi"
version = "2.5.0"
version = "2.5.1"
authors = [

@@ -27,2 +27,24 @@ "Roland Ruckerbauer <roland.rucky@gmail.com>",

links = "hidapi"
include = [
"README.md",
"LICENSE.txt",
"build.rs",
"/src",
"/etc/hidapi/CMakeLists.txt",
"/etc/hidapi/LICENSE*",
"/etc/hidapi/VERSION",
"/etc/hidapi/hidapi",
"/etc/hidapi/libusb",
"/etc/hidapi/src",
"/etc/hidapi/udev",
"/etc/hidapi/linux/CMakeLists.txt",
"/etc/hidapi/linux/*.c",
"/etc/hidapi/linux/*.h",
"/etc/hidapi/mac/CMakeLists.txt",
"/etc/hidapi/mac/*.c",
"/etc/hidapi/mac/*.h",
"/etc/hidapi/windows/CMakeLists.txt",
"/etc/hidapi/windows/*.c",
"/etc/hidapi/windows/*.h",
]
description = "Rust-y wrapper around hidapi"

@@ -88,7 +110,12 @@ documentation = "https://docs.rs/hidapi"

[target."cfg(target_os = \"linux\")".dependencies.nix]
version = "0.26"
version = "0.27"
features = [
"fs",
"ioctl",
"poll",
]
optional = true
[target."cfg(target_os = \"linux\")".dependencies.udev]
version = "0.7"
version = "0.8"
optional = true

@@ -95,0 +122,0 @@

@@ -280,3 +280,3 @@ // **************************************************************************

if device.is_null() {
match self.check_error() {
match HidApiBackend::check_error() {
Ok(err) => Err(err),

@@ -283,0 +283,0 @@ Err(e) => Err(e),

@@ -492,3 +492,3 @@ //! This backend uses libudev to discover devices and then talks to hidraw directly

fn read_timeout(&self, buf: &mut [u8], timeout: i32) -> HidResult<usize> {
let pollfd = PollFd::new(self.fd.as_raw_fd(), PollFlags::POLLIN);
let pollfd = PollFd::new(&self.fd, PollFlags::POLLIN);
let res = poll(&mut [pollfd], timeout)?;

@@ -495,0 +495,0 @@

name: Rust
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
CARGO_TERM_COLOR: always
jobs:
build-linux:
runs-on: ubuntu-latest
env:
DEBIAN_FRONTEND: noninteractive
strategy:
fail-fast: false # don't give up on the whole matrix if one variant fails
matrix:
linkage: ["static", "shared"]
library: ["hidraw", "libusb"]
steps:
- name: checkout repository and submodules
uses: actions/checkout@v2
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y cmake libudev-dev libumockdev-dev umockdev
- name: Build libusb
run: |
git clone https://github.com/libusb/libusb.git ./etc/libusb/
cd ./etc/libusb/
./autogen.sh
make
sudo make install
- name: Build hidapi
run: |
cd ./etc/hidapi/
mkdir ./build/
cd ./build/
cmake ..
make
sudo make install
- name: List pkgconfig definitions
run: grep -RHn ^ /usr/local/lib/pkgconfig
- name: Build
run: cargo build --no-default-features --features linux-${{ matrix.linkage }}-${{ matrix.library }} --verbose
- name: Run tests
run: cargo test --no-default-features --features linux-${{ matrix.linkage }}-${{ matrix.library }} --verbose
build-linux-native:
runs-on: ubuntu-latest
env:
DEBIAN_FRONTEND: noninteractive
steps:
- name: checkout repository and submodules
uses: actions/checkout@v2
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y libudev-dev
- name: Build
run: cargo build --no-default-features --features linux-native --verbose
- name: Run tests
run: cargo test --no-default-features --features linux-native --verbose
build-windows:
runs-on: windows-latest
steps:
- name: checkout repository and submodules
uses: actions/checkout@v2
with:
submodules: recursive
- name: Install rust environment
run: |
curl.exe --proto "=https" --tlsv1.2 -L -o rustup-init.exe https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe
.\rustup-init.exe -y
- name: Build
run: cargo build --no-default-features --verbose
- name: Run tests
run: cargo test --no-default-features --verbose
build-windows-native:
runs-on: windows-latest
steps:
- name: checkout repository and submodules
uses: actions/checkout@v2
with:
submodules: recursive
- name: Install rust environment
run: |
curl.exe --proto "=https" --tlsv1.2 -L -o rustup-init.exe https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe
.\rustup-init.exe -y
- name: Build
run: cargo build --no-default-features --features windows-native --verbose
- name: Run tests
run: cargo test --no-default-features --features windows-native --verbose
build-macos:
runs-on: macos-latest
steps:
- name: checkout repository and submodules
uses: actions/checkout@v2
with:
submodules: recursive
- name: Install rust environment
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
- name: Build
run: cargo build --no-default-features --verbose
- name: Run tests
run: cargo test --no-default-features --verbose
fmt-check:
runs-on: ubuntu-latest
env:
DEBIAN_FRONTEND: noninteractive
steps:
- name: checkout repository and submodules
uses: actions/checkout@v2
with:
submodules: recursive
- name: fmt check
run: cargo fmt --check
target
Cargo.lock
.idea/
hidapi-rs.iml
[submodule "etc/hidapi"]
path = etc/hidapi
url = https://github.com/libusb/hidapi.git
language: rust
matrix:
include:
- env: TARGET=x86_64-unknown-linux-gnu FEATURE_FLAGS="linux-static-libusb"
- env: TARGET=x86_64-unknown-linux-gnu FEATURE_FLAGS="linux-static-hidraw"
- env: TARGET=x86_64-unknown-linux-gnu FEATURE_FLAGS="linux-shared-libusb"
- env: TARGET=x86_64-unknown-linux-gnu FEATURE_FLAGS="linux-shared-hidraw"
- env: TARGET=x86_64-apple-darwin
os: osx
script:
- cargo build --verbose --no-default-features --features="${FEATURE_FLAGS}"
- cargo test --verbose --no-default-features --features="${FEATURE_FLAGS}"
addons:
apt:
packages:
- libusb-1.0-0-dev
- libudev-dev
- libhidapi-dev
{
"rust-analyzer.cargo.noDefaultFeatures": true,
"rust-analyzer.cargo.features": ["linux-native"]
}
environment:
matrix:
- BUILD_ENV: msbuild
arch: x64
- BUILD_ENV: msbuild
arch: Win32
- BUILD_ENV: cygwin
for:
-
matrix:
only:
- BUILD_ENV: msbuild
os: Visual Studio 2015
build_script:
- cmd: msbuild .\windows\hidapi.sln /p:Configuration=Release /p:Platform=%arch% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
-
matrix:
only:
- BUILD_ENV: cygwin
os: Visual Studio 2022
install:
- cmd: C:\cygwin64\setup-x86_64.exe --quiet-mode --no-shortcuts --upgrade-also --packages autoconf,automake
build_script:
- cmd: C:\cygwin64\bin\bash -exlc "cd $APPVEYOR_BUILD_FOLDER; ./bootstrap; ./configure; make"
image: freebsd/latest
packages:
- autoconf
- automake
- gmake
- libiconv
- libtool
- pkgconf
- cmake
- ninja
sources:
- https://github.com/libusb/hidapi
tasks:
- configure: |
cd hidapi
echo Configure Autotools build
./bootstrap
./configure
echo Configure CMake build
mkdir -p build install_cmake
cmake -GNinja -B build -S . -DCMAKE_INSTALL_PREFIX=install_cmake
- build-autotools: |
cd hidapi
make
make DESTDIR=$PWD/root install
make clean
- build-cmake: |
cd hidapi/build
ninja
ninja install
ninja clean
- build-manual: |
cd hidapi/libusb
gmake -f Makefile-manual
image: netbsd/latest
packages:
- cmake
- pkgconf
- libusb1
- libiconv
sources:
- https://github.com/libusb/hidapi
tasks:
- configure: |
cd hidapi
mkdir -p build install
cmake -B build -S . -DCMAKE_INSTALL_PREFIX=install
- build: |
cd hidapi/build
make
make install
make clean
image: openbsd/latest
packages:
- cmake
- pkgconf
- libusb1--
- libiconv
- ninja
sources:
- https://github.com/libusb/hidapi
tasks:
- configure: |
cd hidapi
mkdir -p build install
cmake -GNinja -B build -S . -DCMAKE_INSTALL_PREFIX=install
- build: |
cd hidapi/build
ninja
ninja install
ninja clean
alpine_task:
container:
image: alpine:latest
install_script: apk add autoconf automake g++ gcc libusb-dev libtool linux-headers eudev-dev make musl-dev
script:
- ./bootstrap
- ./configure || { cat config.log; exit 1; }
- make
- make install
freebsd11_task:
freebsd_instance:
image: freebsd-11-2-release-amd64
install_script:
- pkg install -y
autoconf automake libiconv libtool pkgconf
script:
- ./bootstrap
- ./configure || { cat config.log; exit 1; }
- make
- make install
freebsd12_task:
freebsd_instance:
image: freebsd-12-1-release-amd64
install_script:
- pkg install -y
autoconf automake libiconv libtool pkgconf
script:
- ./bootstrap
- ./configure || { cat config.log; exit 1; }
- make
- make install
* text=auto
*.sln text eol=crlf
*.vcproj text eol=crlf
bootstrap text eol=lf
configure.ac text eol=lf
name: GitHub Builds
on: [push, pull_request]
env:
NIX_COMPILE_FLAGS: -Wall -Wextra -pedantic -Werror
MSVC_COMPILE_FLAGS: /W4 /WX
jobs:
macos-automake:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Install build tools
run: brew install autoconf automake libtool
- name: Configure Automake
run: |
./bootstrap
./configure --prefix=$(pwd)/install
- name: Build Automake
run: |
make
make install
- name: Clean build
run: make clean
- name: Build Manual makefile
working-directory: mac
run: make -f Makefile-manual
macos-cmake:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
with:
path: hidapisrc
- name: Install dependencies
run: brew install meson ninja
- name: Configure CMake
run: |
rm -rf build install
cmake -B build/shared -S hidapisrc -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHIDAPI_ENABLE_ASAN=ON -DCMAKE_INSTALL_PREFIX=install/shared -DHIDAPI_BUILD_HIDTEST=ON "-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
cmake -B build/static -S hidapisrc -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHIDAPI_ENABLE_ASAN=ON -DCMAKE_INSTALL_PREFIX=install/static -DBUILD_SHARED_LIBS=FALSE -DHIDAPI_BUILD_HIDTEST=ON "-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
cmake -B build/framework -S hidapisrc -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHIDAPI_ENABLE_ASAN=ON -DCMAKE_INSTALL_PREFIX=install/framework -DCMAKE_FRAMEWORK=ON -DHIDAPI_BUILD_HIDTEST=ON "-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
- name: Build CMake Shared
working-directory: build/shared
run: make install
- name: Build CMake Static
working-directory: build/static
run: make install
- name: Build CMake Framework
working-directory: build/framework
run: make install
- name: Check artifacts
uses: andstor/file-existence-action@v2
with:
files: "install/shared/lib/libhidapi.dylib, \
install/shared/include/hidapi/hidapi.h, \
install/shared/include/hidapi/hidapi_darwin.h, \
install/static/lib/libhidapi.a, \
install/static/include/hidapi/hidapi.h, \
install/static/include/hidapi/hidapi_darwin.h, \
install/framework/lib/hidapi.framework/hidapi, \
install/framework/lib/hidapi.framework/Headers/hidapi.h, \
install/framework/lib/hidapi.framework/Headers/hidapi_darwin.h"
fail: true
- name: Check CMake Export Package Shared
run: |
cmake \
-B build/shared_test \
-S hidapisrc/hidtest \
-Dhidapi_ROOT=install/shared \
-DCMAKE_INSTALL_PREFIX=install/shared_test \
"-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
cd build/shared_test
make install
- name: Check CMake Export Package Static
run: |
cmake \
-B build/static_test \
-S hidapisrc/hidtest \
-Dhidapi_ROOT=install/static \
-DCMAKE_INSTALL_PREFIX=install/static_test \
"-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
cd build/static_test
make install
- name: Check Meson build
run: |
meson setup build_meson hidapisrc
cd build_meson
ninja
ubuntu-cmake:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
path: hidapisrc
- name: Install dependencies
run: |
sudo apt update
sudo apt install libudev-dev libusb-1.0-0-dev python3-pip ninja-build
sudo -H pip3 install meson
- name: Configure CMake
run: |
rm -rf build install
cmake -B build/shared -S hidapisrc -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHIDAPI_ENABLE_ASAN=ON -DCMAKE_INSTALL_PREFIX=install/shared -DHIDAPI_BUILD_HIDTEST=ON "-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
cmake -B build/static -S hidapisrc -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHIDAPI_ENABLE_ASAN=ON -DCMAKE_INSTALL_PREFIX=install/static -DBUILD_SHARED_LIBS=FALSE -DHIDAPI_BUILD_HIDTEST=ON "-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
- name: Build CMake Shared
working-directory: build/shared
run: make install
- name: Build CMake Static
working-directory: build/static
run: make install
- name: Check artifacts
uses: andstor/file-existence-action@v2
with:
files: "install/shared/lib/libhidapi-libusb.so, \
install/shared/lib/libhidapi-hidraw.so, \
install/shared/include/hidapi/hidapi.h, \
install/shared/include/hidapi/hidapi_libusb.h, \
install/static/lib/libhidapi-libusb.a, \
install/static/lib/libhidapi-hidraw.a, \
install/static/include/hidapi/hidapi.h, \
install/static/include/hidapi/hidapi_libusb.h"
fail: true
- name: Check CMake Export Package Shared
run: |
cmake \
-B build/shared_test \
-S hidapisrc/hidtest \
-Dhidapi_ROOT=install/shared \
-DCMAKE_INSTALL_PREFIX=install/shared_test \
"-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
cd build/shared_test
make install
- name: Check CMake Export Package Static
run: |
cmake \
-B build/static_test \
-S hidapisrc/hidtest \
-Dhidapi_ROOT=install/static \
-DCMAKE_INSTALL_PREFIX=install/static_test \
"-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
cd build/static_test
make install
- name: Check Meson build
run: |
meson setup build_meson hidapisrc
cd build_meson
ninja
windows-cmake:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
with:
path: hidapisrc
- name: Install dependencies
shell: cmd
run: |
choco install ninja
pip3 install meson
refreshenv
- name: Configure CMake MSVC
shell: cmd
run: |
cmake -B build\msvc -S hidapisrc -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHIDAPI_WITH_TESTS=ON -DHIDAPI_BUILD_PP_DATA_DUMP=ON -DHIDAPI_ENABLE_ASAN=ON -DCMAKE_INSTALL_PREFIX=install\msvc -DHIDAPI_BUILD_HIDTEST=ON "-DCMAKE_C_FLAGS=%MSVC_COMPILE_FLAGS%"
- name: Build CMake MSVC
working-directory: build/msvc
run: cmake --build . --config RelWithDebInfo --target install
- name: Check artifacts MSVC
uses: andstor/file-existence-action@v2
with:
files: "install/msvc/lib/hidapi.lib, \
install/msvc/bin/hidapi.dll, \
install/msvc/include/hidapi/hidapi.h, \
install/msvc/include/hidapi/hidapi_winapi.h"
fail: true
- name: Check CMake Export Package
shell: cmd
run: |
cmake ^
-B build\msvc_test ^
-S hidapisrc\hidtest ^
-Dhidapi_ROOT=install\msvc ^
-DCMAKE_INSTALL_PREFIX=install\msvc_test ^
"-DCMAKE_C_FLAGS=%MSVC_COMPILE_FLAGS%"
cd build\msvc_test
cmake --build . --target install
- name: Run CTest MSVC
shell: cmd
working-directory: build/msvc
run: ctest -C RelWithDebInfo --rerun-failed --output-on-failure
- name: Configure CMake NMake
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
cmake -G"NMake Makefiles" -B build\nmake -S hidapisrc -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHIDAPI_WITH_TESTS=ON -DHIDAPI_BUILD_PP_DATA_DUMP=ON -DHIDAPI_ENABLE_ASAN=ON -DCMAKE_INSTALL_PREFIX=install\nmake -DHIDAPI_BUILD_HIDTEST=ON "-DCMAKE_C_FLAGS=%MSVC_COMPILE_FLAGS%"
- name: Build CMake NMake
working-directory: build\nmake
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
nmake install
- name: Check artifacts NMake
uses: andstor/file-existence-action@v2
with:
files: "install/nmake/lib/hidapi.lib, \
install/nmake/bin/hidapi.dll, \
install/nmake/include/hidapi/hidapi.h, \
install/nmake/include/hidapi/hidapi_winapi.h"
fail: true
- name: Check CMake Export Package NMake
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
cmake ^
-G"NMake Makefiles" ^
-B build\nmake_test ^
-S hidapisrc\hidtest ^
-Dhidapi_ROOT=install\nmake ^
-DCMAKE_INSTALL_PREFIX=install\nmake_test ^
"-DCMAKE_C_FLAGS=%MSVC_COMPILE_FLAGS%"
cd build\nmake_test
nmake install
- name: Run CTest NMake
working-directory: build\nmake
run: ctest --rerun-failed --output-on-failure
- name: Configure CMake MinGW
shell: cmd
run: |
cmake -G"MinGW Makefiles" -B build\mingw -S hidapisrc -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHIDAPI_WITH_TESTS=ON -DHIDAPI_BUILD_PP_DATA_DUMP=ON -DCMAKE_INSTALL_PREFIX=install\mingw -DHIDAPI_BUILD_HIDTEST=ON "-DCMAKE_C_FLAGS=%NIX_COMPILE_FLAGS%"
- name: Build CMake MinGW
working-directory: build\mingw
run: cmake --build . --target install
- name: Check artifacts MinGW
uses: andstor/file-existence-action@v2
with:
files: "install/mingw/lib/libhidapi.dll.a, \
install/mingw/bin/libhidapi.dll, \
install/mingw/include/hidapi/hidapi.h, \
install/mingw/include/hidapi/hidapi_winapi.h"
fail: true
- name: Check CMake Export Package MinGW
shell: cmd
run: |
cmake ^
-G"MinGW Makefiles" ^
-B build\mingw_test ^
-S hidapisrc\hidtest ^
-Dhidapi_ROOT=install\mingw ^
-DCMAKE_INSTALL_PREFIX=install\mingw_test ^
"-DCMAKE_C_FLAGS=%NIX_COMPILE_FLAGS%"
cd build\mingw_test
cmake --build . --target install
- name: Run CTest MinGW
working-directory: build\mingw
run: ctest --rerun-failed --output-on-failure
- name: Check Meson build
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
meson setup build_meson hidapisrc
cd build_meson
ninja
windows-msbuild:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: microsoft/setup-msbuild@v1.1
- name: MSBuild x86
run: msbuild windows\hidapi.sln /p:Configuration=Release /p:Platform=Win32
- name: Check artifacts x86
uses: andstor/file-existence-action@v2
with:
files: "windows/Release/hidapi.dll, windows/Release/hidapi.lib, windows/Release/hidapi.pdb"
fail: true
- name: MSBuild x64
run: msbuild windows\hidapi.sln /p:Configuration=Release /p:Platform=x64
- name: Check artifacts x64
uses: andstor/file-existence-action@v2
with:
files: "windows/x64/Release/hidapi.dll, windows/x64/Release/hidapi.lib, windows/x64/Release/hidapi.pdb"
fail: true
- name: Gather artifacts
run: |
md artifacts
md artifacts\x86
md artifacts\x64
md artifacts\include
Copy-Item "windows\Release\hidapi.dll","windows\Release\hidapi.lib","windows\Release\hidapi.pdb" -Destination "artifacts\x86"
Copy-Item "windows\x64\Release\hidapi.dll","windows\x64\Release\hidapi.lib","windows\x64\Release\hidapi.pdb" -Destination "artifacts\x64"
Copy-Item "hidapi\hidapi.h","windows\hidapi_winapi.h" -Destination "artifacts\include"
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: hidapi-win
path: artifacts/
retention-days: ${{ (github.event_name == 'pull_request' || github.ref_name != 'master') && 7 || 90 }}
fedora-mingw:
runs-on: ubuntu-latest
container: fedora:latest
steps:
- uses: actions/checkout@v3
with:
path: hidapisrc
- name: Install dependencies
run: sudo dnf install -y autoconf automake libtool mingw64-gcc cmake ninja-build make
- name: Configure CMake
run: |
rm -rf build install
mingw64-cmake -B build/shared-cmake -S hidapisrc -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=install/shared-cmake -DHIDAPI_BUILD_HIDTEST=ON "-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
mingw64-cmake -B build/static-cmake -S hidapisrc -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=install/static-cmake -DBUILD_SHARED_LIBS=FALSE -DHIDAPI_BUILD_HIDTEST=ON "-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
- name: Configure Automake
working-directory: hidapisrc
run: |
./bootstrap
mingw64-configure
- name: Build CMake Shared
working-directory: build/shared-cmake
run: ninja install
- name: Build CMake Static
working-directory: build/static-cmake
run: ninja install
- name: Build Automake
working-directory: hidapisrc
run: |
make
make DESTDIR=$PWD/../install/automake install
make clean
- name: Build manual Makefile
working-directory: hidapisrc/windows
run: make -f Makefile-manual OS=MINGW CC=x86_64-w64-mingw32-gcc
- name: Check artifacts
uses: andstor/file-existence-action@v2
with:
files: "install/shared-cmake/bin/libhidapi.dll, \
install/shared-cmake/lib/libhidapi.dll.a, \
install/shared-cmake/include/hidapi/hidapi.h, \
install/shared-cmake/include/hidapi/hidapi_winapi.h, \
install/static-cmake/lib/libhidapi.a, \
install/static-cmake/include/hidapi/hidapi.h, \
install/static-cmake/include/hidapi/hidapi_winapi.h"
fail: true
- name: Check CMake Export Package Shared
run: |
mingw64-cmake \
-GNinja \
-B build/shared_test \
-S hidapisrc/hidtest \
-Dhidapi_DIR=$PWD/install/shared-cmake/lib/cmake/hidapi \
-DCMAKE_INSTALL_PREFIX=install/shared_test \
"-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
cd build/shared_test
ninja install
- name: Check CMake Export Package Static
run: |
mingw64-cmake \
-GNinja \
-B build/static_test \
-S hidapisrc/hidtest \
-Dhidapi_DIR=$PWD/install/static-cmake/lib/cmake/hidapi \
-DCMAKE_INSTALL_PREFIX=install/static_test \
"-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
cd build/static_test
ninja install
archlinux:
runs-on: ubuntu-latest
container: archlinux:latest
steps:
- uses: actions/checkout@v3
with:
path: hidapisrc
- name: Install dependencies
run: |
pacman -Sy
pacman -S --noconfirm gcc pkg-config autoconf automake libtool libusb libudev0 cmake make
- name: Configure CMake
run: |
rm -rf build install
cmake -B build/shared-cmake -S hidapisrc -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=install/shared-cmake -DHIDAPI_BUILD_HIDTEST=ON "-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
cmake -B build/static-cmake -S hidapisrc -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=install/static-cmake -DBUILD_SHARED_LIBS=FALSE -DHIDAPI_BUILD_HIDTEST=ON "-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
- name: Configure Automake
working-directory: hidapisrc
run: |
./bootstrap
./configure
- name: Build CMake Shared
working-directory: build/shared-cmake
run: make install
- name: Build CMake Static
working-directory: build/static-cmake
run: make install
- name: Build Automake
working-directory: hidapisrc
run: |
make
make DESTDIR=$PWD/../install/automake install
make clean
- name: Build manual Makefile
run: |
cd hidapisrc/linux
make -f Makefile-manual
cd ../libusb
make -f Makefile-manual
- name: Check artifacts
uses: andstor/file-existence-action@v2
with:
files: "install/shared-cmake/lib/libhidapi-libusb.so, \
install/shared-cmake/lib/libhidapi-hidraw.so, \
install/shared-cmake/include/hidapi/hidapi.h, \
install/shared-cmake/include/hidapi/hidapi_libusb.h, \
install/static-cmake/lib/libhidapi-libusb.a, \
install/static-cmake/lib/libhidapi-hidraw.a, \
install/static-cmake/include/hidapi/hidapi.h, \
install/static-cmake/include/hidapi/hidapi_libusb.h"
fail: true
- name: Check CMake Export Package Shared
run: |
cmake \
-B build/shared_test \
-S hidapisrc/hidtest \
-Dhidapi_ROOT=install/shared-cmake \
-DCMAKE_INSTALL_PREFIX=install/shared_test \
"-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
cd build/shared_test
make install
- name: Check CMake Export Package Static
run: |
cmake \
-B build/static_test \
-S hidapisrc/hidtest \
-Dhidapi_ROOT=install/static-cmake \
-DCMAKE_INSTALL_PREFIX=install/static_test \
"-DCMAKE_C_FLAGS=${NIX_COMPILE_FLAGS}"
cd build/static_test
make install
alpine:
runs-on: ubuntu-latest
container: alpine:edge
env:
# A bug in musl: https://www.openwall.com/lists/musl/2020/01/20/2
ALPINE_COMPILE_FLAGS: ${NIX_COMPILE_FLAGS} -Wno-overflow
steps:
- uses: actions/checkout@v3
with:
path: hidapisrc
- name: Install dependencies
run: |
apk add gcc musl-dev autoconf automake libtool eudev-dev libusb-dev linux-headers cmake ninja make
- name: Configure CMake
run: |
rm -rf build install
cmake -B build/shared-cmake -S hidapisrc -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=install/shared-cmake -DHIDAPI_BUILD_HIDTEST=ON "-DCMAKE_C_FLAGS=${ALPINE_COMPILE_FLAGS}"
cmake -B build/static-cmake -S hidapisrc -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=install/static-cmake -DBUILD_SHARED_LIBS=FALSE -DHIDAPI_BUILD_HIDTEST=ON "-DCMAKE_C_FLAGS=${ALPINE_COMPILE_FLAGS}"
- name: Configure Automake
working-directory: hidapisrc
run: |
./bootstrap
./configure
- name: Build CMake Shared
working-directory: build/shared-cmake
run: ninja install
- name: Build CMake Static
working-directory: build/static-cmake
run: ninja install
- name: Build Automake
working-directory: hidapisrc
run: |
make
make DESTDIR=$PWD/../install/automake install
make clean
- name: Build manual Makefile
run: |
cd hidapisrc/linux
make -f Makefile-manual
cd ../libusb
make -f Makefile-manual
- name: Check artifacts
uses: andstor/file-existence-action@v2
with:
files: "install/shared-cmake/lib/libhidapi-libusb.so, \
install/shared-cmake/lib/libhidapi-hidraw.so, \
install/shared-cmake/include/hidapi/hidapi.h, \
install/shared-cmake/include/hidapi/hidapi_libusb.h, \
install/static-cmake/lib/libhidapi-libusb.a, \
install/static-cmake/lib/libhidapi-hidraw.a, \
install/static-cmake/include/hidapi/hidapi.h, \
install/static-cmake/include/hidapi/hidapi_libusb.h"
fail: true
- name: Check CMake Export Package Shared
run: |
cmake \
-GNinja \
-B build/shared_test \
-S hidapisrc/hidtest \
-Dhidapi_ROOT=install/shared-cmake \
-DCMAKE_INSTALL_PREFIX=install/shared_test \
"-DCMAKE_C_FLAGS=${ALPINE_COMPILE_FLAGS}"
cd build/shared_test
ninja install
- name: Check CMake Export Package Static
run: |
cmake \
-GNinja \
-B build/static_test \
-S hidapisrc/hidtest \
-Dhidapi_ROOT=install/static-cmake \
-DCMAKE_INSTALL_PREFIX=install/static_test \
"-DCMAKE_C_FLAGS=${ALPINE_COMPILE_FLAGS}"
cd build/static_test
ninja install
name: Checks
run-name: Code checks for '${{ github.ref_name }}'
# General comment:
# Coverity doesn't support merging or including reports from multible machine/platforms (at least not officially).
# But otherwise there is no good way to keep the issues from all platforms at Coverity Scans at once.
# This script uses undocumented (but appears to be working) hack:
# The build logs from one machine/platform gets moved to a next once,
# and "fixed" so that cov-build can append logs from the next platform.
# The "fix" is based on the fact, that Coverity perfectly allows appending logs from multiple builds
# that are done *on the same host* machine.
on:
# On-demand run
workflow_dispatch:
# Weekly run
schedule:
- cron: '30 5 * * 0'
jobs:
coverity-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
with:
path: src
- name: Setup MSVC
uses: TheMrMilchmann/setup-msvc-dev@v2.0.0
with:
arch: x64
- name: Configure
run: |
cmake -B build -S src -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHIDAPI_WITH_TESTS=ON -DHIDAPI_BUILD_HIDTEST=ON
- name: Lookup Coverity Build Tool hash
id: coverity-cache-lookup
run: |
$coverity_hash=Invoke-RestMethod -Uri https://scan.coverity.com/download/cxx/win64 -Method Post -Body @{token='${{ secrets.COVERITY_SCAN_TOKEN }}';project='hidapi';md5=1}
echo "coverity_hash=$coverity_hash" >> $Env:GITHUB_OUTPUT
- name: Get cached Coverity Build Tool
id: cov-build-cache
uses: actions/cache@v3
with:
path: cov-root
key: cov-root-cxx-win64-${{ steps.coverity-cache-lookup.outputs.coverity_hash }}
- name: Get and configure Coverity
if: steps.cov-build-cache.outputs.cache-hit != 'true'
run: |
Invoke-WebRequest -Uri https://scan.coverity.com/download/cxx/win64 -OutFile coverity.zip -Method Post -Body @{token='${{ secrets.COVERITY_SCAN_TOKEN }}';project='hidapi'}
Remove-Item 'cov-root' -Recurse -Force -ErrorAction SilentlyContinue
Expand-Archive coverity.zip -DestinationPath cov-root
$cov_root=Get-ChildItem -Path 'cov-root'
$Env:PATH += ";$($cov_root.FullName)\bin"
cov-configure -msvc
- name: Make Coverity available in PATH
run: |
$cov_root=Get-ChildItem -Path 'cov-root'
echo "$($cov_root.FullName)\bin" >> $Env:GITHUB_PATH
- name: Build with Coverity
working-directory: build
run: |
cov-build --dir cov-int nmake
Rename-Item ".\cov-int\emit\$(hostname)" hostname
- name: Backup Coverity logs
uses: actions/upload-artifact@v3
with:
name: coverity-logs-windows
path: build/cov-int
retention-days: 7
coverity-macos:
runs-on: macos-latest
needs: [coverity-windows]
steps:
- uses: actions/checkout@v3
with:
path: src
- name: Install dependencies
run: brew install ninja
- name: Configure
run: |
cmake -B build -S src -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHIDAPI_WITH_TESTS=ON -DHIDAPI_BUILD_HIDTEST=ON -DCMAKE_C_COMPILER=clang
- uses: actions/download-artifact@v3
with:
name: coverity-logs-windows
path: build/cov-int
- name: Fixup cov-int
run: |
rm -f build/cov-int/emit/hostname/emit-db.lock build/cov-int/emit/hostname/emit-db.write-lock
mv build/cov-int/emit/hostname build/cov-int/emit/$(hostname)
- name: Lookup Coverity Build Tool hash
id: coverity-cache-lookup
shell: bash
run: |
hash=$(curl https://scan.coverity.com/download/cxx/Darwin --data "token=${{ secrets.COVERITY_SCAN_TOKEN }}&project=hidapi&md5=1")
echo "coverity_hash=${hash}" >> $GITHUB_OUTPUT
- name: Get cached Coverity Build Tool
id: cov-build-cache
uses: actions/cache@v3
with:
path: cov-root
key: cov-root-cxx-Darwin-${{ steps.coverity-cache-lookup.outputs.coverity_hash }}
- name: Get and configure Coverity
if: steps.cov-build-cache.outputs.cache-hit != 'true'
run: |
curl https://scan.coverity.com/download/cxx/Darwin --output coverity.dmg --data "token=${{ secrets.COVERITY_SCAN_TOKEN }}&project=hidapi"
hdiutil attach coverity.dmg -mountroot coverity
export COV_DIR_NAME=$(ls -1 --color=never coverity)
rm -rf cov-root
mkdir cov-root
cp ./coverity/${COV_DIR_NAME}/${COV_DIR_NAME}.sh cov-root/
cd cov-root/
./${COV_DIR_NAME}.sh
./bin/cov-configure --clang
- name: Make Coverity available in PATH
run: echo "$(pwd)/cov-root/bin" >> $GITHUB_PATH
- name: Build with Coverity
working-directory: build
run: |
cov-build --dir cov-int --append-log ninja
mv cov-int/emit/$(hostname) cov-int/emit/hostname
- name: Backup Coverity logs
uses: actions/upload-artifact@v3
with:
name: coverity-logs-windows-macos
path: build/cov-int
retention-days: 7
coverity-ubuntu:
runs-on: ubuntu-latest
needs: [coverity-macos]
steps:
- uses: actions/checkout@v3
with:
path: src
- name: Install dependencies
run: sudo apt install libudev-dev libusb-1.0-0-dev ninja-build
- name: Configure
run: |
cmake -B build -S src -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHIDAPI_WITH_TESTS=ON -DHIDAPI_BUILD_HIDTEST=ON -DCMAKE_C_COMPILER=gcc
- uses: actions/download-artifact@v3
with:
name: coverity-logs-windows-macos
path: build/cov-int
- name: Fixup cov-int
run: |
rm -f build/cov-int/emit/hostname/emit-db.lock build/cov-int/emit/hostname/emit-db.write-lock
mv build/cov-int/emit/hostname build/cov-int/emit/$(hostname)
- name: Lookup Coverity Build Tool hash
id: coverity-cache-lookup
shell: bash
run: |
hash=$(curl https://scan.coverity.com/download/cxx/linux64 --data "token=${{ secrets.COVERITY_SCAN_TOKEN }}&project=hidapi&md5=1")
echo "coverity_hash=${hash}" >> $GITHUB_OUTPUT
- name: Get cached Coverity Build Tool
id: cov-build-cache
uses: actions/cache@v3
with:
path: cov-root
key: cov-root-cxx-linux64-${{ steps.coverity-cache-lookup.outputs.coverity_hash }}
- name: Get and configure Coverity
if: steps.cov-build-cache.outputs.cache-hit != 'true'
run: |
curl https://scan.coverity.com/download/cxx/linux64 --output coverity.tar.gz --data "token=${{ secrets.COVERITY_SCAN_TOKEN }}&project=hidapi"
rm -rf cov-root
mkdir cov-root
tar -xzf coverity.tar.gz --strip 1 -C cov-root
./cov-root/bin/cov-configure --gcc
- name: Make Coverity available in PATH
run: echo "$(pwd)/cov-root/bin" >> $GITHUB_PATH
- name: Build with Coverity
working-directory: build
run: |
cov-build --dir cov-int --append-log ninja
- name: Submit results to Coverity Scan
working-directory: build
run: |
tar -czf cov-int.tar.gz cov-int
curl --form token=${{ secrets.COVERITY_SCAN_TOKEN }} \
--form email=${{ secrets.COVERITY_SCAN_EMAIL }} \
--form file=@cov-int.tar.gz \
--form version="$GITHUB_SHA" \
--form description="Automatic HIDAPI build" \
https://scan.coverity.com/builds?project=hidapi
mv cov-int/emit/$(hostname) cov-int/emit/hostname
- name: Backup Coverity logs
uses: actions/upload-artifact@v3
with:
name: coverity-logs-windows-macos-linux
path: build/cov-int
retention-days: 7
name: Docs
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Install Doxygen static libclang deps
run: sudo apt-get install libclang1-12 libclang-cpp12
- name: Install Doxygen from SF binary archives
env:
DOXYGEN_VERSION: '1.9.6'
run: |
mkdir .doxygen && cd .doxygen
curl -L https://sourceforge.net/projects/doxygen/files/rel-$DOXYGEN_VERSION/doxygen-$DOXYGEN_VERSION.linux.bin.tar.gz > doxygen.tar.gz
gunzip doxygen.tar.gz
tar xf doxygen.tar
cd doxygen-$DOXYGEN_VERSION
sudo make install
- uses: actions/checkout@v3
- run: doxygen
working-directory: doxygen
- name: Save doxygen docs as artifact
uses: actions/upload-artifact@v3
with:
name: HIDAPI_doxygen_docs
path: ${{ github.workspace }}/doxygen/html
deploy-docs:
runs-on: ubuntu-latest
needs: [build]
if: github.ref_type == 'branch' && github.ref_name == 'master'
concurrency:
group: "github-pages-deploy"
cancel-in-progress: true
steps:
- name: downlod artifact
uses: actions/download-artifact@v3
with:
name: HIDAPI_doxygen_docs
path: docs
- name: upload to github pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
force_orphan: true
# Autotools-added generated files
Makefile.in
aclocal.m4
ar-lib
autom4te.cache/
config.*
configure
configure~
compile
depcomp
install-sh
libusb/Makefile.in
linux/Makefile.in
ltmain.sh
mac/Makefile.in
missing
testgui/Makefile.in
windows/Makefile.in
Makefile
stamp-h1
libtool
# macOS
.DS_Store
# Qt Creator
CMakeLists.txt.user
# doxgen output
doxygen/html/
LOCAL_PATH:= $(call my-dir)
HIDAPI_ROOT_REL:= ../..
HIDAPI_ROOT_ABS:= $(LOCAL_PATH)/../..
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(HIDAPI_ROOT_REL)/libusb/hid.c
LOCAL_C_INCLUDES += \
$(HIDAPI_ROOT_ABS)/hidapi \
$(HIDAPI_ROOT_ABS)/android
LOCAL_SHARED_LIBRARIES := libusb1.0
LOCAL_MODULE := libhidapi
include $(BUILD_SHARED_LIBRARY)
HIDAPI Authors:
Alan Ott <alan@signal11.us>:
Original Author and Maintainer
Linux, Windows, and Mac implementations
Ludovic Rousseau <rousseau@debian.org>:
Formatting for Doxygen documentation
Bug fixes
Correctness fixes
libusb/hidapi Team:
Development/maintenance since June 4th 2019
For a comprehensive list of contributions, see the commit list at github:
https://github.com/libusb/hidapi/graphs/contributors

Sorry, the diff of this file is not supported yet

# Building HIDAPI using Autotools (deprecated)
---
**NOTE**: for all intentions and purposes the Autotools build scripts for HIDAPI are _deprecated_ and going to be obsolete in the future.
HIDAPI Team recommends using CMake build for HIDAPI.
If you are already using Autotools build scripts provided by HIDAPI,
consider switching to CMake build scripts as soon as possible.
---
To be able to use Autotools to build HIDAPI, it has to be [installed](#installing-autotools)/available in the system.
Make sure you've checked [prerequisites](BUILD.md#prerequisites) and installed all required dependencies.
## Installing Autotools
HIDAPI uses few specific tools/packages from Autotools: `autoconf`, `automake`, `libtool`.
On different platforms or package managers, those could be named a bit differently or packaged together.
You'll have to check the documentation/package list for your specific package manager.
### Linux
On Ubuntu the tools are available via APT:
```sh
sudo apt install autoconf automake libtool
```
### FreeBSD
FreeBSD Autotools can be installed as:
```sh
pkg_add -r autotools
```
Additionally, on FreeBSD you will need to install GNU make:
```sh
pkg_add -r gmake
```
## Building HIDAPI with Autotools
A simple command list, to build HIDAPI with Autotools as a _shared library_ and install in into your system:
```sh
./bootstrap # this prepares the configure script
./configure
make # build the library
make install # as root, or using sudo, this will install hidapi into your system
```
`./configure` can take several arguments which control the build. A few commonly used options:
```sh
--enable-testgui
# Enable the build of Foxit-based Test GUI. This requires Fox toolkit to
# be installed/available. See README.md#test-gui for remarks.
--prefix=/usr
# Specify where you want the output headers and libraries to
# be installed. The example above will put the headers in
# /usr/include and the binaries in /usr/lib. The default is to
# install into /usr/local which is fine on most systems.
--disable-shared
# By default, both shared and static libraries are going to be built/installed.
# This option disables shared library build, if only static library is required.
```
## Cross Compiling
This section talks about cross compiling HIDAPI for Linux using Autotools.
This is useful for using HIDAPI on embedded Linux targets. These
instructions assume the most raw kind of embedded Linux build, where all
prerequisites will need to be built first. This process will of course vary
based on your embedded Linux build system if you are using one, such as
OpenEmbedded or Buildroot.
For the purpose of this section, it will be assumed that the following
environment variables are exported.
```sh
$ export STAGING=$HOME/out
$ export HOST=arm-linux
```
`STAGING` and `HOST` can be modified to suit your setup.
### Prerequisites
Depending on what backend you want to cross-compile, you also need to prepare the dependencies:
`libusb` for libusb HIDAPI backend, or `libudev` for hidraw HIDAPI backend.
An example of cross-compiling `libusb`. From `libusb` source directory, run:
```sh
./configure --host=$HOST --prefix=$STAGING
make
make install
```
An example of cross-comping `libudev` is not covered by this section.
Check `libudev`'s documentation for details.
### Building HIDAPI
Build HIDAPI:
```sh
PKG_CONFIG_DIR= \
PKG_CONFIG_LIBDIR=$STAGING/lib/pkgconfig:$STAGING/share/pkgconfig \
PKG_CONFIG_SYSROOT_DIR=$STAGING \
./configure --host=$HOST --prefix=$STAGING
# make / make install - same as for a regular build
```
# Building HIDAPI using CMake
To build HIDAPI with CMake, it has to be [installed](#installing-cmake)/available in the system.
Make sure you've checked [prerequisites](BUILD.md#prerequisites) and installed all required dependencies.
HIDAPI CMake build system allows you to build HIDAPI in two generally different ways:
1) As a [standalone package/library](#standalone-package-build);
2) As [part of a larger CMake project](#hidapi-as-a-subdirectory).
**TL;DR**: if you're experienced developer and have been working with CMake projects or have been written some of your own -
most of this document may not be of interest for you; just check variables names, its default values and the target names.
## Installing CMake
CMake can be installed either using your system's package manager,
or by downloading an installer/prebuilt version from the [official website](https://cmake.org/download/).
On most \*nix systems, the preferred way to install CMake is via package manager,
e.g. `sudo apt install cmake`.
On Windows CMake could be provided by your development environment (e.g. by Visual Studio Installer or MinGW installer),
or you may install it system-wise using the installer from the official website.
On macOS CMake may be installed by Homebrew/MacPorts or using the installer from the official website.
## Standalone package build
To build HIDAPI as a standalone package, you follow [general steps](https://cmake.org/runningcmake/) of building any CMake project.
An example of building HIDAPI with CMake:
```sh
# precondition: create a <build dir> somewhere on the filesystem (preferably outside of the HIDAPI source)
# this is the place where all intermediate/build files are going to be located
cd <build dir>
# configure the build
cmake <HIDAPI source dir>
# build it!
cmake --build .
# install library; by default installs into /usr/local/
cmake --build . --target install
# NOTE: you need to run install command as root, to be able to install into /usr/local/
```
Such invocation will use the default (as per CMake magic) compiler/build environment available in your system.
You may pass some additional CMake variables to control the build configuration as `-D<CMake Variable>=value`.
E.g.:
```sh
# install command now would install things into /usr
cmake <HIDAPI source dir> -DCMAKE_INSTALL_PREFIX=/usr
```
<details>
<summary>Using a specific CMake generator</summary>
An example of using `Ninja` as a CMake generator:
```sh
cd <build dir>
# configure the build
cmake -GNinja <HIDAPI source dir>
# we know, that CMake has generated build files for Ninja,
# so we can use `ninja` directly, instead of `cmake --build .`
ninja
# install library
ninja install
```
`-G` here specifies a native build system CMake would generate build files for.
Check [CMake Documentation](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html) for a list of available generators (system-specific).
</details><br>
Some of the [standard](https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html) CMake variables you may want to use to configure a build:
- [`CMAKE_INSTALL_PREFIX`](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html) - prefix where `install` target would install the library(ies);
- [`CMAKE_BUILD_TYPE`](https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html) - standard possible values: `Debug`, `Release`, `RelWithDebInfo`, `MinSizeRel`; Defaults to `Release` for HIDAPI, if not specified;
- [`BUILD_SHARED_LIBS`](https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html) - when set to TRUE, HIDAPI is built as a shared library, otherwise build statically; Defaults to `TRUE` for HIDAPI, if not specified;
<details>
<summary>macOS-specific variables</summary>
- [`CMAKE_FRAMEWORK`](https://cmake.org/cmake/help/latest/variable/CMAKE_FRAMEWORK.html) - (since CMake 3.15) when set to TRUE, HIDAPI is built as a framework library, otherwise build as a regular static/shared library; Defaults to `FALSE` for HIDAPI, if not specified;
- [`CMAKE_OSX_DEPLOYMENT_TARGET`](https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_DEPLOYMENT_TARGET.html) - minimum version of the target platform (e.g. macOS or iOS) on which the target binaries are to be deployed; defaults to a maximum supported target platform by currently used XCode/Toolchain;
</details><br>
HIDAPI-specific CMake variables:
- `HIDAPI_BUILD_HIDTEST` - when set to TRUE, build a small test application `hidtest`;
- `HIDAPI_WITH_TESTS` - when set to TRUE, build all (unit-)tests;
currently this option is only available on Windows, since only Windows backend has tests;
<details>
<summary>Linux-specific variables</summary>
- `HIDAPI_WITH_HIDRAW` - when set to TRUE, build HIDRAW-based implementation of HIDAPI (`hidapi-hidraw`), otherwise don't build it; defaults to TRUE;
- `HIDAPI_WITH_LIBUSB` - when set to TRUE, build LIBUSB-based implementation of HIDAPI (`hidapi-libusb`), otherwise don't build it; defaults to TRUE;
**NOTE**: at least one of `HIDAPI_WITH_HIDRAW` or `HIDAPI_WITH_LIBUSB` has to be set to TRUE.
</details><br>
To see all most-useful CMake variables available for HIDAPI, one of the most convenient ways is too use [`cmake-gui`](https://cmake.org/cmake/help/latest/manual/cmake-gui.1.html) tool ([example](https://cmake.org/runningcmake/)).
_NOTE_: HIDAPI packages built by CMake can be used with `pkg-config`, as if built with [Autotools](BUILD.autotools.md).
### MSVC and Ninja
It is possible to build a CMake project (including HIDAPI) using MSVC compiler and Ninja (for medium and larger projects it is so much faster than msbuild).
For that:
1) Open cmd.exe;
2) Setup MSVC build environment variables, e.g.: `vcvarsall.bat x64`, where:
- `vcvarsall.bat` is an environment setup script of your MSVC toolchain installation;<br>For MSVC 2019 Community edition it is located at: `C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\`;
- `x64` -a target architecture to build;
3) Follow general build steps, and use `Ninja` as a generator.
### Using HIDAPI in a CMake project
When HIDAPI is used as a standalone package (either installed into the system or built manually and installed elsewhere), the simplest way to use it is as showed in the example:
```cmake
project(my_application)
add_executable(my_application main.c)
find_package(hidapi REQUIRED)
target_link_libraries(my_application PRIVATE hidapi::hidapi)
```
If HIDAPI isn't installed in your system, or `find_package` cannot find HIDAPI by default for any other reasons,
the recommended way manually specify which HIDAPI package to use is via `hidapi_ROOT` CMake variable, e.g.:
`-Dhidapi_ROOT=<path to HIDAPI installation prefix>`.
_NOTE_: usage of `hidapi_ROOT` is only possible (and recommended) with CMake 3.12 and higher. For older versions of CMake you'd need to specify [`CMAKE_PREFIX_PATH`](https://cmake.org/cmake/help/latest/variable/CMAKE_PREFIX_PATH.html#variable:CMAKE_PREFIX_PATH) instead.
Check with [`find_package`](https://cmake.org/cmake/help/latest/command/find_package.html) documentation if you need more details.
Available CMake targets after successful `find_package(hidapi)`:
- `hidapi::hidapi` - indented to be used in most cases;
- `hidapi::include` - if you need only to include `<hidapi.h>` but not link against the library;
- `hidapi::winapi` - same as `hidapi::hidapi` on Windows; available only on Windows;
- `hidapi::darwin` - same as `hidapi::hidapi` on macOS; available only on macOS;
- `hidapi::libusb` - available when libusb backend is used/available;
- `hidapi::hidraw` - available when hidraw backend is used/available on Linux;
**NOTE**: on Linux often both `hidapi::libusb` and `hidapi::hidraw` backends are available; in that case `hidapi::hidapi` is an alias for **`hidapi::hidraw`**. The motivation is that `hidraw` backend is a native Linux kernel implementation of HID protocol, and supports various HID devices (USB, Bluetooth, I2C, etc.). If `hidraw` backend isn't built at all (`hidapi::libusb` is the only target) - `hidapi::hidapi` is an alias for `hidapi::libusb`.
If you're developing a cross-platform application and you are sure you need to use `libusb` backend on Linux, the simple way to achieve this is:
```cmake
if(TARGET hidapi::libusb)
target_link_libraries(my_project PRIVATE hidapi::libusb)
else()
target_link_libraries(my_project PRIVATE hidapi::hidapi)
endif()
```
## HIDAPI as a subdirectory
HIDAPI can be easily used as a subdirectory of a larger CMake project:
```cmake
# root CMakeLists.txt
cmake_minimum_required(VERSION 3.4.3 FATAL_ERROR)
add_subdirectory(hidapi)
add_subdirectory(my_application)
# my_application/CMakeLists.txt
project(my_application)
add_executable(my_application main.c)
# NOTE: no `find_package` is required, since HIDAPI targets are already a part of the project tree
target_link_libraries(my_application PRIVATE hidapi::hidapi)
```
Lets call this "larger project" a "host project".
All of the variables described in [standalone build](#standalone-package-build) section can be used to control HIDAPI build in case of a subdirectory, e.g.:
```cmake
set(HIDAPI_WITH_LIBUSB FALSE) # surely will be used only on Linux
set(BUILD_SHARED_LIBS FALSE) # HIDAPI as static library on all platforms
add_subdirectory(hidapi)
```
<details>
<summary>NOTE</summary>
If you project happen to use `BUILD_SHARED_LIBS` as a `CACHE` variable globally for you project, setting it as simple variable, as showed above _will have not affect_ up until _CMake 3.13_. See [CMP0077](https://cmake.org/cmake/help/latest/policy/CMP0077.html) for details.
</details><br>
There are several important differences in the behavior of HIDAPI CMake build system when CMake is built as standalone package vs subdirectory build:
1) In _standalone build_ a number of standard and HIDAPI-specific variables are marked as _cache variables_ or _options_.
This is done for convenience: when you're building HIDAPI as a standalone package and using tools like `cmake-gui` - those are highlighted as variables that can be changed and has some short description/documentation. E.g.:
![an example of highlighted variables in cmake-gui](documentation/cmake-gui-highlights.png "cmake-gui highlighted variables")<br>
E.g.2:<br>
![an example of drop-down menu in cmake-gui](documentation/cmake-gui-drop-down.png "cmake-gui drop-down menu")<br>
When HIDAPI is built as a _subdirectory_ - **_none of the variables are marked for cache or as options_** by HIDAPI.
This is done to let the host project's developer decide what is important (what needs to be highlighted) and what's not.
2) The default behavior/default value for some of the variables is a bit different:
- by default, none of HIDAPI targets are [installed](https://cmake.org/cmake/help/latest/command/install.html); if required, HIDAPI targets can be installed by host project _after_ including HIDAPI subdirectory (requires CMake 3.13 or later); **or**, the default installation can be enabled by setting `HIDAPI_INSTALL_TARGETS` variable _before_ including HIDAPI subdirectory.
HIDAPI uses [GNUInstallDirs](https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html) to specify install locations. Variables like `CMAKE_INSTALL_LIBDIR` can be used to control HIDAPI's installation locations. E.g.:
```cmake
# enable the installation if you need it
set(HIDAPI_INSTALL_TARGETS ON)
# (optionally) change default installation locations if it makes sense for your target platform, etc.
set(CMAKE_INSTALL_LIBDIR "lib64")
add_subdirectory(hidapi)
```
- HIDAPI prints its version during the configuration when built as a standalone package; to enable this for subdirectory builds - set `HIDAPI_PRINT_VERSION` to TRUE before including HIDAPI;
3) In a subdirectory build, HIDAPI _doesn't modify or set any of the CMake variables_ that may change the build behavior.
For instance, in a _standalone build_, if CMAKE_BUILD_TYPE or BUILD_SHARED_LIBS variables are not set, those are defaulted to "Release" and "TRUE" explicitly.
In a _subdirectory build_, even if not set, those variables remain unchanged, so a host project's developer has a full control over the HIDAPI build configuration.
Available CMake targets after `add_subdirectory(hidapi)` _are the same as in case of [standalone build](#standalone-package-build)_, and a few additional ones:
- `hidapi_include` - the interface library; `hidapi::hidapi` is an alias of it;
- `hidapi_winapi` - library target on Windows; `hidapi::winapi` is an alias of it;
- `hidapi_darwin` - library target on macOS; `hidapi::darwin` is an alias of it;
- `hidapi_libusb` - library target for libusb backend; `hidapi::libusb` is an alias of it;
- `hidapi_hidraw` - library target for hidraw backend; `hidapi::hidraw` is an alias of it;
- `hidapi-libusb` - an alias of `hidapi_libusb` for compatibility with raw library name;
- `hidapi-hidraw` - an alias of `hidapi_hidraw` for compatibility with raw library name;
- `hidapi` - an alias of `hidapi_winapi` or `hidapi_darwin` on Windows or macOS respectfully.
Advanced:
- Why would I need additional targets described in this section above, if I already have alias targets compatible with `find_package`?
- an example:
```cmake
add_subdirectory(hidapi)
if(TARGET hidapi_libusb)
# see libusb/hid.c for usage of `NO_ICONV`
target_compile_definitions(hidapi_libusb PRIVATE NO_ICONV)
endif()
```
## Both Shared and Static build
If you're a former (or present) user of Autotools build scripts for HIDAPI, or you're a package manager maintainer and you're often working with those - you're likely asking how to build HIDAPI with CMake and get both Shared and Static libraries (as would be done by Autotools: `./configure --enable-static --enable-shared ...`).
CMake doesn't have such option of-the-box and it is decided not to introduce any manual CMake-level workarounds for HIDAPI on this matter.
If you want to mimic the Autotools behavior, it is possible by building/installing first the static version of the library and then shared version of the library. The installation folder (`CMAKE_INSTALL_PREFIX`) should point to the same directory for both variants, that way:
- both static and shared library binaries will be available and usable;
- a single header file(s) for both of them;
- Autotools/pkg-config (`.pc`) files will be generated and usable _as if_ generated by Autotools natively and build configured with both `-enable-static --enable-shared` options;
- CMake package scripts will be generated and fully usable, but _only the last build installed_, i.e. if the last was installed Shared version of the binary - CMake targets found by `find_package(hidapi)` would point to a Shared binaries.
There is a historical discussion, why such solution is simplest/preferable: https://github.com/libusb/hidapi/issues/424
#### TL;DR/Sample
```sh
# First - configure/build
# Static libraries
cmake -S <HIDAPI source dir> -B "<build dir>/static" -DCMAKE_INSTALL_PREFIX=<your installation prefix> -DBUILD_SHARED_LIBS=FALSE
cmake --build "<build dir>/static"
# Shared libraries
cmake -S <HIDAPI source dir> -B "<build dir>/shared" -DCMAKE_INSTALL_PREFIX=<your installation prefix> -DBUILD_SHARED_LIBS=TRUE
cmake --build "<build dir>/shared"
# (Optionally) change the installation destination.
# NOTE1: this is supported by CMake only on UNIX platforms
# See https://cmake.org/cmake/help/latest/envvar/DESTDIR.html
# NOTE2: this is not the same as `CMAKE_INSTALL_PREFIX` set above
# NOTE3: this is only required if you have a staging dir other than the final runtime dir,
# e.g. during cross-compilation
export DESTDIR="$STAGING_DIR"
#
# Install the libraries
# NOTE: order of installation matters - install Shared variant *the last*
# Static libraries
cmake --install "<build dir>/static"
# Shared libraries
cmake --install "<build dir>/shared"
```
# Building HIDAPI from Source
## Table of content
* [Intro](#intro)
* [Prerequisites](#prerequisites)
* [Linux](#linux)
* [FreeBSD](#freebsd)
* [Mac](#mac)
* [Windows](#windows)
* [Embedding HIDAPI directly into your source tree](#embedding-hidapi-directly-into-your-source-tree)
* [Building the manual way on Unix platforms](#building-the-manual-way-on-unix-platforms)
* [Building on Windows](#building-on-windows)
## Intro
For various reasons, you may need to build HIDAPI on your own.
It can be done in several different ways:
- using [CMake](BUILD.cmake.md);
- using [Autotools](BUILD.autotools.md) (deprecated);
- using [manual makefiles](#building-the-manual-way-on-unix-platforms);
- using `Meson` (requires CMake);
**Autotools** build system is historically the first mature build system for
HIDAPI. The most common usage of it is in its separate README: [BUILD.autotools.md](BUILD.autotools.md).<br/>
NOTE: for all intentions and purposes the Autotools build scripts for HIDAPI are _deprecated_ and going to be obsolete in the future.
HIDAPI Team recommends using CMake build for HIDAPI.
**CMake** build system is de facto an industry standard for many open-source and proprietary projects and solutions.
HIDAPI is one of the projects which use the power of CMake to its advantage.
More documentation is available in its separate README: [BUILD.cmake.md](BUILD.cmake.md).
**Meson** build system for HIDAPI is designed as a [wrapper](https://mesonbuild.com/CMake-module.html) over CMake build script.
It is present for the convenience of Meson users who need to use HIDAPI and need to be sure HIDAPI is built in accordance with officially supported build scripts.<br>
In the Meson script of your project you need a `hidapi = subproject('hidapi')` subproject, and `hidapi.get_variable('hidapi_dep')` as your dependency.
There are also backend/platform-specific dependencies available: `hidapi_winapi`, `hidapi_darwin`, `hidapi_hidraw`, `hidapi_libusb`.
If you don't know where to start to build HIDAPI, we recommend starting with [CMake](BUILD.cmake.md) build.
## Prerequisites:
Regardless of what build system you choose to use, there are specific dependencies for each platform/backend.
### Linux:
Depending on which backend you're going to build, you'll need to install
additional development packages. For `linux/hidraw` backend, you need a
development package for `libudev`. For `libusb` backend, naturally, you need
`libusb` development package.
On Debian/Ubuntu systems these can be installed by running:
```sh
# required only by hidraw backend
sudo apt install libudev-dev
# required only by libusb backend
sudo apt install libusb-1.0-0-dev
```
### FreeBSD:
On FreeBSD, you will need to install libiconv. This is done by running
the following:
```sh
pkg_add -r libiconv
```
### Mac:
Make sure you have XCode installed and its Command Line Tools.
### Windows:
You just need a compiler. You may use Visual Studio or Cygwin/MinGW,
depending on which environment is best for your needs.
## Embedding HIDAPI directly into your source tree
Instead of using one of the provided standalone build systems,
you may want to integrate HIDAPI directly into your source tree.
---
If your project uses CMake as a build system, it is safe to add HIDAPI as a [subdirectory](BUILD.cmake.md#hidapi-as-a-subdirectory).
---
If _the only option_ that works for you is adding HIDAPI sources directly
to your project's build system, then you need:
- include a _single source file_ into your project's build system,
depending on your platform and the backend you want to use:
- [`windows\hid.c`](windows/hid.c);
- [`linux/hid.c`](linux/hid.c);
- [`libusb/hid.c`](libusb/hid.c);
- [`mac/hid.c`](mac/hid.c);
- add a [`hidapi`](hidapi) folder to the include path when building `hid.c`;
- make the platform/backend specific [dependencies](#prerequisites) available during the compilation/linking, when building `hid.c`;
NOTE: the above doesn't guarantee that having a copy of `<backend>/hid.c` and `hidapi/hidapi.h` is enough to build HIDAPI.
The only guarantee that `<backend>/hid.c` includes all necessary sources to compile it as a single file.
Check the manual makefiles for a simple example/reference of what are the dependencies of each specific backend.
## Building the manual way on Unix platforms
Manual Makefiles are provided mostly to give the user an idea what it takes
to build a program which embeds HIDAPI directly inside of it. These should
really be used as examples only. If you want to build a system-wide shared
library, use one of the build systems mentioned above.
To build HIDAPI using the manual Makefiles, change the directory
of your platform and run make. For example, on Linux run:
```sh
cd linux/
make -f Makefile-manual
```
## Building on Windows
To build the HIDAPI DLL on Windows using Visual Studio, build the `.sln` file
in the `windows/` directory.
To build HIDAPI using MinGW or Cygwin using Autotools, use general Autotools
[instruction](BUILD.autotools.md).
Any windows builds (MSVC or MinGW/Cygwin) are also supported by [CMake](BUILD.cmake.md).
If you are looking for information regarding DDK build of HIDAPI:
- the build has been broken for a while and now the support files are obsolete.

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

# HIDAPI Doxygen output
This site is dedicated to hosting an [API reference for the HIDAPI library](#API).
For general information, see the [source repository](https://github.com/libusb/hidapi#readme).
There are also build instructions hosted on github:
- [Building from source](https://github.com/libusb/hidapi/blob/master/BUILD.md)
- [Using CMake](https://github.com/libusb/hidapi/blob/master/BUILD.cmake.md)
- [Using Autotools (deprecated)](https://github.com/libusb/hidapi/blob/master/BUILD.autotools.md)
\example test.c contains a basic example usage of the HIDAPI library.
This file is mostly for the maintainer.
Updating a Version:
1. Update VERSION file.
2. HID_API_VERSION_MAJOR/HID_API_VERSION_MINOR/HID_API_VERSION_PATCH in hidapi.h.
Before firing a new release:
1. Run the "Checks" Githtub Action
2. Make sure no defects are found at: https://scan.coverity.com/projects/hidapi
3. Fix if any
Firing a new release:
1. Update the Version (if not yet updated).
2. Prepare the Release Notes.
3. Store the Release Notes into a file.
4. Create locally an annotated git tag with release notes attached, e.g.: `git tag -aF ../hidapi_release_notes hidapi-<VERSION>`
5. Push newly created tag: `git push origin hidapi-<VERSION>`
6. Grab the hidapi-win.zip from Summary page of "GitHub Builds" Action for latest master build.
7. Create a Github Release with hidapi-win.zip attached, for newly created tag.
Debug
Release
*.exp
*.ilk
*.lib
*.suo
*.vcproj.*
*.ncb
*.suo
*.dll
*.pdb
*.o
.deps/
.libs/
hidtest-hidraw
hidtest-libusb
hidtest
cmake_minimum_required(VERSION 3.1.3 FATAL_ERROR)
project(hidtest C)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
# hidtest is build as a standalone project
if(POLICY CMP0074)
# allow using hidapi_ROOT if CMake supports it
cmake_policy(SET CMP0074 NEW)
endif()
find_package(hidapi 0.12 REQUIRED)
message(STATUS "Using HIDAPI: ${hidapi_VERSION}")
else()
# hidtest is built as part of the main HIDAPI build
message(STATUS "Building hidtest")
endif()
set(HIDAPI_HIDTEST_TARGETS)
if(NOT WIN32 AND NOT APPLE AND CMAKE_SYSTEM_NAME MATCHES "Linux")
if(TARGET hidapi::hidraw)
add_executable(hidtest_hidraw test.c)
target_link_libraries(hidtest_hidraw hidapi::hidraw)
list(APPEND HIDAPI_HIDTEST_TARGETS hidtest_hidraw)
endif()
if(TARGET hidapi::libusb)
add_executable(hidtest_libusb test.c)
target_compile_definitions(hidtest_libusb PRIVATE USING_HIDAPI_LIBUSB)
target_link_libraries(hidtest_libusb hidapi::libusb)
list(APPEND HIDAPI_HIDTEST_TARGETS hidtest_libusb)
endif()
else()
add_executable(hidtest test.c)
target_link_libraries(hidtest hidapi::hidapi)
list(APPEND HIDAPI_HIDTEST_TARGETS hidtest)
endif()
install(TARGETS ${HIDAPI_HIDTEST_TARGETS}
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
)

Sorry, the diff of this file is not supported yet

/*******************************************************
HIDAPI - Multi-Platform library for
communication with HID devices.
Alan Ott
Signal 11 Software
libusb/hidapi Team
Copyright 2022.
This contents of this file may be used by anyone
for any reason without any conditions and may be
used as a starting point for your own applications
which use HIDAPI.
********************************************************/
#include <stdio.h>
#include <wchar.h>
#include <string.h>
#include <stdlib.h>
#include <hidapi.h>
// Headers needed for sleeping.
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
// Fallback/example
#ifndef HID_API_MAKE_VERSION
#define HID_API_MAKE_VERSION(mj, mn, p) (((mj) << 24) | ((mn) << 8) | (p))
#endif
#ifndef HID_API_VERSION
#define HID_API_VERSION HID_API_MAKE_VERSION(HID_API_VERSION_MAJOR, HID_API_VERSION_MINOR, HID_API_VERSION_PATCH)
#endif
//
// Sample using platform-specific headers
#if defined(__APPLE__) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
#include <hidapi_darwin.h>
#endif
#if defined(_WIN32) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
#include <hidapi_winapi.h>
#endif
#if defined(USING_HIDAPI_LIBUSB) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
#include <hidapi_libusb.h>
#endif
//
const char *hid_bus_name(hid_bus_type bus_type) {
static const char *const HidBusTypeName[] = {
"Unknown",
"USB",
"Bluetooth",
"I2C",
"SPI",
};
if ((int)bus_type < 0)
bus_type = HID_API_BUS_UNKNOWN;
if ((int)bus_type >= (int)(sizeof(HidBusTypeName) / sizeof(HidBusTypeName[0])))
bus_type = HID_API_BUS_UNKNOWN;
return HidBusTypeName[bus_type];
}
void print_device(struct hid_device_info *cur_dev) {
printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
printf("\n");
printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string);
printf(" Product: %ls\n", cur_dev->product_string);
printf(" Release: %hx\n", cur_dev->release_number);
printf(" Interface: %d\n", cur_dev->interface_number);
printf(" Usage (page): 0x%hx (0x%hx)\n", cur_dev->usage, cur_dev->usage_page);
printf(" Bus type: %d (%s)\n", cur_dev->bus_type, hid_bus_name(cur_dev->bus_type));
printf("\n");
}
void print_hid_report_descriptor_from_device(hid_device *device) {
unsigned char descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE];
int res = 0;
printf(" Report Descriptor: ");
res = hid_get_report_descriptor(device, descriptor, sizeof(descriptor));
if (res < 0) {
printf("error getting: %ls", hid_error(device));
}
else {
printf("(%d bytes)", res);
}
for (int i = 0; i < res; i++) {
if (i % 10 == 0) {
printf("\n");
}
printf("0x%02x, ", descriptor[i]);
}
printf("\n");
}
void print_hid_report_descriptor_from_path(const char *path) {
hid_device *device = hid_open_path(path);
if (device) {
print_hid_report_descriptor_from_device(device);
hid_close(device);
}
else {
printf(" Report Descriptor: Unable to open device by path\n");
}
}
void print_devices(struct hid_device_info *cur_dev) {
for (; cur_dev; cur_dev = cur_dev->next) {
print_device(cur_dev);
}
}
void print_devices_with_descriptor(struct hid_device_info *cur_dev) {
for (; cur_dev; cur_dev = cur_dev->next) {
print_device(cur_dev);
print_hid_report_descriptor_from_path(cur_dev->path);
}
}
int main(int argc, char* argv[])
{
(void)argc;
(void)argv;
int res;
unsigned char buf[256];
#define MAX_STR 255
wchar_t wstr[MAX_STR];
hid_device *handle;
int i;
struct hid_device_info *devs;
printf("hidapi test/example tool. Compiled with hidapi version %s, runtime version %s.\n", HID_API_VERSION_STR, hid_version_str());
if (HID_API_VERSION == HID_API_MAKE_VERSION(hid_version()->major, hid_version()->minor, hid_version()->patch)) {
printf("Compile-time version matches runtime version of hidapi.\n\n");
}
else {
printf("Compile-time version is different than runtime version of hidapi.\n]n");
}
if (hid_init())
return -1;
#if defined(__APPLE__) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
// To work properly needs to be called before hid_open/hid_open_path after hid_init.
// Best/recommended option - call it right after hid_init.
hid_darwin_set_open_exclusive(0);
#endif
devs = hid_enumerate(0x0, 0x0);
print_devices_with_descriptor(devs);
hid_free_enumeration(devs);
// Set up the command buffer.
memset(buf,0x00,sizeof(buf));
buf[0] = 0x01;
buf[1] = 0x81;
// Open the device using the VID, PID,
// and optionally the Serial number.
////handle = hid_open(0x4d8, 0x3f, L"12345");
handle = hid_open(0x4d8, 0x3f, NULL);
if (!handle) {
printf("unable to open device\n");
hid_exit();
return 1;
}
// Read the Manufacturer String
wstr[0] = 0x0000;
res = hid_get_manufacturer_string(handle, wstr, MAX_STR);
if (res < 0)
printf("Unable to read manufacturer string\n");
printf("Manufacturer String: %ls\n", wstr);
// Read the Product String
wstr[0] = 0x0000;
res = hid_get_product_string(handle, wstr, MAX_STR);
if (res < 0)
printf("Unable to read product string\n");
printf("Product String: %ls\n", wstr);
// Read the Serial Number String
wstr[0] = 0x0000;
res = hid_get_serial_number_string(handle, wstr, MAX_STR);
if (res < 0)
printf("Unable to read serial number string\n");
printf("Serial Number String: (%d) %ls\n", wstr[0], wstr);
print_hid_report_descriptor_from_device(handle);
struct hid_device_info* info = hid_get_device_info(handle);
if (info == NULL) {
printf("Unable to get device info\n");
} else {
print_devices(info);
}
// Read Indexed String 1
wstr[0] = 0x0000;
res = hid_get_indexed_string(handle, 1, wstr, MAX_STR);
if (res < 0)
printf("Unable to read indexed string 1\n");
printf("Indexed String 1: %ls\n", wstr);
// Set the hid_read() function to be non-blocking.
hid_set_nonblocking(handle, 1);
// Try to read from the device. There should be no
// data here, but execution should not block.
res = hid_read(handle, buf, 17);
// Send a Feature Report to the device
buf[0] = 0x2;
buf[1] = 0xa0;
buf[2] = 0x0a;
buf[3] = 0x00;
buf[4] = 0x00;
res = hid_send_feature_report(handle, buf, 17);
if (res < 0) {
printf("Unable to send a feature report.\n");
}
memset(buf,0,sizeof(buf));
// Read a Feature Report from the device
buf[0] = 0x2;
res = hid_get_feature_report(handle, buf, sizeof(buf));
if (res < 0) {
printf("Unable to get a feature report: %ls\n", hid_error(handle));
}
else {
// Print out the returned buffer.
printf("Feature Report\n ");
for (i = 0; i < res; i++)
printf("%02x ", (unsigned int) buf[i]);
printf("\n");
}
memset(buf,0,sizeof(buf));
// Toggle LED (cmd 0x80). The first byte is the report number (0x1).
buf[0] = 0x1;
buf[1] = 0x80;
res = hid_write(handle, buf, 17);
if (res < 0) {
printf("Unable to write(): %ls\n", hid_error(handle));
}
// Request state (cmd 0x81). The first byte is the report number (0x1).
buf[0] = 0x1;
buf[1] = 0x81;
hid_write(handle, buf, 17);
if (res < 0) {
printf("Unable to write()/2: %ls\n", hid_error(handle));
}
// Read requested state. hid_read() has been set to be
// non-blocking by the call to hid_set_nonblocking() above.
// This loop demonstrates the non-blocking nature of hid_read().
res = 0;
i = 0;
while (res == 0) {
res = hid_read(handle, buf, sizeof(buf));
if (res == 0) {
printf("waiting...\n");
}
if (res < 0) {
printf("Unable to read(): %ls\n", hid_error(handle));
break;
}
i++;
if (i >= 10) { /* 10 tries by 500 ms - 5 seconds of waiting*/
printf("read() timeout\n");
break;
}
#ifdef _WIN32
Sleep(500);
#else
usleep(500*1000);
#endif
}
if (res > 0) {
printf("Data read:\n ");
// Print out the returned buffer.
for (i = 0; i < res; i++)
printf("%02x ", (unsigned int) buf[i]);
printf("\n");
}
hid_close(handle);
/* Free static HIDAPI objects. */
hid_exit();
#ifdef _WIN32
system("pause");
#endif
return 0;
}
Debug
Release
*.exp
*.ilk
*.lib
*.suo
*.vcproj.*
*.ncb
*.suo
*.dll
*.pdb
*.o
*.so
hidtest-hidraw
.deps
.libs
*.lo
*.la

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

# Ignore All, except pkg.m4, and of course this file.
*
!.gitignore
!pkg.m4
!ax_pthread.m4

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Debug
Release
*.exp
*.ilk
*.lib
*.suo
*.vcproj.*
*.ncb
*.suo
*.dll
*.pdb
*.o
hidapi-hidtest
.deps
.libs
*.la
*.lo

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: hidapi-hidraw
Description: C Library for USB/Bluetooth HID device access from Linux, Mac OS X, FreeBSD, and Windows. This is the hidraw implementation.
URL: https://github.com/libusb/hidapi
Version: @VERSION@
Libs: -L${libdir} -lhidapi-hidraw
Cflags: -I${includedir}/hidapi
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: hidapi-libusb
Description: C Library for USB HID device access from Linux, Mac OS X, FreeBSD, and Windows. This is the libusb implementation.
URL: https://github.com/libusb/hidapi
Version: @VERSION@
Libs: -L${libdir} -lhidapi-libusb
Cflags: -I${includedir}/hidapi
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: hidapi
Description: C Library for USB/Bluetooth HID device access from Linux, Mac OS X, FreeBSD, and Windows.
URL: https://github.com/libusb/hidapi
Version: @VERSION@
Libs: -L${libdir} -lhidapi
Cflags: -I${includedir}/hidapi
cmake_minimum_required(VERSION 3.1.3 FATAL_ERROR)
project(hidapi LANGUAGES C)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/root")
foreach(ROOT_ELEMENT CMakeLists.txt hidapi src windows linux mac libusb pc VERSION)
file(COPY "${CMAKE_CURRENT_LIST_DIR}/../../${ROOT_ELEMENT}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/root/")
endforeach()
add_subdirectory("${CMAKE_CURRENT_BINARY_DIR}/root" hidapi_root)
Debug
Release
*.exp
*.ilk
*.lib
*.suo
*.vcproj.*
*.ncb
*.suo
*.dll
*.pdb
*.o
hidapi-testgui
hidapi-hidraw-testgui
hidapi-libusb-testgui
.deps
.libs
*.la
*.lo
TestGUI.app
#!/bin/bash
#### Configuration:
# The name of the executable. It is assumed
# that it is in the current working directory.
EXE_NAME=hidapi-testgui
# Path to the executable directory inside the bundle.
# This must be an absolute path, so use $PWD.
EXEPATH=$PWD/TestGUI.app/Contents/MacOS
# Libraries to explicitly bundle, even though they
# may not be in /opt/local. One per line. These
# are used with grep, so only a portion of the name
# is required. eg: libFOX, libz, etc.
LIBS_TO_BUNDLE=libFOX
function copydeps {
local file=$1
# echo "Copying deps for $file...."
local BASE_OF_EXE=`basename $file`
# A will contain the dependencies of this library
local A=`otool -LX $file |cut -f 1 -d " "`
local i
for i in $A; do
local BASE=`basename $i`
# See if it's a lib we specifically want to bundle
local bundle_this_lib=0
local j
for j in $LIBS_TO_BUNDLE; do
echo $i |grep -q $j
if [ $? -eq 0 ]; then
bundle_this_lib=1
echo "bundling $i because it's in the list."
break;
fi
done
# See if it's in /opt/local. Bundle all in /opt/local
local isOptLocal=0
echo $i |grep -q /opt/local
if [ $? -eq 0 ]; then
isOptLocal=1
echo "bundling $i because it's in /opt/local."
fi
# Bundle the library
if [ $isOptLocal -ne 0 ] || [ $bundle_this_lib -ne 0 ]; then
# Copy the file into the bundle if it exists.
if [ -f $EXEPATH/$BASE ]; then
z=0
else
cp $i $EXEPATH
chmod 755 $EXEPATH/$BASE
fi
# echo "$BASE_OF_EXE depends on $BASE"
# Fix the paths using install_name_tool and then
# call this function recursively for each dependency
# of this library.
if [ $BASE_OF_EXE != $BASE ]; then
# Fix the paths
install_name_tool -id @executable_path/$BASE $EXEPATH/$BASE
install_name_tool -change $i @executable_path/$BASE $EXEPATH/$BASE_OF_EXE
# Call this function (recursive) on
# on each dependency of this library.
copydeps $EXEPATH/$BASE
fi
fi
done
}
rm -f $EXEPATH/*
mkdir -p $EXEPATH
# Copy the binary into the bundle. Use ../libtool to do this if it's
# available because if $EXE_NAME was built with autotools, it will be
# necessary. If ../libtool not available, just use cp to do the copy, but
# only if $EXE_NAME is a binary.
if [ -x ../libtool ]; then
../libtool --mode=install cp $EXE_NAME $EXEPATH
else
file -bI $EXE_NAME |grep binary
if [ $? -ne 0 ]; then
echo "There is no ../libtool and $EXE_NAME is not a binary."
echo "I'm not sure what to do."
exit 1
else
cp $EXE_NAME $EXEPATH
fi
fi
copydeps $EXEPATH/$EXE_NAME
/*******************************
Mac support for HID Test GUI
Alan Ott
Signal 11 Software
*******************************/
#include <fx.h>
#import <Cocoa/Cocoa.h>
#ifndef MAC_OS_X_VERSION_10_12
#define MAC_OS_X_VERSION_10_12 101200
#endif
// macOS 10.12 deprecated NSAnyEventMask in favor of NSEventMaskAny
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
#define NSEventMaskAny NSAnyEventMask
#endif
extern FXMainWindow *g_main_window;
@interface MyAppDelegate : NSObject<NSApplicationDelegate>
{
}
@end
@implementation MyAppDelegate
- (void) applicationWillBecomeActive:(NSNotification*)notif
{
printf("WillBecomeActive\n");
g_main_window->show();
}
- (void) applicationWillTerminate:(NSNotification*)notif
{
/* Doesn't get called. Not sure why */
printf("WillTerminate\n");
FXApp::instance()->exit();
}
- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*)sender
{
/* Doesn't get called. Not sure why */
printf("ShouldTerminate\n");
return YES;
}
- (void) applicationWillHide:(NSNotification*)notif
{
printf("WillHide\n");
g_main_window->hide();
}
- (void) handleQuitEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)replyEvent
{
printf("QuitEvent\n");
FXApp::instance()->exit();
}
@end
extern "C" {
void
init_apple_message_system()
{
static MyAppDelegate *d = [MyAppDelegate new];
[[NSApplication sharedApplication] setDelegate:d];
/* Register for Apple Events. */
/* This is from
http://stackoverflow.com/questions/1768497/application-exit-event */
NSAppleEventManager *aem = [NSAppleEventManager sharedAppleEventManager];
[aem setEventHandler:d
andSelector:@selector(handleQuitEvent:withReplyEvent:)
forEventClass:kCoreEventClass andEventID:kAEQuitApplication];
}
void
check_apple_events()
{
NSApplication *app = [NSApplication sharedApplication];
NSAutoreleasePool *pool = [NSAutoreleasePool new];
while (1) {
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:nil
inMode:NSDefaultRunLoopMode
dequeue:YES];
if (event == NULL)
break;
else {
//printf("Event happened: Type: %d\n", event->_type);
[app sendEvent: event];
}
}
[pool release];
}
} /* extern "C" */
/*******************************
Mac support for HID Test GUI
Alan Ott
Signal 11 Software
*******************************/
#ifndef MAC_SUPPORT_H__
#define MAC_SUPPORT_H__
extern "C" {
void init_apple_message_system();
void check_apple_events();
}
#endif

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

/*******************************************************
Demo Program for HIDAPI
Alan Ott
Signal 11 Software
2010-07-20
Copyright 2010, All Rights Reserved
This contents of this file may be used by anyone
for any reason without any conditions and may be
used as a starting point for your own applications
which use HIDAPI.
********************************************************/
#include <fx.h>
#include "hidapi.h"
#include "mac_support.h"
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#ifdef _WIN32
// Thanks Microsoft, but I know how to use strncpy().
#pragma warning(disable:4996)
#endif
class MainWindow : public FXMainWindow {
FXDECLARE(MainWindow)
public:
enum {
ID_FIRST = FXMainWindow::ID_LAST,
ID_CONNECT,
ID_DISCONNECT,
ID_RESCAN,
ID_SEND_OUTPUT_REPORT,
ID_SEND_FEATURE_REPORT,
ID_GET_FEATURE_REPORT,
ID_CLEAR,
ID_TIMER,
ID_MAC_TIMER,
ID_LAST,
};
private:
FXList *device_list;
FXButton *connect_button;
FXButton *disconnect_button;
FXButton *rescan_button;
FXButton *output_button;
FXLabel *connected_label;
FXTextField *output_text;
FXTextField *output_len;
FXButton *feature_button;
FXButton *get_feature_button;
FXTextField *feature_text;
FXTextField *feature_len;
FXTextField *get_feature_text;
FXText *input_text;
FXFont *title_font;
struct hid_device_info *devices;
hid_device *connected_device;
size_t getDataFromTextField(FXTextField *tf, char *buf, size_t len);
int getLengthFromTextField(FXTextField *tf);
protected:
MainWindow() {};
public:
MainWindow(FXApp *a);
~MainWindow();
virtual void create();
long onConnect(FXObject *sender, FXSelector sel, void *ptr);
long onDisconnect(FXObject *sender, FXSelector sel, void *ptr);
long onRescan(FXObject *sender, FXSelector sel, void *ptr);
long onSendOutputReport(FXObject *sender, FXSelector sel, void *ptr);
long onSendFeatureReport(FXObject *sender, FXSelector sel, void *ptr);
long onGetFeatureReport(FXObject *sender, FXSelector sel, void *ptr);
long onClear(FXObject *sender, FXSelector sel, void *ptr);
long onTimeout(FXObject *sender, FXSelector sel, void *ptr);
long onMacTimeout(FXObject *sender, FXSelector sel, void *ptr);
};
// FOX 1.7 changes the timeouts to all be nanoseconds.
// Fox 1.6 had all timeouts as milliseconds.
#if (FOX_MINOR >= 7)
const int timeout_scalar = 1000*1000;
#else
const int timeout_scalar = 1;
#endif
FXMainWindow *g_main_window;
FXDEFMAP(MainWindow) MainWindowMap [] = {
FXMAPFUNC(SEL_COMMAND, MainWindow::ID_CONNECT, MainWindow::onConnect ),
FXMAPFUNC(SEL_COMMAND, MainWindow::ID_DISCONNECT, MainWindow::onDisconnect ),
FXMAPFUNC(SEL_COMMAND, MainWindow::ID_RESCAN, MainWindow::onRescan ),
FXMAPFUNC(SEL_COMMAND, MainWindow::ID_SEND_OUTPUT_REPORT, MainWindow::onSendOutputReport ),
FXMAPFUNC(SEL_COMMAND, MainWindow::ID_SEND_FEATURE_REPORT, MainWindow::onSendFeatureReport ),
FXMAPFUNC(SEL_COMMAND, MainWindow::ID_GET_FEATURE_REPORT, MainWindow::onGetFeatureReport ),
FXMAPFUNC(SEL_COMMAND, MainWindow::ID_CLEAR, MainWindow::onClear ),
FXMAPFUNC(SEL_TIMEOUT, MainWindow::ID_TIMER, MainWindow::onTimeout ),
FXMAPFUNC(SEL_TIMEOUT, MainWindow::ID_MAC_TIMER, MainWindow::onMacTimeout ),
};
FXIMPLEMENT(MainWindow, FXMainWindow, MainWindowMap, ARRAYNUMBER(MainWindowMap));
MainWindow::MainWindow(FXApp *app)
: FXMainWindow(app, "HIDAPI Test Application", NULL, NULL, DECOR_ALL, 200,100, 425,700)
{
devices = NULL;
connected_device = NULL;
FXVerticalFrame *vf = new FXVerticalFrame(this, LAYOUT_FILL_Y|LAYOUT_FILL_X);
FXLabel *label = new FXLabel(vf, "HIDAPI Test Tool");
title_font = new FXFont(getApp(), "Arial", 14, FXFont::Bold);
label->setFont(title_font);
new FXLabel(vf,
"Select a device and press Connect.", NULL, JUSTIFY_LEFT);
new FXLabel(vf,
"Output data bytes can be entered in the Output section, \n"
"separated by space, comma or brackets. Data starting with 0x\n"
"is treated as hex. Data beginning with a 0 is treated as \n"
"octal. All other data is treated as decimal.", NULL, JUSTIFY_LEFT);
new FXLabel(vf,
"Data received from the device appears in the Input section.",
NULL, JUSTIFY_LEFT);
new FXLabel(vf,
"Optionally, a report length may be specified. Extra bytes are\n"
"padded with zeros. If no length is specified, the length is \n"
"inferred from the data.",
NULL, JUSTIFY_LEFT);
new FXLabel(vf, "");
// Device List and Connect/Disconnect buttons
FXHorizontalFrame *hf = new FXHorizontalFrame(vf, LAYOUT_FILL_X);
//device_list = new FXList(new FXHorizontalFrame(hf,FRAME_SUNKEN|FRAME_THICK, 0,0,0,0, 0,0,0,0), NULL, 0, LISTBOX_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0,0,300,200);
device_list = new FXList(new FXHorizontalFrame(hf,FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0), NULL, 0, LISTBOX_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,300,200);
FXVerticalFrame *buttonVF = new FXVerticalFrame(hf);
connect_button = new FXButton(buttonVF, "Connect", NULL, this, ID_CONNECT, BUTTON_NORMAL|LAYOUT_FILL_X);
disconnect_button = new FXButton(buttonVF, "Disconnect", NULL, this, ID_DISCONNECT, BUTTON_NORMAL|LAYOUT_FILL_X);
disconnect_button->disable();
rescan_button = new FXButton(buttonVF, "Re-Scan devices", NULL, this, ID_RESCAN, BUTTON_NORMAL|LAYOUT_FILL_X);
new FXHorizontalFrame(buttonVF, 0, 0,0,0,0, 0,0,50,0);
connected_label = new FXLabel(vf, "Disconnected");
new FXHorizontalFrame(vf);
// Output Group Box
FXGroupBox *gb = new FXGroupBox(vf, "Output", FRAME_GROOVE|LAYOUT_FILL_X);
FXMatrix *matrix = new FXMatrix(gb, 3, MATRIX_BY_COLUMNS|LAYOUT_FILL_X);
new FXLabel(matrix, "Data");
new FXLabel(matrix, "Length");
new FXLabel(matrix, "");
//hf = new FXHorizontalFrame(gb, LAYOUT_FILL_X);
output_text = new FXTextField(matrix, 30, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
output_text->setText("1 0x81 0");
output_len = new FXTextField(matrix, 5, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
output_button = new FXButton(matrix, "Send Output Report", NULL, this, ID_SEND_OUTPUT_REPORT, BUTTON_NORMAL|LAYOUT_FILL_X);
output_button->disable();
//new FXHorizontalFrame(matrix, LAYOUT_FILL_X);
//hf = new FXHorizontalFrame(gb, LAYOUT_FILL_X);
feature_text = new FXTextField(matrix, 30, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
feature_len = new FXTextField(matrix, 5, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
feature_button = new FXButton(matrix, "Send Feature Report", NULL, this, ID_SEND_FEATURE_REPORT, BUTTON_NORMAL|LAYOUT_FILL_X);
feature_button->disable();
get_feature_text = new FXTextField(matrix, 30, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
new FXWindow(matrix);
get_feature_button = new FXButton(matrix, "Get Feature Report", NULL, this, ID_GET_FEATURE_REPORT, BUTTON_NORMAL|LAYOUT_FILL_X);
get_feature_button->disable();
// Input Group Box
gb = new FXGroupBox(vf, "Input", FRAME_GROOVE|LAYOUT_FILL_X|LAYOUT_FILL_Y);
FXVerticalFrame *innerVF = new FXVerticalFrame(gb, LAYOUT_FILL_X|LAYOUT_FILL_Y);
input_text = new FXText(new FXHorizontalFrame(innerVF,LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, 0,0,0,0, 0,0,0,0), NULL, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y);
input_text->setEditable(false);
new FXButton(innerVF, "Clear", NULL, this, ID_CLEAR, BUTTON_NORMAL|LAYOUT_RIGHT);
}
MainWindow::~MainWindow()
{
if (connected_device)
hid_close(connected_device);
hid_exit();
delete title_font;
}
void
MainWindow::create()
{
FXMainWindow::create();
show();
onRescan(NULL, 0, NULL);
#ifdef __APPLE__
init_apple_message_system();
#endif
getApp()->addTimeout(this, ID_MAC_TIMER,
50 * timeout_scalar /*50ms*/);
}
long
MainWindow::onConnect(FXObject *sender, FXSelector sel, void *ptr)
{
if (connected_device != NULL)
return 1;
FXint cur_item = device_list->getCurrentItem();
if (cur_item < 0)
return -1;
FXListItem *item = device_list->getItem(cur_item);
if (!item)
return -1;
struct hid_device_info *device_info = (struct hid_device_info*) item->getData();
if (!device_info)
return -1;
connected_device = hid_open_path(device_info->path);
if (!connected_device) {
FXMessageBox::error(this, MBOX_OK, "Device Error", "Unable To Connect to Device");
return -1;
}
hid_set_nonblocking(connected_device, 1);
getApp()->addTimeout(this, ID_TIMER,
5 * timeout_scalar /*5ms*/);
FXString s;
s.format("Connected to: %04hx:%04hx -", device_info->vendor_id, device_info->product_id);
s += FXString(" ") + device_info->manufacturer_string;
s += FXString(" ") + device_info->product_string;
connected_label->setText(s);
output_button->enable();
feature_button->enable();
get_feature_button->enable();
connect_button->disable();
disconnect_button->enable();
input_text->setText("");
return 1;
}
long
MainWindow::onDisconnect(FXObject *sender, FXSelector sel, void *ptr)
{
hid_close(connected_device);
connected_device = NULL;
connected_label->setText("Disconnected");
output_button->disable();
feature_button->disable();
get_feature_button->disable();
connect_button->enable();
disconnect_button->disable();
getApp()->removeTimeout(this, ID_TIMER);
return 1;
}
long
MainWindow::onRescan(FXObject *sender, FXSelector sel, void *ptr)
{
struct hid_device_info *cur_dev;
device_list->clearItems();
// List the Devices
hid_free_enumeration(devices);
devices = hid_enumerate(0x0, 0x0);
cur_dev = devices;
while (cur_dev) {
// Add it to the List Box.
FXString s;
FXString usage_str;
s.format("%04hx:%04hx -", cur_dev->vendor_id, cur_dev->product_id);
s += FXString(" ") + cur_dev->manufacturer_string;
s += FXString(" ") + cur_dev->product_string;
usage_str.format(" (usage: %04hx:%04hx) ", cur_dev->usage_page, cur_dev->usage);
s += usage_str;
FXListItem *li = new FXListItem(s, NULL, cur_dev);
device_list->appendItem(li);
cur_dev = cur_dev->next;
}
if (device_list->getNumItems() == 0)
device_list->appendItem("*** No Devices Connected ***");
else {
device_list->selectItem(0);
}
return 1;
}
size_t
MainWindow::getDataFromTextField(FXTextField *tf, char *buf, size_t len)
{
const char *delim = " ,{}\t\r\n";
FXString data = tf->getText();
const FXchar *d = data.text();
size_t i = 0;
// Copy the string from the GUI.
size_t sz = strlen(d);
char *str = (char*) malloc(sz+1);
strcpy(str, d);
// For each token in the string, parse and store in buf[].
char *token = strtok(str, delim);
while (token) {
char *endptr;
long int val = strtol(token, &endptr, 0);
buf[i++] = val;
token = strtok(NULL, delim);
}
free(str);
return i;
}
/* getLengthFromTextField()
Returns length:
0: empty text field
>0: valid length
-1: invalid length */
int
MainWindow::getLengthFromTextField(FXTextField *tf)
{
long int len;
FXString str = tf->getText();
size_t sz = str.length();
if (sz > 0) {
char *endptr;
len = strtol(str.text(), &endptr, 0);
if (endptr != str.text() && *endptr == '\0') {
if (len <= 0) {
FXMessageBox::error(this, MBOX_OK, "Invalid length", "Enter a length greater than zero.");
return -1;
}
return len;
}
else
return -1;
}
return 0;
}
long
MainWindow::onSendOutputReport(FXObject *sender, FXSelector sel, void *ptr)
{
char buf[256];
size_t data_len, len;
int textfield_len;
memset(buf, 0x0, sizeof(buf));
textfield_len = getLengthFromTextField(output_len);
data_len = getDataFromTextField(output_text, buf, sizeof(buf));
if (textfield_len < 0) {
FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is invalid. Please enter a number in hex, octal, or decimal.");
return 1;
}
if (textfield_len > sizeof(buf)) {
FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is too long.");
return 1;
}
len = (textfield_len)? textfield_len: data_len;
int res = hid_write(connected_device, (const unsigned char*)buf, len);
if (res < 0) {
FXMessageBox::error(this, MBOX_OK, "Error Writing", "Could not write to device. Error reported was: %ls", hid_error(connected_device));
}
return 1;
}
long
MainWindow::onSendFeatureReport(FXObject *sender, FXSelector sel, void *ptr)
{
char buf[256];
size_t data_len, len;
int textfield_len;
memset(buf, 0x0, sizeof(buf));
textfield_len = getLengthFromTextField(feature_len);
data_len = getDataFromTextField(feature_text, buf, sizeof(buf));
if (textfield_len < 0) {
FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is invalid. Please enter a number in hex, octal, or decimal.");
return 1;
}
if (textfield_len > sizeof(buf)) {
FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is too long.");
return 1;
}
len = (textfield_len)? textfield_len: data_len;
int res = hid_send_feature_report(connected_device, (const unsigned char*)buf, len);
if (res < 0) {
FXMessageBox::error(this, MBOX_OK, "Error Writing", "Could not send feature report to device. Error reported was: %ls", hid_error(connected_device));
}
return 1;
}
long
MainWindow::onGetFeatureReport(FXObject *sender, FXSelector sel, void *ptr)
{
char buf[256];
size_t len;
memset(buf, 0x0, sizeof(buf));
len = getDataFromTextField(get_feature_text, buf, sizeof(buf));
if (len != 1) {
FXMessageBox::error(this, MBOX_OK, "Too many numbers", "Enter only a single report number in the text field");
}
int res = hid_get_feature_report(connected_device, (unsigned char*)buf, sizeof(buf));
if (res < 0) {
FXMessageBox::error(this, MBOX_OK, "Error Getting Report", "Could not get feature report from device. Error reported was: %ls", hid_error(connected_device));
}
if (res > 0) {
FXString s;
s.format("Returned Feature Report. %d bytes:\n", res);
for (int i = 0; i < res; i++) {
FXString t;
t.format("%02hhx ", buf[i]);
s += t;
if ((i+1) % 4 == 0)
s += " ";
if ((i+1) % 16 == 0)
s += "\n";
}
s += "\n";
input_text->appendText(s);
input_text->setBottomLine(INT_MAX);
}
return 1;
}
long
MainWindow::onClear(FXObject *sender, FXSelector sel, void *ptr)
{
input_text->setText("");
return 1;
}
long
MainWindow::onTimeout(FXObject *sender, FXSelector sel, void *ptr)
{
unsigned char buf[256];
int res = hid_read(connected_device, buf, sizeof(buf));
if (res > 0) {
FXString s;
s.format("Received %d bytes:\n", res);
for (int i = 0; i < res; i++) {
FXString t;
t.format("%02hhx ", buf[i]);
s += t;
if ((i+1) % 4 == 0)
s += " ";
if ((i+1) % 16 == 0)
s += "\n";
}
s += "\n";
input_text->appendText(s);
input_text->setBottomLine(INT_MAX);
}
if (res < 0) {
input_text->appendText("hid_read() returned error\n");
input_text->setBottomLine(INT_MAX);
}
getApp()->addTimeout(this, ID_TIMER,
5 * timeout_scalar /*5ms*/);
return 1;
}
long
MainWindow::onMacTimeout(FXObject *sender, FXSelector sel, void *ptr)
{
#ifdef __APPLE__
check_apple_events();
getApp()->addTimeout(this, ID_MAC_TIMER,
50 * timeout_scalar /*50ms*/);
#endif
return 1;
}
int main(int argc, char **argv)
{
FXApp app("HIDAPI Test Application", "Signal 11 Software");
app.init(argc, argv);
g_main_window = new MainWindow(&app);
app.create();
app.run();
return 0;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDisplayName</key>
<string></string>
<key>CFBundleExecutable</key>
<string>hidapi-testgui</string>
<key>CFBundleIconFile</key>
<string>Signal11.icns</string>
<key>CFBundleIdentifier</key>
<string>us.signal11.hidtestgui</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>testgui</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CSResourcesFileMapped</key>
<true/>
</dict>
</plist>

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet


Microsoft Visual Studio Solution File, Format Version 10.00
# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testgui", "testgui.vcproj", "{08769AC3-785A-4DDC-BFC7-1775414B7AB7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{08769AC3-785A-4DDC-BFC7-1775414B7AB7}.Debug|Win32.ActiveCfg = Debug|Win32
{08769AC3-785A-4DDC-BFC7-1775414B7AB7}.Debug|Win32.Build.0 = Debug|Win32
{08769AC3-785A-4DDC-BFC7-1775414B7AB7}.Release|Win32.ActiveCfg = Release|Win32
{08769AC3-785A-4DDC-BFC7-1775414B7AB7}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Sorry, the diff of this file is not supported yet

Debug
Release
.vs/
*.exp
*.ilk
*.lib
*.suo
*.vcproj.*
*.vcxproj.*
*.ncb
*.suo
*.dll
*.pdb
.deps
.libs
*.lo
*.la

Sorry, the diff of this file is not supported yet


Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.136
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hidapi", "hidapi.vcxproj", "{A107C21C-418A-4697-BB10-20C3AA60E2E4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hidtest", "hidtest.vcxproj", "{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|Win32.ActiveCfg = Debug|Win32
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|Win32.Build.0 = Debug|Win32
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|x64.ActiveCfg = Debug|x64
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|x64.Build.0 = Debug|x64
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|Win32.ActiveCfg = Release|Win32
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|Win32.Build.0 = Release|Win32
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|x64.ActiveCfg = Release|x64
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|x64.Build.0 = Release|x64
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|Win32.ActiveCfg = Debug|Win32
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|Win32.Build.0 = Debug|Win32
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|x64.ActiveCfg = Debug|x64
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|x64.Build.0 = Debug|x64
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|Win32.ActiveCfg = Release|Win32
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|Win32.Build.0 = Release|Win32
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|x64.ActiveCfg = Release|x64
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8749E535-9C65-4A89-840E-78D7578C7866}
EndGlobalSection
EndGlobal

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

project(pp_data_dump C)
add_executable(pp_data_dump pp_data_dump.c)
set_target_properties(pp_data_dump
PROPERTIES
C_STANDARD 11
C_STANDARD_REQUIRED TRUE
)
target_link_libraries(pp_data_dump
PRIVATE hidapi_winapi
)
install(TARGETS pp_data_dump
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
)
#include <hid.c>
#include <../windows/hidapi_descriptor_reconstruct.h>
#include <hidapi.h>
#if defined(__MINGW32__)
#pragma GCC diagnostic ignored "-Wformat"
#pragma GCC diagnostic ignored "-Wformat-extra-args"
#endif
void dump_hid_pp_cap(FILE* file, phid_pp_cap pp_cap, unsigned int cap_idx) {
fprintf(file, "pp_data->cap[%d]->UsagePage = 0x%04hX\n", cap_idx, pp_cap->UsagePage);
fprintf(file, "pp_data->cap[%d]->ReportID = 0x%02hhX\n", cap_idx, pp_cap->ReportID);
fprintf(file, "pp_data->cap[%d]->BitPosition = %hhu\n", cap_idx, pp_cap->BitPosition);
fprintf(file, "pp_data->cap[%d]->BitSize = %hu\n", cap_idx, pp_cap->ReportSize);
fprintf(file, "pp_data->cap[%d]->ReportCount = %hu\n", cap_idx, pp_cap->ReportCount);
fprintf(file, "pp_data->cap[%d]->BytePosition = 0x%04hX\n", cap_idx, pp_cap->BytePosition);
fprintf(file, "pp_data->cap[%d]->BitCount = %hu\n", cap_idx, pp_cap->BitCount);
fprintf(file, "pp_data->cap[%d]->BitField = 0x%02lX\n", cap_idx, pp_cap->BitField);
fprintf(file, "pp_data->cap[%d]->NextBytePosition = 0x%04hX\n", cap_idx, pp_cap->NextBytePosition);
fprintf(file, "pp_data->cap[%d]->LinkCollection = 0x%04hX\n", cap_idx, pp_cap->LinkCollection);
fprintf(file, "pp_data->cap[%d]->LinkUsagePage = 0x%04hX\n", cap_idx, pp_cap->LinkUsagePage);
fprintf(file, "pp_data->cap[%d]->LinkUsage = 0x%04hX\n", cap_idx, pp_cap->LinkUsage);
// 8 Flags in one byte
fprintf(file, "pp_data->cap[%d]->IsMultipleItemsForArray = %hhu\n", cap_idx, pp_cap->IsMultipleItemsForArray);
fprintf(file, "pp_data->cap[%d]->IsButtonCap = %hhu\n", cap_idx, pp_cap->IsButtonCap);
fprintf(file, "pp_data->cap[%d]->IsPadding = %hhu\n", cap_idx, pp_cap->IsPadding);
fprintf(file, "pp_data->cap[%d]->IsAbsolute = %hhu\n", cap_idx, pp_cap->IsAbsolute);
fprintf(file, "pp_data->cap[%d]->IsRange = %hhu\n", cap_idx, pp_cap->IsRange);
fprintf(file, "pp_data->cap[%d]->IsAlias = %hhu\n", cap_idx, pp_cap->IsAlias);
fprintf(file, "pp_data->cap[%d]->IsStringRange = %hhu\n", cap_idx, pp_cap->IsStringRange);
fprintf(file, "pp_data->cap[%d]->IsDesignatorRange = %hhu\n", cap_idx, pp_cap->IsDesignatorRange);
fprintf(file, "pp_data->cap[%d]->Reserved1 = 0x%02hhX%02hhX%02hhX\n", cap_idx, pp_cap->Reserved1[0], pp_cap->Reserved1[1], pp_cap->Reserved1[2]);
for (int token_idx = 0; token_idx < 4; token_idx++) {
fprintf(file, "pp_data->cap[%d]->pp_cap->UnknownTokens[%d].Token = 0x%02hhX\n", cap_idx, token_idx, pp_cap->UnknownTokens[token_idx].Token);
fprintf(file, "pp_data->cap[%d]->pp_cap->UnknownTokens[%d].Reserved = 0x%02hhX%02hhX%02hhX\n", cap_idx, token_idx, pp_cap->UnknownTokens[token_idx].Reserved[0], pp_cap->UnknownTokens[token_idx].Reserved[1], pp_cap->UnknownTokens[token_idx].Reserved[2]);
fprintf(file, "pp_data->cap[%d]->pp_cap->UnknownTokens[%d].BitField = 0x%08lX\n", cap_idx, token_idx, pp_cap->UnknownTokens[token_idx].BitField);
}
if (pp_cap->IsRange) {
fprintf(file, "pp_data->cap[%d]->Range.UsageMin = 0x%04hX\n", cap_idx, pp_cap->Range.UsageMin);
fprintf(file, "pp_data->cap[%d]->Range.UsageMax = 0x%04hX\n", cap_idx, pp_cap->Range.UsageMax);
fprintf(file, "pp_data->cap[%d]->Range.StringMin = %hu\n", cap_idx, pp_cap->Range.StringMin);
fprintf(file, "pp_data->cap[%d]->Range.StringMax = %hu\n", cap_idx, pp_cap->Range.StringMax);
fprintf(file, "pp_data->cap[%d]->Range.DesignatorMin = %hu\n", cap_idx, pp_cap->Range.DesignatorMin);
fprintf(file, "pp_data->cap[%d]->Range.DesignatorMax = %hu\n", cap_idx, pp_cap->Range.DesignatorMax);
fprintf(file, "pp_data->cap[%d]->Range.DataIndexMin = %hu\n", cap_idx, pp_cap->Range.DataIndexMin);
fprintf(file, "pp_data->cap[%d]->Range.DataIndexMax = %hu\n", cap_idx, pp_cap->Range.DataIndexMax);
}
else {
fprintf(file, "pp_data->cap[%d]->NotRange.Usage = 0x%04hX\n", cap_idx, pp_cap->NotRange.Usage);
fprintf(file, "pp_data->cap[%d]->NotRange.Reserved1 = 0x%04hX\n", cap_idx, pp_cap->NotRange.Reserved1);
fprintf(file, "pp_data->cap[%d]->NotRange.StringIndex = %hu\n", cap_idx, pp_cap->NotRange.StringIndex);
fprintf(file, "pp_data->cap[%d]->NotRange.Reserved2 = %hu\n", cap_idx, pp_cap->NotRange.Reserved2);
fprintf(file, "pp_data->cap[%d]->NotRange.DesignatorIndex = %hu\n", cap_idx, pp_cap->NotRange.DesignatorIndex);
fprintf(file, "pp_data->cap[%d]->NotRange.Reserved3 = %hu\n", cap_idx, pp_cap->NotRange.Reserved3);
fprintf(file, "pp_data->cap[%d]->NotRange.DataIndex = %hu\n", cap_idx, pp_cap->NotRange.DataIndex);
fprintf(file, "pp_data->cap[%d]->NotRange.Reserved4 = %hu\n", cap_idx, pp_cap->NotRange.Reserved4);
}
if (pp_cap->IsButtonCap) {
fprintf(file, "pp_data->cap[%d]->Button.LogicalMin = %ld\n", cap_idx, pp_cap->Button.LogicalMin);
fprintf(file, "pp_data->cap[%d]->Button.LogicalMax = %ld\n", cap_idx, pp_cap->Button.LogicalMax);
}
else
{
fprintf(file, "pp_data->cap[%d]->NotButton.HasNull = %hhu\n", cap_idx, pp_cap->NotButton.HasNull);
fprintf(file, "pp_data->cap[%d]->NotButton.Reserved4 = 0x%02hhX%02hhX%02hhX\n", cap_idx, pp_cap->NotButton.Reserved4[0], pp_cap->NotButton.Reserved4[1], pp_cap->NotButton.Reserved4[2]);
fprintf(file, "pp_data->cap[%d]->NotButton.LogicalMin = %ld\n", cap_idx, pp_cap->NotButton.LogicalMin);
fprintf(file, "pp_data->cap[%d]->NotButton.LogicalMax = %ld\n", cap_idx, pp_cap->NotButton.LogicalMax);
fprintf(file, "pp_data->cap[%d]->NotButton.PhysicalMin = %ld\n", cap_idx, pp_cap->NotButton.PhysicalMin);
fprintf(file, "pp_data->cap[%d]->NotButton.PhysicalMax = %ld\n", cap_idx, pp_cap->NotButton.PhysicalMax);
};
fprintf(file, "pp_data->cap[%d]->Units = %lu\n", cap_idx, pp_cap->Units);
fprintf(file, "pp_data->cap[%d]->UnitsExp = %lu\n", cap_idx, pp_cap->UnitsExp);
}
void dump_hidp_link_collection_node(FILE* file, phid_pp_link_collection_node pcoll, unsigned int coll_idx) {
fprintf(file, "pp_data->LinkCollectionArray[%d]->LinkUsage = 0x%04hX\n", coll_idx, pcoll->LinkUsage);
fprintf(file, "pp_data->LinkCollectionArray[%d]->LinkUsagePage = 0x%04hX\n", coll_idx, pcoll->LinkUsagePage);
fprintf(file, "pp_data->LinkCollectionArray[%d]->Parent = %hu\n", coll_idx, pcoll->Parent);
fprintf(file, "pp_data->LinkCollectionArray[%d]->NumberOfChildren = %hu\n", coll_idx, pcoll->NumberOfChildren);
fprintf(file, "pp_data->LinkCollectionArray[%d]->NextSibling = %hu\n", coll_idx, pcoll->NextSibling);
fprintf(file, "pp_data->LinkCollectionArray[%d]->FirstChild = %hu\n", coll_idx, pcoll->FirstChild);
fprintf(file, "pp_data->LinkCollectionArray[%d]->CollectionType = %d\n", coll_idx, pcoll->CollectionType);
fprintf(file, "pp_data->LinkCollectionArray[%d]->IsAlias = %d\n", coll_idx, pcoll->IsAlias);
fprintf(file, "pp_data->LinkCollectionArray[%d]->Reserved = 0x%08X\n", coll_idx, pcoll->Reserved);
}
int dump_pp_data(FILE* file, hid_device* dev)
{
BOOL res;
hidp_preparsed_data* pp_data = NULL;
res = HidD_GetPreparsedData(dev->device_handle, (PHIDP_PREPARSED_DATA*) &pp_data);
if (!res) {
printf("ERROR: HidD_GetPreparsedData failed!");
return -1;
}
else {
fprintf(file, "pp_data->MagicKey = 0x%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX\n", pp_data->MagicKey[0], pp_data->MagicKey[1], pp_data->MagicKey[2], pp_data->MagicKey[3], pp_data->MagicKey[4], pp_data->MagicKey[5], pp_data->MagicKey[6], pp_data->MagicKey[7]);
fprintf(file, "pp_data->Usage = 0x%04hX\n", pp_data->Usage);
fprintf(file, "pp_data->UsagePage = 0x%04hX\n", pp_data->UsagePage);
fprintf(file, "pp_data->Reserved = 0x%04hX%04hX\n", pp_data->Reserved[0], pp_data->Reserved[1]);
fprintf(file, "# Input caps_info struct:\n");
fprintf(file, "pp_data->caps_info[0]->FirstCap = %hu\n", pp_data->caps_info[0].FirstCap);
fprintf(file, "pp_data->caps_info[0]->LastCap = %hu\n", pp_data->caps_info[0].LastCap);
fprintf(file, "pp_data->caps_info[0]->NumberOfCaps = %hu\n", pp_data->caps_info[0].NumberOfCaps);
fprintf(file, "pp_data->caps_info[0]->ReportByteLength = %hu\n", pp_data->caps_info[0].ReportByteLength);
fprintf(file, "# Output caps_info struct:\n");
fprintf(file, "pp_data->caps_info[1]->FirstCap = %hu\n", pp_data->caps_info[1].FirstCap);
fprintf(file, "pp_data->caps_info[1]->LastCap = %hu\n", pp_data->caps_info[1].LastCap);
fprintf(file, "pp_data->caps_info[1]->NumberOfCaps = %hu\n", pp_data->caps_info[1].NumberOfCaps);
fprintf(file, "pp_data->caps_info[1]->ReportByteLength = %hu\n", pp_data->caps_info[1].ReportByteLength);
fprintf(file, "# Feature caps_info struct:\n");
fprintf(file, "pp_data->caps_info[2]->FirstCap = %hu\n", pp_data->caps_info[2].FirstCap);
fprintf(file, "pp_data->caps_info[2]->LastCap = %hu\n", pp_data->caps_info[2].LastCap);
fprintf(file, "pp_data->caps_info[2]->NumberOfCaps = %hu\n", pp_data->caps_info[2].NumberOfCaps);
fprintf(file, "pp_data->caps_info[2]->ReportByteLength = %hu\n", pp_data->caps_info[2].ReportByteLength);
fprintf(file, "# LinkCollectionArray Offset & Size:\n");
fprintf(file, "pp_data->FirstByteOfLinkCollectionArray = 0x%04hX\n", pp_data->FirstByteOfLinkCollectionArray);
fprintf(file, "pp_data->NumberLinkCollectionNodes = %hu\n", pp_data->NumberLinkCollectionNodes);
phid_pp_cap pcap = (phid_pp_cap)(((unsigned char*)pp_data) + offsetof(hidp_preparsed_data, caps));
fprintf(file, "# Input hid_pp_cap struct:\n");
for (int caps_idx = pp_data->caps_info[0].FirstCap; caps_idx < pp_data->caps_info[0].LastCap; caps_idx++) {
dump_hid_pp_cap(file, pcap + caps_idx, caps_idx);
fprintf(file, "\n");
}
fprintf(file, "# Output hid_pp_cap struct:\n");
for (int caps_idx = pp_data->caps_info[1].FirstCap; caps_idx < pp_data->caps_info[1].LastCap; caps_idx++) {
dump_hid_pp_cap(file, pcap + caps_idx, caps_idx);
fprintf(file, "\n");
}
fprintf(file, "# Feature hid_pp_cap struct:\n");
for (int caps_idx = pp_data->caps_info[2].FirstCap; caps_idx < pp_data->caps_info[2].LastCap; caps_idx++) {
dump_hid_pp_cap(file, pcap + caps_idx, caps_idx);
fprintf(file, "\n");
}
phid_pp_link_collection_node pcoll = (phid_pp_link_collection_node)(((unsigned char*)pcap) + pp_data->FirstByteOfLinkCollectionArray);
fprintf(file, "# Link Collections:\n");
for (int coll_idx = 0; coll_idx < pp_data->NumberLinkCollectionNodes; coll_idx++) {
dump_hidp_link_collection_node(file, pcoll + coll_idx, coll_idx);
}
HidD_FreePreparsedData((PHIDP_PREPARSED_DATA) pp_data);
return 0;
}
}
int main(int argc, char* argv[])
{
(void)argc;
(void)argv;
#define MAX_STR 255
struct hid_device_info *devs, *cur_dev;
printf("pp_data_dump tool. Compiled with hidapi version %s, runtime version %s.\n", HID_API_VERSION_STR, hid_version_str());
if (hid_version()->major == HID_API_VERSION_MAJOR && hid_version()->minor == HID_API_VERSION_MINOR && hid_version()->patch == HID_API_VERSION_PATCH) {
printf("Compile-time version matches runtime version of hidapi.\n\n");
}
else {
printf("Compile-time version is different than runtime version of hidapi.\n]n");
}
if (hid_init())
return -1;
devs = hid_enumerate(0x0, 0x0);
cur_dev = devs;
while (cur_dev) {
printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
printf("\n");
printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string);
printf(" Product: %ls\n", cur_dev->product_string);
printf(" Release: %hX\n", cur_dev->release_number);
printf(" Interface: %d\n", cur_dev->interface_number);
printf(" Usage (page): %02X (%02X)\n", cur_dev->usage, cur_dev->usage_page);
hid_device *device = hid_open_path(cur_dev->path);
if (device) {
char filename[MAX_STR];
FILE* file;
sprintf_s(filename, MAX_STR, "%04X_%04X_%04X_%04X.pp_data", cur_dev->vendor_id, cur_dev->product_id, cur_dev->usage, cur_dev->usage_page);
errno_t err = fopen_s(&file, filename, "w");
if (err == 0) {
fprintf(file, "# HIDAPI device info struct:\n");
fprintf(file, "dev->vendor_id = 0x%04hX\n", cur_dev->vendor_id);
fprintf(file, "dev->product_id = 0x%04hX\n", cur_dev->product_id);
fprintf(file, "dev->manufacturer_string = \"%ls\"\n", cur_dev->manufacturer_string);
fprintf(file, "dev->product_string = \"%ls\"\n", cur_dev->product_string);
fprintf(file, "dev->release_number = 0x%04hX\n", cur_dev->release_number);
fprintf(file, "dev->interface_number = %d\n", cur_dev->interface_number);
fprintf(file, "dev->usage = 0x%04hX\n", cur_dev->usage);
fprintf(file, "dev->usage_page = 0x%04hX\n", cur_dev->usage_page);
fprintf(file, "dev->path = \"%s\"\n", cur_dev->path);
fprintf(file, "\n# Preparsed Data struct:\n");
int res = dump_pp_data(file, device);
if (res == 0) {
printf("Dumped Preparsed Data to %s\n", filename);
}
else {
printf("ERROR: Dump Preparsed Data to %s failed!\n", filename);
}
fclose(file);
}
hid_close(device);
}
else {
printf(" Device: not available.\n");
}
printf("\n");
cur_dev = cur_dev->next;
}
hid_free_enumeration(devs);
/* Free static HIDAPI objects. */
hid_exit();
//system("pause");
return 0;
}
add_executable(hid_report_reconstructor_test hid_report_reconstructor_test.c)
set_target_properties(hid_report_reconstructor_test
PROPERTIES
C_STANDARD 11
C_STANDARD_REQUIRED TRUE
)
target_link_libraries(hid_report_reconstructor_test
PRIVATE hidapi_include hidapi_winapi
)
# Each test case requires 2 files:
# <name>.pp_data - textual representation of HIDP_PREPARSED_DATA;
# <name>_expected.rpt_desc - reconstructed HID Report Descriptor out of .pp_data file;
#
# (Non-required by test):
# <name>_real.dpt_desc - the original report rescriptor used to create a test case;
set(HID_DESCRIPTOR_RECONSTRUCT_TEST_CASES
046D_C52F_0001_000C
046D_C52F_0001_FF00
046D_C52F_0002_0001
046D_C52F_0002_FF00
17CC_1130_0000_FF01
046D_0A37_0001_000C
046A_0011_0006_0001
046D_C077_0002_0001
046D_C283_0004_0001
046D_B010_0006_0001
046D_B010_0002_FF00
046D_B010_0002_0001
046D_B010_0001_FF00
046D_B010_0001_000C
046D_C534_0001_000C
046D_C534_0001_FF00
046D_C534_0002_0001
046D_C534_0002_FF00
046D_C534_0006_0001
046D_C534_0080_0001
047F_C056_0001_000C
047F_C056_0003_FFA0
047F_C056_0005_000B
045E_02FF_0005_0001
)
set(CMAKE_VERSION_SUPPORTS_ENVIRONMENT_MODIFICATION "3.22")
if(HIDAPI_ENABLE_ASAN AND MSVC)
if(CMAKE_VERSION VERSION_LESS CMAKE_VERSION_SUPPORTS_ENVIRONMENT_MODIFICATION)
message("CTest/ASAN: Make sure to run ctest from MSVC Command Prompt")
endif()
endif()
foreach(TEST_CASE ${HID_DESCRIPTOR_RECONSTRUCT_TEST_CASES})
set(TEST_PP_DATA "${CMAKE_CURRENT_LIST_DIR}/data/${TEST_CASE}.pp_data")
if(NOT EXISTS "${TEST_PP_DATA}")
message(FATAL_ERROR "Missing '${TEST_PP_DATA}' file for '${TEST_CASE}' test case")
endif()
set(TEST_EXPECTED_DESCRIPTOR "${CMAKE_CURRENT_LIST_DIR}/data/${TEST_CASE}_expected.rpt_desc")
if(NOT EXISTS "${TEST_EXPECTED_DESCRIPTOR}")
message(FATAL_ERROR "Missing '${TEST_EXPECTED_DESCRIPTOR}' file for '${TEST_CASE}' test case")
endif()
add_test(NAME "WinHidReportReconstructTest_${TEST_CASE}"
COMMAND hid_report_reconstructor_test "${TEST_PP_DATA}" "${TEST_EXPECTED_DESCRIPTOR}"
WORKING_DIRECTORY "$<TARGET_FILE_DIR:hidapi_winapi>"
)
if(HIDAPI_ENABLE_ASAN)
if(MSVC)
if(NOT CMAKE_VERSION VERSION_LESS CMAKE_VERSION_SUPPORTS_ENVIRONMENT_MODIFICATION)
get_filename_component(MSVC_BUILD_TOOLS_DIR "${CMAKE_LINKER}" DIRECTORY)
set_property(TEST "WinHidReportReconstructTest_${TEST_CASE}" PROPERTY ENVIRONMENT_MODIFICATION "PATH=path_list_append:${MSVC_BUILD_TOOLS_DIR}")
endif()
endif()
set_property(TEST "WinHidReportReconstructTest_${TEST_CASE}" PROPERTY ENVIRONMENT "ASAN_SAVE_DUMPS=AsanDump_${TEST_CASE}.dmp")
endif()
endforeach()

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

#include "../hidapi_descriptor_reconstruct.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#if defined(__MINGW32__)
#pragma GCC diagnostic ignored "-Wformat"
#endif
static hidp_preparsed_data * alloc_preparsed_data_from_file(char* filename)
{
FILE* file;
errno_t err = fopen_s(&file, filename, "r");
if (err != 0) {
fprintf(stderr, "ERROR: Couldn't open file '%s' for reading: %s\n", filename, strerror(err));
return NULL;
}
char line[256];
{
unsigned short vendor_id = 0;
unsigned short product_id = 0;
unsigned short usage = 0;
unsigned short usage_page = 0;
unsigned short release_number = 0;
int interface_number = -1;
BOOLEAN header_read_success = FALSE;
char manufacturer_string[128];
manufacturer_string[0] = '\0';
char product_string[128];
product_string[0] = '\0';
// char path[128];
// path[0] = '\0';
while (fgets(line, sizeof(line), file) != NULL) {
if (line[0] == '\r' || line[0] == '\n') {
line[0] = '\0';
}
if (line[0] == '\0') {
// read the 'metadata' only until the first empty line
header_read_success = TRUE;
break;
}
if (sscanf(line, "dev->vendor_id = 0x%04hX\n", &vendor_id)) continue;
if (sscanf(line, "dev->product_id = 0x%04hX\n", &product_id)) continue;
if (sscanf(line, "dev->usage_page = 0x%04hX\n", &usage_page)) continue;
if (sscanf(line, "dev->usage = 0x%04hX\n", &usage)) continue;
if (sscanf(line, "dev->manufacturer_string = \"%127[^\"\n]", manufacturer_string)) continue;
if (sscanf(line, "dev->product_string = \"%127[^\"\n]", product_string)) continue;
if (sscanf(line, "dev->release_number = 0x%04hX\n", &release_number)) continue;
if (sscanf(line, "dev->interface_number = %d\n", &interface_number)) continue;
// if (sscanf(line, "dev->path = \"%127[^\"]\n", path)) continue;
}
if (!header_read_success) {
fprintf(stderr, "ERROR: Couldn't read PP Data header (missing newline)\n");
fclose(file);
return NULL;
}
printf("'Virtual' Device Read: %04hx %04hx\n", vendor_id, product_id);
if (manufacturer_string[0] != '\0') {
printf(" Manufacturer: %s\n", manufacturer_string);
}
if (product_string[0] != '\0') {
printf(" Product: %s\n", product_string);
}
printf(" Release: %hx\n", release_number);
printf(" Interface: %d\n", interface_number);
printf(" Usage (page): 0x%hx (0x%hx)\n", usage, usage_page);
}
hidp_preparsed_data static_pp_data;
memset(&static_pp_data, 0, sizeof(static_pp_data));
hidp_preparsed_data *pp_data = &static_pp_data;
unsigned int rt_idx;
unsigned int caps_idx;
unsigned int token_idx;
unsigned int coll_idx;
USAGE temp_usage;
BOOLEAN temp_boolean[3];
UCHAR temp_uchar[3];
USHORT temp_ushort;
ULONG temp_ulong;
LONG temp_long;
USHORT FirstByteOfLinkCollectionArray = 0;
USHORT NumberLinkCollectionNodes = 0;
while (fgets(line, sizeof(line), file) != NULL) {
if (line[0] == '#')
continue;
if (FirstByteOfLinkCollectionArray != 0 && NumberLinkCollectionNodes != 0) {
size_t size_of_preparsed_data = offsetof(hidp_preparsed_data, caps) + FirstByteOfLinkCollectionArray + (NumberLinkCollectionNodes * sizeof(hid_pp_link_collection_node));
pp_data->FirstByteOfLinkCollectionArray = FirstByteOfLinkCollectionArray;
pp_data->NumberLinkCollectionNodes = NumberLinkCollectionNodes;
FirstByteOfLinkCollectionArray = 0;
NumberLinkCollectionNodes = 0;
pp_data = malloc(size_of_preparsed_data);
memcpy(pp_data, &static_pp_data, sizeof(static_pp_data));
}
if (sscanf(line, "pp_data->MagicKey = 0x%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX\n", &pp_data->MagicKey[0], &pp_data->MagicKey[1], &pp_data->MagicKey[2], &pp_data->MagicKey[3], &pp_data->MagicKey[4], &pp_data->MagicKey[5], &pp_data->MagicKey[6], &pp_data->MagicKey[7])) continue;
if (sscanf(line, "pp_data->Usage = 0x%04hX\n", &pp_data->Usage)) continue;
if (sscanf(line, "pp_data->UsagePage = 0x%04hX\n", &pp_data->UsagePage)) continue;
if (sscanf(line, "pp_data->Reserved = 0x%04hX%04hX\n", &pp_data->Reserved[0], &pp_data->Reserved[1])) continue;
if (sscanf(line, "pp_data->caps_info[%d]", &rt_idx) == 1) {
const size_t caps_info_count = sizeof(pp_data->caps_info) / sizeof(pp_data->caps_info[0]);
if (rt_idx >= caps_info_count) {
fprintf(stderr, "Broken pp_data file, pp_data->caps_info[<idx>] can have at most %zu elements, accessing %ud, (%s)", caps_info_count, rt_idx, line);
continue;
}
if (sscanf(line, "pp_data->caps_info[%d]->FirstCap = %hu\n", &rt_idx, &temp_ushort) == 2) {
pp_data->caps_info[rt_idx].FirstCap = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->caps_info[%d]->LastCap = %hu\n", &rt_idx, &temp_ushort) == 2) {
pp_data->caps_info[rt_idx].LastCap = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->caps_info[%d]->NumberOfCaps = %hu\n", &rt_idx, &temp_ushort) == 2) {
pp_data->caps_info[rt_idx].NumberOfCaps = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->caps_info[%d]->ReportByteLength = %hu\n", &rt_idx, &temp_ushort) == 2) {
pp_data->caps_info[rt_idx].ReportByteLength = temp_ushort;
continue;
}
fprintf(stderr, "Ignoring unimplemented caps_info field: %s", line);
continue;
}
if (sscanf(line, "pp_data->FirstByteOfLinkCollectionArray = 0x%04hX\n", &FirstByteOfLinkCollectionArray)) {
continue;
}
if (sscanf(line, "pp_data->NumberLinkCollectionNodes = %hu\n", &NumberLinkCollectionNodes)) {
continue;
}
if (sscanf(line, "pp_data->cap[%d]", &caps_idx) == 1) {
if (pp_data->FirstByteOfLinkCollectionArray == 0) {
fprintf(stderr, "Error reading pp_data file (%s): FirstByteOfLinkCollectionArray is 0 or not reported yet\n", line);
continue;
}
if ((caps_idx + 1) * sizeof(hid_pp_cap) > pp_data->FirstByteOfLinkCollectionArray) {
fprintf(stderr, "Error reading pp_data file (%s): the caps index (%u) is out of pp_data bytes boundary (%hu vs %hu)\n", line, caps_idx, (unsigned short) ((caps_idx + 1) * sizeof(hid_pp_cap)), pp_data->FirstByteOfLinkCollectionArray);
continue;
}
if (sscanf(line, "pp_data->cap[%d]->UsagePage = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
pp_data->caps[caps_idx].UsagePage = temp_usage;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->ReportID = 0x%02hhX\n", &caps_idx, &temp_uchar[0]) == 2) {
pp_data->caps[caps_idx].ReportID = temp_uchar[0];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->BitPosition = %hhu\n", &caps_idx, &temp_uchar[0]) == 2) {
pp_data->caps[caps_idx].BitPosition = temp_uchar[0];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->BitSize = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].ReportSize = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->ReportCount = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].ReportCount = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->BytePosition = 0x%04hX\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].BytePosition = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->BitCount = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].BitCount = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->BitField = 0x%02lX\n", &caps_idx, &temp_ulong) == 2) {
pp_data->caps[caps_idx].BitField = temp_ulong;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->NextBytePosition = 0x%04hX\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].NextBytePosition = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->LinkCollection = 0x%04hX\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].LinkCollection = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->LinkUsagePage = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
pp_data->caps[caps_idx].LinkUsagePage = temp_usage;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->LinkUsage = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
pp_data->caps[caps_idx].LinkUsage = temp_usage;
continue;
}
// 8 Flags in one byte
if (sscanf(line, "pp_data->cap[%d]->IsMultipleItemsForArray = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
pp_data->caps[caps_idx].IsMultipleItemsForArray = temp_boolean[0];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->IsButtonCap = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
pp_data->caps[caps_idx].IsButtonCap = temp_boolean[0];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->IsPadding = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
pp_data->caps[caps_idx].IsPadding = temp_boolean[0];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->IsAbsolute = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
pp_data->caps[caps_idx].IsAbsolute = temp_boolean[0];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->IsRange = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
pp_data->caps[caps_idx].IsRange = temp_boolean[0];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->IsAlias = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
pp_data->caps[caps_idx].IsAlias = temp_boolean[0];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->IsStringRange = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
pp_data->caps[caps_idx].IsStringRange = temp_boolean[0];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->IsDesignatorRange = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
pp_data->caps[caps_idx].IsDesignatorRange = temp_boolean[0];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->Reserved1 = 0x%hhu%hhu%hhu\n", &caps_idx, &temp_uchar[0], &temp_uchar[1], &temp_uchar[2]) == 4) {
pp_data->caps[caps_idx].Reserved1[0] = temp_uchar[0];
pp_data->caps[caps_idx].Reserved1[1] = temp_uchar[1];
pp_data->caps[caps_idx].Reserved1[2] = temp_uchar[2];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->pp_cap->UnknownTokens[%d]", &caps_idx, &token_idx) == 2) {
const size_t unknown_tokens_count = sizeof(pp_data->caps[0].UnknownTokens) / sizeof(pp_data->caps[0].UnknownTokens[0]);
if (token_idx >= unknown_tokens_count) {
fprintf(stderr, "Broken pp_data file, pp_data->caps[<idx>].UnknownTokens[<idx>] can have at most %zu elements, accessing %ud, (%s)", unknown_tokens_count, token_idx, line);
continue;
}
if (sscanf(line, "pp_data->cap[%d]->pp_cap->UnknownTokens[%d].Token = 0x%02hhX\n", &caps_idx, &token_idx, &temp_uchar[0]) == 3) {
pp_data->caps[caps_idx].UnknownTokens[token_idx].Token = temp_uchar[0];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->pp_cap->UnknownTokens[%d].Reserved = 0x%02hhX%02hhX%02hhX\n", &caps_idx, &token_idx, &temp_uchar[0], &temp_uchar[1], &temp_uchar[2]) == 5) {
pp_data->caps[caps_idx].UnknownTokens[token_idx].Reserved[0] = temp_uchar[0];
pp_data->caps[caps_idx].UnknownTokens[token_idx].Reserved[1] = temp_uchar[1];
pp_data->caps[caps_idx].UnknownTokens[token_idx].Reserved[2] = temp_uchar[2];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->pp_cap->UnknownTokens[%d].BitField = 0x%08lX\n", &caps_idx, &token_idx, &temp_ulong) == 3) {
pp_data->caps[caps_idx].UnknownTokens[token_idx].BitField = temp_ulong;
continue;
}
fprintf(stderr, "Ignoring unimplemented pp_data->cap[]->pp_cap->UnknownTokens field: %s", line);
continue;
}
// Range
if (sscanf(line, "pp_data->cap[%d]->Range.UsageMin = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
pp_data->caps[caps_idx].Range.UsageMin = temp_usage;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->Range.UsageMax = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
pp_data->caps[caps_idx].Range.UsageMax = temp_usage;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->Range.StringMin = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].Range.StringMin = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->Range.StringMax = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].Range.StringMax = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->Range.DesignatorMin = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].Range.DesignatorMin = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->Range.DesignatorMax = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].Range.DesignatorMax = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->Range.DataIndexMin = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].Range.DataIndexMin = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->Range.DataIndexMax = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].Range.DataIndexMax = temp_ushort;
continue;
}
// NotRange
if (sscanf(line, "pp_data->cap[%d]->NotRange.Usage = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
pp_data->caps[caps_idx].NotRange.Usage = temp_usage;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->NotRange.Reserved1 = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
pp_data->caps[caps_idx].NotRange.Reserved1 = temp_usage;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->NotRange.StringIndex = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].NotRange.StringIndex = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->NotRange.Reserved2 = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].NotRange.Reserved2 = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->NotRange.DesignatorIndex = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].NotRange.DesignatorIndex = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->NotRange.Reserved3 = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].NotRange.Reserved3 = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->NotRange.DataIndex = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].NotRange.DataIndex = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->NotRange.Reserved4 = %hu\n", &caps_idx, &temp_ushort) == 2) {
pp_data->caps[caps_idx].NotRange.Reserved4 = temp_ushort;
continue;
}
// Button
if (sscanf(line, "pp_data->cap[%d]->Button.LogicalMin = %ld\n", &caps_idx, &temp_long) == 2) {
pp_data->caps[caps_idx].Button.LogicalMin = temp_long;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->Button.LogicalMax = %ld\n", &caps_idx, &temp_long) == 2) {
pp_data->caps[caps_idx].Button.LogicalMax = temp_long;
continue;
}
// NotButton
if (sscanf(line, "pp_data->cap[%d]->NotButton.HasNull = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
pp_data->caps[caps_idx].NotButton.HasNull = temp_boolean[0];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->NotButton.Reserved4 = 0x%02hhX%02hhX%02hhX\n", &caps_idx, &temp_uchar[0], &temp_uchar[1], &temp_uchar[2]) == 4) {
pp_data->caps[caps_idx].NotButton.Reserved4[0] = temp_uchar[0];
pp_data->caps[caps_idx].NotButton.Reserved4[1] = temp_uchar[1];
pp_data->caps[caps_idx].NotButton.Reserved4[2] = temp_uchar[2];
continue;
}
if (sscanf(line, "pp_data->cap[%d]->NotButton.LogicalMin = %ld\n", &caps_idx, &temp_long) == 2) {
pp_data->caps[caps_idx].NotButton.LogicalMin = temp_long;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->NotButton.LogicalMax = %ld\n", &caps_idx, &temp_long) == 2) {
pp_data->caps[caps_idx].NotButton.LogicalMax = temp_long;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->NotButton.PhysicalMin = %ld\n", &caps_idx, &temp_long) == 2) {
pp_data->caps[caps_idx].NotButton.PhysicalMin = temp_long;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->NotButton.PhysicalMax = %ld\n", &caps_idx, &temp_long) == 2) {
pp_data->caps[caps_idx].NotButton.PhysicalMax = temp_long;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->Units = %lu\n", &caps_idx, &temp_ulong) == 2) {
pp_data->caps[caps_idx].Units = temp_ulong;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->UnitsExp = %lu\n", &caps_idx, &temp_ulong) == 2) {
pp_data->caps[caps_idx].UnitsExp = temp_ulong;
continue;
}
if (sscanf(line, "pp_data->cap[%d]->Reserved1 = 0x%02hhu%02hhu%02hhu\n", &coll_idx, &temp_uchar[0], &temp_uchar[1], &temp_uchar[2]) == 4) {
pp_data->caps[caps_idx].Reserved1[0] = temp_uchar[0];
pp_data->caps[caps_idx].Reserved1[1] = temp_uchar[1];
pp_data->caps[caps_idx].Reserved1[2] = temp_uchar[2];
continue;
}
fprintf(stderr, "Ignoring unimplemented cap field: %s", line);
continue;
}
if (sscanf(line, "pp_data->LinkCollectionArray[%d]", &coll_idx) == 1) {
if (pp_data->FirstByteOfLinkCollectionArray == 0 || pp_data->NumberLinkCollectionNodes == 0) {
fprintf(stderr, "Error reading pp_data file (%s): FirstByteOfLinkCollectionArray or NumberLinkCollectionNodes is 0 or not reported yet\n", line);
continue;
}
if (coll_idx >= pp_data->NumberLinkCollectionNodes) {
fprintf(stderr, "Error reading pp_data file (%s): the LinkCollection index (%u) is out of boundary (%hu)\n", line, coll_idx, pp_data->NumberLinkCollectionNodes);
continue;
}
phid_pp_link_collection_node pcoll = (phid_pp_link_collection_node)(((unsigned char*)&pp_data->caps[0]) + pp_data->FirstByteOfLinkCollectionArray);
if (sscanf(line, "pp_data->LinkCollectionArray[%d]->LinkUsage = 0x%04hX\n", &coll_idx, &temp_usage) == 2) {
pcoll[coll_idx].LinkUsage = temp_usage;
continue;
}
if (sscanf(line, "pp_data->LinkCollectionArray[%d]->LinkUsagePage = 0x%04hX\n", &coll_idx, &temp_usage) == 2) {
pcoll[coll_idx].LinkUsagePage = temp_usage;
continue;
}
if (sscanf(line, "pp_data->LinkCollectionArray[%d]->Parent = %hu\n", &coll_idx, &temp_ushort) == 2) {
pcoll[coll_idx].Parent = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->LinkCollectionArray[%d]->NumberOfChildren = %hu\n", &coll_idx, &temp_ushort) == 2) {
pcoll[coll_idx].NumberOfChildren = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->LinkCollectionArray[%d]->NextSibling = %hu\n", &coll_idx, &temp_ushort) == 2) {
pcoll[coll_idx].NextSibling = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->LinkCollectionArray[%d]->FirstChild = %hu\n", &coll_idx, &temp_ushort) == 2) {
pcoll[coll_idx].FirstChild = temp_ushort;
continue;
}
if (sscanf(line, "pp_data->LinkCollectionArray[%d]->CollectionType = %ld\n", &coll_idx, &temp_ulong) == 2) {
pcoll[coll_idx].CollectionType = temp_ulong;
continue;
}
if (sscanf(line, "pp_data->LinkCollectionArray[%d]->IsAlias = %ld\n", &coll_idx, &temp_ulong) == 2) {
pcoll[coll_idx].IsAlias = temp_ulong;
continue;
}
if (sscanf(line, "pp_data->LinkCollectionArray[%d]->Reserved = %ld\n", &coll_idx, &temp_ulong) == 2) {
pcoll[coll_idx].Reserved = temp_ulong;
continue;
}
fprintf(stderr, "Ignoring unimplemented LinkCollectionArray field: %s", line);
continue;
}
}
//end:
fclose(file);
if (pp_data == &static_pp_data) {
return NULL;
}
return pp_data;
}
static BOOLEAN read_hex_data_from_text_file(const char *filename, unsigned char *data_out, size_t data_size, size_t *actual_read)
{
size_t read_index = 0;
FILE* file = NULL;
errno_t err = fopen_s(&file, filename, "r");
if (err != 0) {
fprintf(stderr, "ERROR: Couldn't open file '%s' for reading: %s\n", filename, strerror(err));
return FALSE;
}
BOOLEAN result = TRUE;
unsigned int val;
char buf[16];
while (fscanf(file, "%15s", buf) == 1) {
if (sscanf(buf, "0x%X", &val) != 1) {
fprintf(stderr, "Invalid HEX text ('%s') file, got %s\n", filename, buf);
result = FALSE;
goto end;
}
if (read_index >= data_size) {
fprintf(stderr, "Buffer for file read is too small. Got only %zu bytes to read '%s'\n", data_size, filename);
result = FALSE;
goto end;
}
if (val > (unsigned char)-1) {
fprintf(stderr, "Invalid HEX text ('%s') file, got a value of: %u\n", filename, val);
result = FALSE;
goto end;
}
data_out[read_index] = (unsigned char) val;
read_index++;
}
if (!feof(file)) {
fprintf(stderr, "Invalid HEX text ('%s') file - failed to read all values\n", filename);
result = FALSE;
goto end;
}
*actual_read = read_index;
end:
fclose(file);
return result;
}
int main(int argc, char* argv[])
{
if (argc != 3) {
fprintf(stderr, "Expected 2 arguments for the test ('<>.pp_data' and '<>_expected.rpt_desc'), got: %d\n", argc - 1);
return EXIT_FAILURE;
}
printf("Checking: '%s' / '%s'\n", argv[1], argv[2]);
hidp_preparsed_data *pp_data = alloc_preparsed_data_from_file(argv[1]);
if (pp_data == NULL) {
return EXIT_FAILURE;
}
int result = EXIT_SUCCESS;
unsigned char report_descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE];
int res = hid_winapi_descriptor_reconstruct_pp_data(pp_data, report_descriptor, sizeof(report_descriptor));
if (res < 0) {
result = EXIT_FAILURE;
fprintf(stderr, "Failed to reconstruct descriptor");
goto end;
}
size_t report_descriptor_size = (size_t) res;
unsigned char expected_report_descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE];
size_t expected_report_descriptor_size = 0;
if (!read_hex_data_from_text_file(argv[2], expected_report_descriptor, sizeof(expected_report_descriptor), &expected_report_descriptor_size)) {
result = EXIT_FAILURE;
goto end;
}
if (report_descriptor_size == expected_report_descriptor_size) {
if (memcmp(report_descriptor, expected_report_descriptor, report_descriptor_size) == 0) {
printf("Reconstructed Report Descriptor matches the expected descriptor\n");
goto end;
}
else {
result = EXIT_FAILURE;
fprintf(stderr, "Reconstructed Report Descriptor has different content than expected\n");
}
}
else {
result = EXIT_FAILURE;
fprintf(stderr, "Reconstructed Report Descriptor has different size: %zu when expected %zu\n", report_descriptor_size, expected_report_descriptor_size);
}
printf(" Reconstructed Report Descriptor:\n");
for (int i = 0; i < res; i++) {
printf("0x%02X, ", report_descriptor[i]);
}
printf("\n");
fflush(stdout);
end:
free(pp_data);
return result;
}
/****************************************************************************
Copyright (c) 2015 Artyom Pavlov All Rights Reserved.
This file is part of hidapi-rs, based on hidapi_rust by Roland Ruckerbauer.
It's also based on the Oleg Bulatov's work (https://github.com/dmage/co2mon)
****************************************************************************/
//! Opens a KIT MT 8057 CO2 detector and reads data from it. This
//! example will not work unless such device is plugged into your system.
use hidapi::{HidApi, HidError};
use std::io;
const CODE_TEMPERATURE: u8 = 0x42;
const CODE_CONCENTRATION: u8 = 0x50;
const HID_TIMEOUT: i32 = 5000;
const DEV_VID: u16 = 0x04d9;
const DEV_PID: u16 = 0xa052;
const PACKET_SIZE: usize = 8;
type Packet = [u8; PACKET_SIZE];
enum CO2Result {
Temperature(f32),
Concentration(u16),
Unknown(u8, u16),
Error(&'static str),
}
fn decode_temperature(value: u16) -> f32 {
(value as f32) * 0.0625 - 273.15
}
fn decrypt(buf: Packet) -> Packet {
let mut res: [u8; PACKET_SIZE] = [
(buf[3] << 5) | (buf[2] >> 3),
(buf[2] << 5) | (buf[4] >> 3),
(buf[4] << 5) | (buf[0] >> 3),
(buf[0] << 5) | (buf[7] >> 3),
(buf[7] << 5) | (buf[1] >> 3),
(buf[1] << 5) | (buf[6] >> 3),
(buf[6] << 5) | (buf[5] >> 3),
(buf[5] << 5) | (buf[3] >> 3),
];
let magic_word = b"Htemp99e";
for i in 0..PACKET_SIZE {
let sub_val: u8 = (magic_word[i] << 4) | (magic_word[i] >> 4);
res[i] = u8::wrapping_sub(res[i], sub_val);
}
res
}
fn decode_buf(buf: Packet) -> CO2Result {
// Do we need to decrypt the data?
let res = if buf[4] == 0x0d { buf } else { decrypt(buf) };
let kind = res[0];
let val = u16::from_be_bytes(res[1..3].try_into().unwrap());
let checksum = res[3];
let tail = res[4];
if tail != 0x0d {
return CO2Result::Error("Unexpected data (data[4] != 0x0d)");
}
let checksum_calc = res[0].wrapping_add(res[1]).wrapping_add(res[2]);
if checksum != checksum_calc {
return CO2Result::Error("Checksum error");
}
match kind {
CODE_TEMPERATURE => CO2Result::Temperature(decode_temperature(val)),
CODE_CONCENTRATION => {
if val > 3000 {
CO2Result::Error("Concentration bigger than 3000 (uninitialized device?)")
} else {
CO2Result::Concentration(val)
}
}
_ => CO2Result::Unknown(res[0], val),
}
}
fn invalid_data_err(msg: impl Into<String>) -> HidError {
HidError::IoError {
error: io::Error::new(io::ErrorKind::InvalidData, msg.into()),
}
}
fn main() -> Result<(), HidError> {
let api = HidApi::new()?;
let dev = api.open(DEV_VID, DEV_PID)?;
dev.send_feature_report(&[0; PACKET_SIZE])?;
if let Some(manufacturer) = dev.get_manufacturer_string()? {
println!("Manufacurer:\t{manufacturer}");
}
if let Some(product) = dev.get_product_string()? {
println!("Product:\t{product}");
}
if let Some(serial_number) = dev.get_serial_number_string()? {
println!("Serial number:\t{serial_number}");
}
let mut buf = [0; PACKET_SIZE];
loop {
let n = dev.read_timeout(&mut buf[..], HID_TIMEOUT)?;
if n != PACKET_SIZE {
let msg = format!("unexpected packet length: {n}/{PACKET_SIZE}");
return Err(invalid_data_err(msg));
}
match decode_buf(buf) {
CO2Result::Temperature(val) => println!("Temp:\t{val}"),
CO2Result::Concentration(val) => println!("Conc:\t{val}"),
CO2Result::Unknown(..) => (),
CO2Result::Error(msg) => {
return Err(invalid_data_err(msg));
}
}
}
}
use hidapi::HidApi;
fn main() {
println!("Printing all available hid devices:");
match HidApi::new() {
Ok(api) => {
for device in api.device_list() {
println!(
" {} (Interface {}):",
match device.product_string() {
Some(s) => s,
_ => "<COULD NOT FETCH>",
},
device.interface_number()
);
let mut descriptor = vec![0u8; 2048];
match device
.open_device(&api)
.and_then(|dev| dev.get_report_descriptor(&mut descriptor))
{
Ok(length) => println!(" {:?}", &mut descriptor[..length]),
Err(err) => println!(" Failed to retrieve descriptor ({:?})", err),
}
}
}
Err(e) => {
eprintln!("Error: {}", e);
}
}
}
/****************************************************************************
Copyright (c) 2022 ruabmbua All Rights Reserved.
****************************************************************************/
//! Sets the sidechannel volume of the logitech gpro x headset
extern crate hidapi;
use hidapi::HidApi;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let vol = std::env::args()
.nth(1)
.map(|arg| arg.parse::<u8>())
.ok_or("missing sidechannel volume arg")??
.min(100);
let api = HidApi::new()?;
let dev = api.open(0x046d, 0x0aaa)?;
println!("Setting sidechannel volume to {}", vol);
dev.write(&[0x11, 0xff, 0x05, 0x1c, vol])?;
Ok(())
}
/****************************************************************************
Copyright (c) 2015 Osspial All Rights Reserved.
This file is part of hidapi-rs, based on hidapi_rust by Roland Ruckerbauer.
****************************************************************************/
//! Prints out a list of HID devices
extern crate hidapi;
use hidapi::HidApi;
fn main() {
println!("Printing all available hid devices:");
match HidApi::new() {
Ok(api) => {
for device in api.device_list() {
println!(
"VID: {:04x}, PID: {:04x}, Serial: {}, Product name: {}, Interface: {}",
device.vendor_id(),
device.product_id(),
match device.serial_number() {
Some(s) => s,
_ => "<COULD NOT FETCH>",
},
match device.product_string() {
Some(s) => s,
_ => "<COULD NOT FETCH>",
},
device.interface_number()
);
}
}
Err(e) => {
eprintln!("Error: {}", e);
}
}
}
/****************************************************************************
Copyright (c) 2018 Roland Ruckerbauer All Rights Reserved.
This file is part of hidapi-rs, based on hidapi-rs by Osspial
****************************************************************************/
//! Opens the first hid device it can find, and reads data in a blocking fashion
//! from it in an endless loop.
extern crate hidapi;
use hidapi::{HidApi, HidError};
fn main() {
fn run() -> Result<(), HidError> {
let hidapi = HidApi::new()?;
let device_info = hidapi
.device_list()
.next()
.expect("No devices are available!")
.clone();
println!(
"Opening device:\n VID: {:04x}, PID: {:04x}\n",
device_info.vendor_id(),
device_info.product_id()
);
let device = device_info.open_device(&hidapi)?;
let mut buf = vec![0; 64];
println!("Reading data from device ...\n");
loop {
let len = device.read(&mut buf)?;
println!("{:?}", &buf[..len]);
}
}
if let Err(e) = run() {
eprintln!("Error: {}", e);
}
}
/****************************************************************************
Copyright (c) 2015 Osspial All Rights Reserved.
This file is part of hidapi-rs, based on hidapi_rust by Roland Ruckerbauer.
****************************************************************************/
//! Opens a Thrustmaster T-Flight HOTAS X HID and reads data from it. This
//! example will not work unless such an HID is plugged in to your system.
//! Will update in the future to support all HIDs.
extern crate hidapi;
use hidapi::HidApi;
fn main() {
let api = HidApi::new().expect("Failed to create API instance");
let joystick = api.open(1103, 45320).expect("Failed to open device");
loop {
let mut buf = [0u8; 256];
let res = joystick.read(&mut buf[..]).unwrap();
let mut data_string = String::new();
for u in &buf[..res] {
data_string.push_str(&(u.to_string() + "\t"));
}
println!("{}", data_string);
}
}
/****************************************************************************
Copyright (c) 2015 Osspial All Rights Reserved.
This file is part of hidapi-rs, based on hidapi_rust by Roland Ruckerbauer.
****************************************************************************/
//! This example shows the added possibility (after version 0.4.1),
//! to move devices into a function / or closure with static lifetime bounds.
extern crate hidapi;
use hidapi::{HidApi, HidDevice};
use std::rc::Rc;
fn main() {
let _dev = test_lt();
}
fn requires_static_lt_bound<F: Fn() + 'static>(f: F) {
f();
}
fn test_lt() -> Rc<HidDevice> {
let api = HidApi::new().expect("Hidapi init failed");
let mut devices = api.device_list();
let dev_info = devices
.next()
.expect("There is not a single hid device available");
let dev = Rc::new(
api.open(dev_info.vendor_id(), dev_info.product_id())
.expect("Can not open device"),
);
let dev_1 = dev.clone();
requires_static_lt_bound(move || {
println!("{:?}", dev_1.get_device_info().unwrap()); //<! Can be captured by closure with static lt
});
dev //<! Can be returned from a function, which exceeds the lifetime of the API context
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet